相信看了这个标题的同学,对这个问题以已经非常不陌生了,信手拈来,什么雪花,美团Leaf,百度Uidgenerator,滴滴Tinyid,uuid,号段,自增等。

对于我而言,基本上是三个派系,自增、雪花(百度/leaf)、号段(leaf/tinyid)

大多数场景

我身边朋友包括一些大厂的,一些核心业务或边缘业务,用的比较多的还是自增。

具体怎么说呢?

大部分的业务不会有太高的并发,大量写并发,几十个实例都去获取主键最大值,极大可能造成间隙锁竞争。当然出现这么大的数据量,不得上分布式缓存呀,数据库我们就可以用雪花或者号段来 + 分库分表,在大点按天分表??这数据量,不得按小时做冷热备份呀,冷的写入hbase就可以。

再说一说数据补偿

自增情况下的补偿:

通常情况下我们对接第三方渠道,我们补偿数据可能会去分页扫描订单的状态,我们需要加一个order by id asc就可以走index级别索引,index级别基本上是扫描全表了,只不过是扫描的索引。在数据量百万内基本上没啥问题,超过的话建议走联合索引。举个例子,订单的某个大户,可能有个几十w数据,订单分页比较小时【例如20】,mysql默认会先走order by id的主键索引,并且你的条件也比较多,就会扫很多数据,还不如走联合索引快呢。

当然数据量更大的话我们kafka推送单独创建一个表用来记录失败的做补偿就行啦。

大家如果想看看--

微信序列号生成方案

微信序列号跟用户 uin 绑定,具有以下性质:递增的 64 位整形;使用每个用户独立的 64 位 sequence 的体系,而不是用一个全局的 64 位(或更高位) sequence ,很大原因是全局唯一的 sequence 会有非常严重的申请互斥问题,不容易去实现一个高性能高可靠的架构。其实现方式包含如下两个关键点:

1)步进式持久化:增加一个缓存中间层,内存中缓存最近一个分配出现的 sequence:cur_seq,以及分配上限:max_seq;分配 sequence 时,将 cur_seq++,与分配上限 max_seq 比较,如果 cur_seq > max_seq,将分配上限提升一个步长 max_seq += step,并持久化 max_seq;重启时,读出持久化的 max_seq,赋值给 cur_seq。此种处理方式可以降低持久化的硬盘 IO 次数,可以系统的整体吞吐量。

2)分号段共享存储:引入号段 section 的概念,uin 相邻的一段用户属于一个号段,共享一个 max_seq。该处理方式可以大幅减少 max_seq 数据的大小,同时可以进一步地降低 IO 次数。

**说白了也是号段模式,内存加锁分号段,重启是不是会丢一部分号段,那就不要了呗,直接获取max_seq赋值给 cur_seq **