分布式ID生成器高可用方案

背景
由于目前的公司要进行分库分表,而分库分表就要有一个全局唯一的id. 并且 由于后续要根据id范围灰度切流量 并且根据Id分库分表。希望id是递增的, 由于灾备的考虑 也希望ID持久化。
经过分析  id递增和持久化有以下优点
 id递增:
  1. 方便灰度控制,
  2. 线上压测,要求跳号(本人经历过)
  3. id通常是数据库的主键, id有序可以提升索引 创建和查询的性能。
Id持久化:
  1. 方便统计查询
  2. 灾备恢复
目前常见的方案
使用数据库的auto_increment ,UUID,snowflake算法。详见58沈剑的公众号
细聊分布式ID生成方法: https://mp.weixin.qq.com/s/0H-GEXlFnM1z-THI8ZGV2Q
 笔者工作过的某大型电商,维护过订单生成系统,日均800W订单,用的是 多库 auto_increment 这种方案,当时 我们就发现性能已经不不满足需求,但是却无法扩展。
 偶然发现数据库的auto_increment 的改进方案,有茅塞顿开的感觉。遗憾的是文中方案的细节提到甚少,且有单点问题。
参照下文中Leaf部分
MTDDL——美团点评分布式数据访问层中间件: http://tech.meituan.com/mtddl.html
 美团的Leaf ID生成方案分析
优点:
以update代替insert,减少数据库生成数据量
使用应用local memory,可以抗大并发
可以为多个业务线服务
缺点:
数据库单点
 我们经过讨论 是不希望有单点问题的。
经过认真思考 设计如下图
 

 
 
库表结构
3个库 每个库中有一张表 seq
tag: 业务标识, max_id:订单范围值 count: 每次要取的id数 step: id增长步长(等于总表数)
 
怎么保证唯一性
多张表max_id 顺序递增(假设有4个库)
每次update: max_id=max_id
3张seq表未修改前max_Id值 : 1 ,2 ,3,4
第一轮 : 5, 6, 7,8
第二轮 : 7,8,9,10
so:生成的id不会重复
由于性能的要求 每次要取多个订单号,此时的策略是取一个范围,。
可以把max_id作为一个范围。
 
订单号生成流程
请求过来后, 应用根据负载均衡选中一个库,执行 max_id=max_id+count*step
在应用中定义 start, max , 每取一次订单号 return start+step, 直到耗尽范围重新获取
 
此方案是美团leaf 的改进,解决了数据库单点的问题。
 
方案中怎么解决如下问题
  1. 高并发
  2. 递增
  3. 分布式数据库
  4. 扩容
  • 高并发:应用使用local缓存生成id号,增加应用服务数量即可扩展
  • 递增:利用数据库步长实现 趋势递增
  • 分布式数据库:用step字段解决了 单库的问题
  • 扩容: 扩容前可在表中增加一条新的规则,先启用, 等新的数据库上线后, 修改应用配置,重启即 可,可以做到安全迁移
因为每次取订单号范围都要访问数据库导致性能曲线抖动。
 实现了防止性能抖动的方法
目前遗留的问题
 每次取范围都是都要执行 update, select 目前是通过DB事务控制,防止数据库并发问题导致多个应用取到相同范围
代码中updateRange 部分使用 锁实现,性能不高
 压测方面目前 使用HTTP协议,能在4C8G的机器上QPS能压测到近4w/s,TP99 1ms
唯一性测试:生成3500W订单号,无重复.
目前已经上线,稳定运行。
补充:美团Leaf的方案详见: https://mp.weixin.qq.com/s/Bk5k6vRG4Rq4iCtmtYDEGQ, 可惜该文章发表时,我们的ID生成器已经完成开发,SO 我们的实现只是参照了 本文开始提到的Leaf的大概思路。
 
 
 
 
 

猜你喜欢

转载自chenchangqun.iteye.com/blog/2377391