分布式全局唯一ID解决方案


在公司去Oracle的要求下,需要对原有系统进行一些改造优化,由此引出了对分布式全局ID的一些思考。在平常的开发工作中可能不会对id做考量,一般都是使用数据库自带的自增主键或是sequence函数来生成id,但是随着业务的发展,系统会越来越大,会使用一些新的技术,例如分表分库,大数据,ES全文检索等。这时数据主键就越发变得重要,在分布式系统中,对于核心业务表的主键id设计需要考虑以下几点

  • 全局唯一:这里说的全局,可以是整个分布式系统,也可以是整个公司中,或是全球唯一。防止出现撞库
  • 趋势递增:多数关系型数据库索引基于B+树,尽可能的有序,可以更多的保证顺序读写,避免随机读写
  • 信息安全:在某些场景下,主键id的设计可能会加入业务字段,因此要保障信息安全

业界如支付宝,淘宝,美团,叮咚等,均采用 时间戳+userid后几位+随机数 或 唯一数+userid后几位。其原因在于随着业务发展,采用了分库方式解决数据库IO,线程数压力。结合业务场景大致均分为查询某人订单,通过某算法使对某个用户的订单创建和查询均操作到固定某个库(即因子分库法)。下面总结了几种常见分布式id生成方式

UUID

构成:当前日期和时间+时钟序列+全局唯一机器识别码(网卡)

优点:

  • 实现简单,本地生成,基本不会有性能问题
  • 全球唯一,在遇见数据迁移,系统数据合并,或者数据库变更等情况下,可以从容应对

缺点

  • 没有排序,无法保证趋势递增。
  • UUID往往是使用字符串存储,长度为32位的字符串,过长,从性能考虑不适合作主键

数据库序列号

构成:Oracle使用sequence,mysql使用自增字段

优点:

  • 简单,代码方便,性能可以接受。
  • 数字连续自增

缺点

  • 不适合分库系统,分库后ID会重复
  • 不同数据库语法和实现不同,数据库迁移的时候或多数据库版本支持的时候需要处理。
  • 在单个数据库或读写分离或一主多从的情况下,只有一个主库可以生成。有单点故障的风险。

Snowflake雪花算法

构成:整体64位,使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID),最后还有一个符号位,永远是0

优点

  • 简单高效,生成速度快
  • 时间戳在高位,自增序列在低位,整个ID是趋势递增的,按照时间有序递增。
  • 灵活度高,可以根据业务需求,调整bit位的划分,满足不同的需求。

缺点

  • 依赖机器的时钟,如果服务器时钟回拨,会导致重复ID生成。某台回拨N分钟,则该实例将N分钟内无法取号
  • 在分布式环境上,每个服务器的时钟不可能完全同步,有时会出现不是全局递增的情况。
  • 如采用中心化取号服务,对外提供服务,业务系统每次生成业务编号增加一次远程调用

Redis取号

构成:利用redis的自增函数,单线程特性,保障取号不会重复

优点

  • 趋势递增
  • 不依赖于数据库,灵活方便,且性能优于数据库。

缺点

  • 如果系统中没有Redis,还需要引入新的组件,增加系统复杂度。
  • Redis是单线程的,若造成阻塞,则会引发高并发问题,需要处理好集群与主从关系

取号服务

提供取号基础服务,底层为数据库sequence/自增长,该服务提供对数据库的操作。由client接入取号SDK,在SDK内缓存从取号基础服务获取的号段,当号段使用完,再次请求取号基础服务获取号段,同美团Leaf取号方案

优点

  • 性能好
  • Client端SDK获取号段,对业务系统侵入小

缺点

  • 依赖数据库,号段由数据库生成并在client端缓存,当数据库crash,短时间内不影响业务
  • 号段用完需要调用取号服务一次,增加调用链路长度
  • 当业务系统重启,未使用完号段丢失,造成跳号

各公司取号规则

淘宝订单号:唯一ID(13位数字)+userID后6位,共19位

支付宝订单号:YYYYMMDD+userID+唯一ID(具体构成不明),共21位数字

美团酒店订单号:snowflake19位数字,美团内部不同业务板块取号规则不同,如美团外卖订单号采用17位数字,美团电影,买菜订单11位数字

叮咚买菜订单:YYYYMMDD+userID(9位)+4位随机数,共19位数字

壹钱包订单号:1位大写字母+14位数字(类似产品编号)+YYYYMMDD+8位数字

平安银行基金:32位UUID


Author: 顺坚
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint polocy. If reproduced, please indicate source 顺坚 !
评论
 Previous
失血模型与充血模型 失血模型与充血模型
领域模型是对领域内的概念类或现实世界中对象的可视化表示。又称概念模型、领域对象模型、分析对象模型。它专注于分析问题领域本身,发掘重要的业务领域概念,并建立业务领域概念之间的关系。 业务对象模型(也叫领域模型domain model)是描述业
2022-02-20
Next 
mybatis的实现原理 mybatis的实现原理
MyBatis是一个流行的ORM框架,面向接口编程的方式,大大简化了数据库的操作。MyBatis的底层操作封装了JDBC的API,MyBatis的工作原理以及核心流程与JDBC的使用步骤一脉相承,MyBatis的核心对象(SqlSessio
2022-02-13
  TOC