如何高效生成趋势有序的全局唯一ID
所有的业务系统,都有生成ID的需求,如订单id,商品id等
这个ID会是数据库中的唯一主键,在它上面会建立聚集索引
ID生成的核心需求:
(1)全局唯一
(2)趋势有序
1.使用数据库的 auto_increment 来生成全局唯一递增ID
优点:
(1)简单
(2)能够保证唯一性
(3)能够保证递增性
(4)步长固定
缺点:
(1)可用性难以保证:数据库架构是一主多从+读写分离,生成自增ID是写请求,主库挂了就玩不转了
(2)扩展性差,性能有上限:因为写入是单点,数据库主库的写性能决定ID的生成性能上限,并且难以扩展
改进方法:
(1)增加主库,避免写入单点
(2)数据水平切分,保证各主库生成的ID不重复
改进后保证了可用性,但缺点是:
(1)丧失了ID生成的“绝对递增性”
(2)数据库的写压力依然很大,每次生成ID都要访问数据库
2.单点批量ID生成服务
每次生成ID都访问了数据库,使用批量的方式降低数据库写压力
数据库中只存储当前ID的最大值,
如果当前为0,
ID生成服务每次批量拉取6个ID,服务访问数据库,将当前ID的最大值修改为5,应用访问ID生成服务索要ID,ID生成服务不需要每次访问数据库,就能依次派发0,1,2,3,4,5
当ID发完后,再将ID的最大值修改为11,就能再次派发6,7,8,9,10,11
优点:
(1)保证了ID生成的绝对递增有序
(2)大大的降低了数据库的压力
缺点:
(1)服务仍然是单点
(2)如果服务挂了,服务重启起来之后,继续生成ID可能会不连续,中间出现空洞
(3)虽然每秒可以生成几万几十万个ID,但还是有性能上限,无法进行水平扩展
改进方法:
单点服务高可用优化方案是“备用服务”
对外提供的服务是主服务,备用服务时刻处于备用状态,当主服务挂了的时候备用服务顶上。
这个切换的过程对调用方是透明的,可以自动完成,常用的技术是vip+keepalived
3.uuid
string ID =GenUUID();
优点:
(1)本地生成ID,不需要进行远程调用,时延低
(2)扩展性好,基本可以认为没有性能上限
缺点:
(1)无法保证趋势递增
(2)uuid过长,往往用字符串表示,作为主键建立索引查询效率低
优化方案为“转化为两个uint64整数存储”或者“折半存储”(折半后不能保证唯一性)
4.取当前毫秒数
uint64 ID = GenTimeMS();
优点:
(1)本地生成ID,不需要进行远程调用,时延低
(2)生成的ID趋势递增
(3)生成的ID是整数,建立索引后查询效率高
缺点:
(1)如果并发量超过1000,会生成重复的ID
5.类snowflake算法
snowflake是twitter开源的分布式ID生成算法
核心思想是:一个long型的ID,使用其中41bit作为毫秒数,10bit作为机器编号,12bit作为毫秒内序列号