1。为什么我们很多地方都需要一个全球唯一的编号,就是uuid。举一个常见的场景,电商系统在生成订单的时候,需要有一个对应的订单号。在composer上我们也可以看到有很多优秀的组件可以生成uuid。那么,为什么我们要自己实现信号发生器来生成uuid呢?想了想,主要有两个原因:1、希望uuid可以逆向,通过uuid逆向就可以得到我业务相关的数据。但是我看到的uuid相关的composer组件会生成一串指定格式的字符串,我很难将其与具体的业务联系起来。2、希望uuid可以根据音量来调整。比如原来支持1秒可以生成1000个uuid,但是随着业务规模的增长,希望可以支持1秒10000个uuid。而且,最好更改配置。基于以上两个原因,我们需要自己的generator来生成uuid。那么,接下来的问题就是,我们应该如何实现信号发生器,信号发生器的实现原理是什么?2.雪花算法关于数生成器的实现原理,大家可能听说过大名鼎鼎的雪花算法——Snowflake算法,Twitter的分布式自增Id算法。中国的新浪微博也有自己的信号发生器算法实现。虽然具体的实现细节不同,但是原理是一样的,你只需要了解其中的一个就可以了。这里主要介绍snowflake。关于snowflaw的介绍,已经有很多文章介绍过了,写的也很好。不用我重新写一遍,直接使用,粘贴即可。出于对作者的尊重,我会在参考链接中加上原文链接。Twitter的分布式自增ID算法使用long(8×8=64字节)来保存uuid。其中,固定符号位0预留1位,毫秒时间戳预留41位,MachineID预留10位,即机器必须预配置,其余12位预留给Sequence(1毫秒内可支持4096次请求)。可能有人会问4096请求超过1毫秒怎么办?一般的做法是让它等待1毫秒,让41bit的时间戳发生变化。这里我们拆分了MachineId,5byte留给机器(最多支持32台机器),5byte留给业务号(最多支持32种业务)。这里的时间戳保存了当前时间和固定的过去时间之一。差异,而不是当前时间。这样做的好处是可以使用更长时间,而且不受年份限制,只看什么时候用过,2^41/1000360024*365=69年。如果保存当前时间戳,最多只能用到2039。2^41=2199023255552=2039/9/723:47:35理论单机速度:2^12*1000=4096000/s3,如何保证单位时间内的持续增长通过对snowflake的初步了解,我们发现,其实数字生成器也是基于时间戳的,因为时间是唯一的自然元素。但是,如何保证Sequence在单位时间内,比如一秒或者一毫秒内持续递增,是信号发生器实现的关键。我们这里实现的方式比较简单,直接使用redis的incr进行计数,对应的key就是毫秒时间戳。出于redis内存回收的考虑,我们需要为每个key设置一个过期时间。如果key是秒级时间戳,则过期时间为1秒+网络延迟;如果key是毫秒级别的时间戳,则过期时间为1毫秒+网络延迟。同时,为了保证incr、expire(pexpire)的执行是原子的,我们使用lua来实现。嗯,实现思路大致相同。由于能力和水平有限,难免有错误之处,望及时指出。4.参考文章分布式ID生成器PHP+Swoole实现(上)-实现原理
