分布式ID的一些要求
(这段摘自美团Leaf开源项目)
全局唯一性:不能出现重复的ID号,既然是唯一标识,这是最基本的要求。
趋势递增:在MySQL InnoDB引擎中使用的是聚集索引,由于多数RDBMS使用B-tree的数据结构来存储索引数据,在主键的选择上面我们应该尽量使用有序的主键保证写入性能。
单调递增:保证下一个ID一定大于上一个ID,例如事务版本号、IM增量消息、排序等特殊需求。
信息安全:如果ID是连续的,恶意用户的扒取工作就非常容易做了,直接按照顺序下载指定URL即可;如果是订单号就更危险了,竞对可以直接知道我们一天的单量。所以在一些应用场景下,会需要ID无规则、不规则。
方案一:UUID
格式:32位定长随机字符
优点是简单,高效,缺点是,不包含业务属性,时间戳,排序属性等,且UUID中可能包含MAC地址,不安全
缺点
- UUID太长,占用空间多(32个16进制数,128字节)
- 信息不安全,可能包含MAC地址
- ID作为数据库主键时不适合,因为ID太长,需要更多空间,并且对索引算法非常不利(无序导致索引频繁重建)
方案二:系统时间戳
ID内容:用业务属性+定长随机数+系统时间戳(毫秒)
优点是简单,有业务属性,有时间戳,缺点是不能保证有序性
方案三:数据库自增ID,单点批量
缺点:存在单点瓶颈,重启数据库可能造成ID丢失或者不连续
方案四:中间件生成
Redis有incr命令,且本身是单线程,因此可生成唯一ID
zooker的znode节点,mongodb的objectid(类似snowflake分段法)等也可生成唯一ID
缺点:主要还是性能指标跟不上,以下摘自博客 https://blog.csdn.net/x5fnncxzq4/article/details/79549514
“E也考虑过采用ZooKeeper所提供的 Unique Naming Seuence Nodes 所提供的 Unique Naming 特性,但是性能不能满足。(Sequence Nodes的设计目标是解决分布式锁的问题,但不解决性能要求极高的ID生成问题,直接应用是一种Hack行为)”
方案五:twitter的snowflake算法
格式:41bit时间+10bit机器标志符+12bit序列号
优点:
毫秒数在高位,自增序列在低位,整个ID都是趋势递增的。
不依赖数据库等第三方系统,以服务的方式部署,稳定性更高,生成ID的性能也是非常高的。
可以根据自身业务特性分配bit位,非常灵活。
缺点:
- 强依赖机器时钟,如果机器上时钟回拨,会导致发号重复或者服务会处于不可用状态。
- 分布式环境下可能不是全局绝对递增,因为节点时钟可能不完全同步
方案六:UidGenerator
百度开源项目,基于snowflake
方案七:Leaf
美团开源项目
https://tech.meituan.com/MT_Leaf.html
方案八:类Paxos算法