跳转至

分布式 ID 生成器

问题背景

在分布式系统中,往往需要对大量的数据和消息做唯一标识。随着业务增长,对数据库分库分表后需要有一个唯一ID来标识一条数据或消息,数据库的自增ID显然不能满足要求。这时一个能够生成全局唯一ID的系统是非常必要的。业务系统对ID好的需求概括如下:

  • 全局唯一性:不重复
  • 趋势递增:在MySQL的InnoDB引擎中使用的是 聚集索引 ,由于多数RDBMS使用B-tree来存储索引数据,在主键的选择上面我们尽量使用有序的主键保证写入性能。
  • 单调递增:保证下一个ID一定大于上一个ID,例如事务版本号、IM增量消息、排序等特殊需求。
  • 信息安全:如果ID是连续的,会使得恶意爬取非常容易,直接按照顺序下载指定URL即可;如果是订单号,那么竞对可以很容易通过订单号指导一天的订单量。所以在一些场景下,需要ID 无规则不规则
  • 高可用性

常见方法

UUID

UUID(Universally Unique Identifier)的标准形式包含32个16进制数字,以连字符分为5段,形式为8-4-4-4-12的36个字符,示例:550e8400-e29b-41d4-a716-446655440000。详见IETF发布的UUID规范:A Universally Unique IDentifier (UUID) URN Namespace

优点

  • 性能非常高:本地生成,没有网络消耗

缺点:

  • 不易于存储:128位,通常以36长度的字符串表示,很多场景不适用。
  • 安全性差:基于MAC地址生成UUID的算法可能会导致MAC地址泄露,该漏洞曾被用于定位梅丽莎病毒的只做这位置。
  • ID作为主键时在特定的环境会存在一些问题,比如做DB主键的场景下,UUID就非常不适用:
    • MySQL官方明确建议主键要尽量越短越好,36个字符长度的UUID不符合要求;
    • 对数据库索引不利,在InnoBD引擎下,UUID的无序性可能会引起数据位置频繁变动,严重影响性能

类SnowFlake方案

优点

  • 毫秒数在高位,自增序列在低位,整个ID都是趋势递增的
  • 不依赖数据库等第三方系统,以服务的方式部署,稳定性更高,生成ID的性能也是非常高的
  • 可以根据自身业务特性分配bit位,非常灵活

缺点

  • 强依赖机器时钟,如果机器上时钟回拨,会导致发号重复或者服务处于不可用状态