常见分布式应用系统设计图解(十三):短网址系统

短网址系统可能是最常见的分布式系统设计问题之一了,本身从业务需求上说,读远多过写,而且数据结构确定且简单,数据量小,还易于使用缓存,因此本身难度在分布式系统的问题里面算是比较低的。另外,这个系统本身 “分布式” 的特性也比较弱,而且从组件图的角度来说,没有多少是 “可画的” ,因此之前也就没有介绍它。不过后来我改变想法了,我觉得还是可以总结总结,特别是可以把一些相关的特殊需求考虑进去。

短网址服务就像是 bit.ly 这样的,给一个长长的 URL,它给你吐出一个较短的 URL,往后访问这个 URL 就可以做到 302 重定向到原来那个长 URL 了。

  • 图中上半部分是写的部分,无论是 API 直接调用还是通过某一个 UI 去调用,Write API 会进行鉴权操作。另外,如果源 URL 已经是经过短网址服务处理过的,就需要返回失败,否则就陷入了一个递归服务的窘境。
  • 其中写部分的 Cache 是用来防止一些过度的访问,比如由于某种原因,短时间内对某一个特定 URL 来生成短网址的请求特别多,那么就可以通过它来发现并阻止。
  • Key Generator 用来生成短网址中变化的部分(key),这里面根据不同的需求有几种方法:
    • 如果允许按序,那么最简单的方法是使用数据库的 sequence,为了高可用,可以配置多个数据库,step 相同,但起点分散开,比如数据库 A 生成 ID 序列为 1、3、5……,数据库 B 则是 2、4、6……
    • 拿到数据库生成的 ID 以后,可以将这个十进制数转成 [a-zA-Z0-9_-] 这样的 64 进制数。
    • 如果要求key无序,那么可以再根据上述结果加一个算法上的小处理,保证ID到最终key的一对一映射即可,最简单的方法是单个数或者字符的映射,比如a->3、b->M(当然,这种方法相对也比较好猜)。
    • 如果需要自定义 ID,那么这个 Key Generator 可以接受一个自定义 key 去数据库里面找,找不到就可以用,否则就意味着冲突出现了。
  • Key 得到以后,生成的相对路径和原 URL 需要写入 URL DB 中。
  • 这里面有一个问题,就是如果两次请求的长 URL 相同,系统应该给出同样的短 URL 还是不同的短 URL?或者说,应该考虑去重吗?一般说来,不应该去重,应为根据短 URL 可以进行许多收费和数据分析,这两个相同的长 URL 来自于不同的用户,如果这里合并去重了就丢失了和用户对应的这部分信息。
  • 短 URL 生成以后,这里我还画了一个 Syncer,用来将生成的新映射同步到其它地区的节点去。因为短网址的读的服务如果在本地,那么显然响应速度是更快的,而且也可以减轻中心节点的负担。
  • 不同地区的用户,在使用读服务的时候,通过带有缓存的 Read API 来进行,但是具体的地址是根据 DNS 来做均衡,优先使用本地的读服务。
  • 关于读服务,还有一个常见问题是,HTTP 状态码应该是 301 还是 302?一般应该使用 302,因为 301 是永久重定向,很明显我们不希望它是永久重定向,而应该是临时重定向,因为永久重定向会丢失很多后续的访问,和前面提到的去重问题,一样不利于收费和数据分析。