UUID
- UUID由本地生成,没有网络消耗,而且代码实现简单,但它存储空间大,而且是无序的,不能保证趋势递增,mysql默认使用的是InnoDB存储引擎,它的主键索引采用的是B+树索引,无序而且过长的UUID不适合作为主键。
数据库自增ID
- 通过MySQL的主键自增,也就是 auto_increment 来实现,以此来生成自增ID,优点是用现有的数据库系统来实现,成本小,实现简单;缺点是业务系统每次需要ID时,都要请求数据库,性能较低,对数据库压力大,高并发抗不住,而且由于强依赖于数据库,如果 mysql 挂了,就没法生成iD了。
- 可以对这种方法进行改进:这种方法主要的问题是每次获取id,都要去数据库请求一次,性能较低,而且对数据库压力较大,可以修改为生成一个区间的id,放进JVM的内存中,这样就不需要每次都去请求数据库了,而是从JVM内存中获取id,比如这个区间先是1到1000,也就是步长是1000,等这个区间的id请求完后,再请求生成id服务,生成1001到2000区间的id,放到JVM内存中。这个改进方案在高并发场景下会存在问题,比如多个用户同时请求id,当它们同时请求完区间里的id时,会同时去请求id生成服务,此时就存在竞争了,只能有一个用户去请求id生成服务,其他用户服务被阻塞,导致性能降低。解决办法是采用双 buffer 的方案,首先请求生成id服务,比如生成1到1000范围的id,buffer1表示申请到了这个区间,并采用两个 int 来记录区间端点,每次获取id在 buffer1 表示的区间中获取,当 buffer1 中的id使用了10%后,请求生成id服务,生成1001到2000范围的id,由 buffer2 表示,如果 buffer1 用完了,就切换到 buffer2 表示的区间,buffer2 中的id使用了10%后,再次请求生成id服务,生成2001到3000范围的id,由 buffer1 表示,如此反复,这样就缓解了阻塞问题。
数据库多主模式
- 指的是两个或多个主库都能单独生产自增ID,auto_increment_offset 设置起始值,auto_increment_increment 设置自增步长,给他们配置不同的起始值和自增步长,比如有两个主库的话,一个设置起始值为1,步长为2,一个设置起始值为2,步长为2,这样他们的自增id分别为奇数和偶数,不会重复,即使某一个主库挂掉了,也不会影响另外一个主库来生成id。缺点是扩展性不好,比如想再添加一个主库来提高性能的话,那么之前主库的自增规则都需要修改,避免和新主库产生的id重复。
Redis 生成
- 利用 redis 的 incr 和 incrby 命令来实现原子性的自增,其中 incr 命令将 key 中存储的值加1,incrby 命令将 key 中存储的值加上指定的增量值。
- 优点:有序,效率高。
- 缺点:每次要向redis进行请求,有网络请求耗时,如果Redis挂了,就没法生成iD了,而且存在安全性问题,因为id是递增的,所以可以预测下一个id是多少;需要考虑持久化问题,redis支持RDB和AOF两种持久化方式。RDB持久化相当于定时打一个快照进行持久化,如果打完快照后,又连续自增了几次,但还没来得及打下一次快照,这个时候Redis挂掉了,重启Redis后会出现ID重复。AOF持久化相当于对每条写命令进行持久化,如果Redis挂掉了,不会出现ID重复的现象,但是会由于 incr 命令过多,导致重启恢复数据时间过长。
雪花算法
它是一种算法,不依赖数据库,核心思想是基于一个long类型的数来生成分布式id,一个long类型占8个字节,也就是64位,它划分为4个部分:
- 第一部分是标识符,占1位,一般id为正数,所以始终为0;
- 第二部分是时间戳,占41位,毫秒级别,存储的是当前时间和开始时间的差值,这样可以使产生的id从更小值开始。
- 第三部分是工作机器id,占10位,可以部署1024个节点,如果机器分机房(IDC)部署,这10位可以由 5位机房ID + 5位机器ID 组成。
- 第四部分是序列号,占12位,支持每个节点每毫秒可以生成4096个id序号。
- 优点:性能好;时间戳在高位,自增序列在低位,整个ID是趋势递增的;灵活度高,可以根据业务需求调整 bit 位的划分。
- 缺点:依赖机器的时钟,如果服务器时钟回拨,会导致重复ID生成。


265

被折叠的 条评论
为什么被折叠?



