总结全局唯一ID生成方法

364 阅读3分钟

什么是全局唯一?

首先先理解下全局唯一,为什么叫全局呢,肯定你的后台服务是是非单点、集群的模式来支撑业务的,否则你单点服务mysql auto_increment就完美支持了。非单点带来的问题就是更高的并发下的安全问题,且运行环境隔离,在这种环境下,那么如果保证id唯一呢?且一个好的全局id最好要是有序的,这样查询性能会更好,才能更好的服务业务。

什么场景下需要全局唯一id?

理解了何为全局唯一id,那么什么场景下需要呢?比如数据库分库分表下需要保证每条记录的唯一性;商品的订单号,业务流水号等。

全局唯一id的实现方法

数据库 自增策略 实现

数据库自增唯一策略,几乎所有的业务系统都有数据库,所以这个是最常见且接入成本最低的方法。

如果你的系统只有一个master主库,目前大部分系统都是这样,单点库或者一主多从,或者单库分表,统称为主库单点获取。

主库单点: 优点:接入成本很低,简单,且生成的id有序。 缺点:单点不安全;一次生成一个,高并发大流量场景下,业务线程可能阻塞,存在性能隐患。 优化方案: 批量id生成,一次生成多个id,用完了再来申请,相对单点不批量能够支持一定的流量。

相对于主库单点,如果你的系统存在多个master节点,相对于单点,多个master节点性能肯定会更好,集群负载更高,且每台master机器也可以通过批量id生成。可以通过设置每台master节点设置不同的起始值,步长一直就可以了,比如:Master1 生成的是 1,4,710,Master2生成的是2,5,8,11 Master3生成的是 3,6,9,12。这样就可以生成集群中的唯一ID。

Redis的原子操作 INCR 和 INCRBY 来实现:

Redis一主的情况下:
    优点:单节点,redis单线程,不会出现id重复的现象,且生成的id有序,基于内存性能优于mysql。
    缺点:单点不安全,存在性能瓶颈。如果你的系统没有redis,有一定的接入成本。
Redis多主的情况下,可以参照数据库多master节点的方案,可以通过设置每台master节点设置不同的起始值,步长一直就可以了。

算法解决

比如snowflake,它是Twitter开源的分布式ID生成算法,结果是一个long型的ID。

其核心思想是:使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID),最后还有一个符号位,永远是0,这样一个长度为64位的二进制数来生成。

优点:性能高效,接入成本低,id自增有序;能够支持一定并发。
缺点:
    1.如果服务器始终回退可能会有重复id的风险,不过这个可以通过代码保证如果存在时钟回退的情况,抛出异常,报警给研发人员,及时回调时钟。
    2.分布式环境中存在不同机器的时钟不一致,可能会出现重复id的风险,要避免的话需保证集群时钟一致。

总结

具体的id获取方法要根据具体的业务场景、不同的业务需要去选择,没有绝对的好与不好,存在即合理。