Skip to content

Explain

songang edited this page May 13, 2021 · 5 revisions

项目详细解释

背景

发现在github中已有的短链服务中,非分布式服务做到快速扩容,并且有些项目是用的redis作为数据缓存,性能上不够优秀.

短链服务介绍

短链接,通俗来说,就是将长的URL网址,通过程序计算等方式,转换为简短的网址字符串。

使用场景

微博和Twitter都有140字数的限制,如果分享一个长网址,很容易就超出限制。

营销短信,字数的限制,当字数过长: 1.不美观 2.超出字符额外收费。

生成二维码的原始链接,当原始链接过长时,生成的二维码过于复杂,导致一些像素较低的手机无法扫描.

一个短链系统,我们应该做什么呢?

  1. 将长链接变为短链;

  2. 用户访问短链接,会跳转到正确的长链接上去。

短链系统有哪些需要注意的地方

  1. 短链key的生成逻辑
  2. 如何提高短链key生成效率

如何生成短链key

生成短链方法有很多,如: md5长链、 自增序列算法、 摘要算法、哈希法、 普通随机数。

最终本项目借鉴了 美团leaf分布式ID生成系统 整理出来了适合本项目的生成短链key逻辑 <号码段模式>

在针对生成短链key生成效率优化: 使用简化版的 Leaf-segment 数据库方案 及 双buffer优化

数据库方案

首先先看下 短链key生成表结构

CREATE TABLE `durl_short_num` (
`id` tinyint(11) unsigned NOT NULL AUTO_INCREMENT,
`max_num` int(11) NOT NULL DEFAULT '1' COMMENT '号码段开始值',
`step` int(11) NOT NULL DEFAULT '1' COMMENT '步长',
`version` int(11) NOT NULL DEFAULT '1' COMMENT '版本号',
`update_time` int(11) NOT NULL DEFAULT '0' COMMENT '数据修改时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='短链号码段';

短链key为号码段short_num进行62进制转换后的值.

项目初始化及使用期间,每次获取一个step号段。如:200-300, 用完之后再去数据库获取新的号段,可以大大的减轻数据库的压力。

重要字段说明: max_num表示目前所被分配的短链key的最大值。 step表示每次分配的号段长度。version是一个乐观锁,每次都更新version,保证并发时数据的正确性

在多台机器,考虑获取号码段重复获取数据时使用乐观锁查询方式.

在实际线上环境,只需要把step设置得足够大,比如1000。 那么只有当1000个号被消耗完了之后才会去重新读写一次数据库。 读写数据库的频率从1减小到了1/step,大致架构如下图所示:

双buffer

如果取号段的时机是在号段消耗完的时候进行的,也就意味着号段临界点的ID下发时间取决于下一次从DB取回号段的时间, 并且在这期间进来的请求也会因为DB号段没有取回来,导致线程阻塞。 如果请求DB的网络和DB的性能稳定,这种情况对系统的影响是不大的,但是假如取DB的时候网络发生抖动,或者DB发生慢查询就会导致整个系统的响应时间变慢。

为此,我们希望DB取号段的过程能够做到无阻塞,不需要在DB取号段的时候阻塞请求线程, 即当号段消费到某个点时就异步的把下一个号段加载到内存中。 而不需要等到号段用尽的时候才去更新号段。

采用双buffer的方式,服务内部有两个号段缓存区segment。 当前号段已下发10%时,如果下一个号段未更新,则另启一个更新线程去更新下一个号段。 当前号段全部下发完后,如果下个号段准备好了则切换到下个号段为当前segment接着下发,循环往复。

Clone this wiki locally