前言

某些输入框的限制,导致域名本身不需要那么冗余等,短域名的可观性非常好
在设计这种系统的时候,需要明白输入输出是什么,以及限制条件如何调优等

以下的文章知识点主要来源于:短网址系统设计
记笔记的同时融入了一些自已的见解和拓展

1. 背景

设计方案同时,需要明白整体业务的流程,防止设计完之后不符合

输入?

输入一个冗长的域名以及过期时间(如果没有过期时间则给默认)
或者是一个自定义域名

输出?

自定义的别名域名返回短域名,通过点击短域名会重定向网页

约束?

  • 过期时间到了会失效(类似网盘的分享链接)
  • 域名唯一不重复
  • 自定义的域名需要的长度以及什么字符生成
  • QPS(系统阈值),读写接口的QPS是多少,对应QPS可看我之前的文章:QPS常用的测试以及优化方法
  • 延迟
  • 存储空间的大小(估算域名访问条数)
  • 可靠性
  • 安全性(防止爬虫爬取)

2. 设计

针对以上提出的需求对应解决相关的问题

2.1 过期时间

过期时间的处理策略,学过Redis的应该知道Redis的过期处理策略:

  1. Redis框架从入门到学精(全)
  2. Redis的常见面试题(全)
  3. Python操作Redis从入门到精通附代码(全)

大致Redis的删除策略如下:
(1) 定时删除:在设置键的过期时间的同时,创建一个定时器 timer). 让定时器在键的过期时间来临时,立即执行对键的删除操作。

(2) 惰性删除:放任键过期不管,但是每次从键空间中获取键时,都检查取得的键是否过期,如果过期的话,就删除该键;如果没有过期,就返回该键。

(3) 定期删除:每隔一段时间程序就对数据库进行一次检查,删除里面的过期键。至于要删除多少过期键,以及要检查多少个数据库,则由算法决定。

可以借鉴该过期策略

策略逻辑优缺点
延迟删除用户读取判断当前时间,如果大于过期时间,则将其删除存储空间利用率低
定时删除定时调用删除函数空间利用率高,但是回调触发占用CPU,导致性能差
轮询删除周期扫描全表空间与性能的折中

如果延迟时间比较高能接受,可以采用延迟删除

2.2 域名唯一

读写接口大致逻辑如下:

写接口:输入长域名,如果存储过则不需要进一步存储,没存储过则生成短域名,并将其两者映射存储在DB中
读接口:获取短域名判断是否有效,没有存储或者无效直接返回,如果有效,通过映射关系查询长域名,并且对其重定向

  • 读时消重:返回数据的时候判断重复(feed流,count一次,不用count第二次)
  • 写时消重:写数据的时候判断(推荐)

对应的ID唯一不重复,可参考这篇文章:分布式ID生成方法的超详细分析(全)

参考分布式ID的生成方法:数据库自增、时间戳、Redis的incr命令自增、雪花算法(融入机器ID以及时间戳)

此处的域名生成:

生成方法大致情况
UUID7位数字,长度要截取,不可保证
哈希长度需要截取,同样也不可保证
数据库自增ID7位62进制(维护一个已被使用,即使过期了也不会被服用)(推荐)

3. 优化

优化可以从吞吐量、延迟、可靠性、迭代的速率、安全性等


吞吐量:
大的QPS通过水平扩展,使用Nginx做负载均衡
通过分片、副本扩容缩容平衡QPS


延迟:
Redis和Mysql交互的时候需要延迟,延迟还得算上跨机房

  • 存储层:
    1.为了降低这种延迟,如果业务比较简单,可以通过rocksDB数据库存储(持久化key 、value),如果业务比较复杂,可以使用关系型数据存储,而不是用mysql。数据的分析需求后期如果还要用上,可以将kafka消息写入到ELK中
    2.构建索引也不可使用mysql数据库,不好维护,本身长域名与短域名要相互映射,此处可使用倒排索引(类似elasticsearch):Elasticsearch从入门到精通超详细版本(全)
    3.写时分片(类似mycat框架):Mycat的常见面试题(全)。主要通过一致性哈希(一致性哈希算法的原理与应用剖析),写入分片位置,读数据的时候也用相同的哈希。

  • 缓存层:
    可通过本地、Redis等缓存(延迟比较苛刻,可使用本地缓存,用本地的LRU进行维护)
    查询长域名是否存储,短域名是否被分配,可使用布隆过滤器(不过有假的,准确率一般):布隆过滤器的原理和实现详细分析(全)

  • 业务层:
    1.基于预处理缓存一部分的数据,只对尾号进行分布式ID生成(只保证唯一性,但可能不保连续单调,但也足够)
    2.分布式ID可采用zookeeper等组件处理数据一致性:Zookeeper从入门到精通(全)
    3.可使用lua脚本降低对Redis的调用次数,也可配置Openresty:Openresty框架入门详解

  • 拓扑层:
    利用地理位置,同一地区的请求路由分发到最近的机房


可靠性:
冗余副本、存储多份可保证可用性

  1. Redis以及mq系列:一方面分组读写、一方面提供备份
  2. 监控阈值,实现系统熔断、限流、扩容缩容

可参考如下框架文章:
kafka框架从入门到精通(全)


迭代效率:

  1. 监控缓存的命中率,是否会让Redis击穿崩盘(增加热点数据等)
  2. 监控qos阈值进行扩容缩容,节省成本

可参考如下文章:
云服务器安装elasticsearch 以及 kibana 附详细图文(全)


安全性:

  1. 自增ID,可能会被他人爬虫
  2. 使用哈希,可能会存在冲突,但解决安全
  3. 防止DOS攻击,可通过IP限流或者黑名单拉黑
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐