分布式id

ID生成策略

可以自定义加入业务团队id | 年份等其它业务维度来制定策略 ,补充直观性

比如 库位编码,商品编码

带来的好处:如果生成的策略和业务相关

A01-001-23 (库位编码,仓库地点,库区,楼层,通道,层级,库位 …… 库位类型等等)

B-100-2018000001(B表示冷冻品,100表示商品二级分类,后面的表示批次)

snowflake(雪花)

snowflake是twitter开源的分布式ID生成算法,其核心思想是:一个long型的ID,使用其中41bit作为毫秒数,10bit作为机器编号,12bit作为毫秒内序列号。这个算法单机每秒内理论上最多可以生成1000*(2^12),也就是400W的ID,完全能满足业务的需求。

缺点:生成的ID不是很直观

其它生成技术

redis , zk , uuid

redis ,zk

  • 实现太重了,需要网络和服务器资源
  • 调用链路过长,不用应对高并发的场景
  • zookeeper有性能瓶颈
    • 读还好,写并发上k级别时,集群越大 写瓶颈越明显
    • 半数同意才能提交
  • redis cluster ,超高并发下也会有延时 , 性能瓶颈

uuid 不适合筛选,不是趋势递增

自定义分布式ID算法

借鉴snowflake的思想,结合各公司的业务逻辑和并发量,可以实现自己的分布式ID生成算法。

举例,假设某公司ID生成器服务的需求如下:

(1)单机高峰并发量小于1W,预计未来5年单机高峰并发量小于10W

(2)有2个机房,预计未来5年机房数量小于4个

(3)每个机房机器数小于100台

(4)目前有5个业务线有ID生成需求,预计未来业务线数量小于10个

(5)…

分析过程如下:

(1)高位取从2016年1月1日到现在的毫秒数(假设系统ID生成器服务在这个时间之后上线),假设系统至少运行10年,那至少需要10年365天24小时3600秒1000毫秒=320*10^9,差不多预留39bit给毫秒数

(2)每秒的单机高峰并发量小于10W,即平均每毫秒的单机高峰并发量小于100,差不多预留7bit给每毫秒内序列号

(3)5年内机房数小于4个,预留2bit给机房标识

(4)每个机房小于100台机器,预留7bit给每个机房内的服务器标识

(5)业务线小于10个,预留4bit给业务线标识

39bit 4bit 2bit 7bit 预留 7bit
毫秒数 业务线 机房 机器 毫秒内序列号

64位相当于20位的无符号长整形

59位相当于18位的长整形

这样设计的64bit标识,可以保证:

(1)每个业务线、每个机房、每个机器生成的ID都是不同的

(2)同一个机器,每个毫秒内生成的ID都是不同的

(3)同一个机器,同一个毫秒内,以序列号区分保证生成的ID是不同的

(4)将毫秒数放在最高位,保证生成的ID是趋势递增的

缺点

(1)由于“没有一个全局时钟”,每台服务器分配的ID是绝对递增的,但从全局看,生成的ID只是趋势递增的(有些服务器的时间早,有些服务器的时间晚)

最后一个容易忽略的问题

生成的ID,例如message-id/ order-id/ tiezi-id,在数据量大时往往需要分库分表,这些ID经常作为取模分库分表的依据,为了分库分表后数据均匀,ID生成往往有“取模随机性”的需求,所以我们通常把每秒内的序列号放在ID的最末位,保证生成的ID是随机的。

又如果,我们在跨毫秒时,序列号总是归0,会使得序列号为0的ID比较多,导致生成的ID取模后不均匀。解决方法是,序列号不是每次都归0,而是归一个0到9的随机数。

分布式ID生成的服务架构

生成策略

预加载机制
  • 提前加载
  • 并发获取,使用Disruptor框架提升性能
  • 可以使用zk,redis加个业务线的生成规则配置成元数据提供给id生成服务
单点生成方式
  • 固定机器生成 ,好处是可以做到全局唯一,缺点就是单点
  • 业务规则拼接:机器码+时间戳+自增序列
    • 如果需要时间戳 或者 与时钟相关的串 来拼接,则要考虑NTP问题
    • NTP问题:高并发下时间校准,ID生成服务器(时间走的比标准的快一些)同步标准时间服务器
    • 自增序列:AtomicLong

实现

一定要做兜底(补偿)策略

保证能走通核心链路

(预加载机制+单点生成方式)

实际使用上面两种方式相结合

架构角色功能
  • zk cluster 配置服务中心

    • 配置ID规则
    • 如果服务业务线过多,可提供id规则的路由服务 提高规则的查询效率
  • 定时任务

    • 独立服务

    • 监控服务id使用率,达到配置的阈值60%就启动任务

    • 最好不要在系统使用高峰期间启动任务

    • job (生成id载入到服务本地cache【Guava】和MySQL中,可以防止单点问题,并提高性能)

  • Guava缓存

  • DB (MySQL or NoSQL)

  • Mutil Producer

    • Service ABC id请求收集
  • WorkerPool Consumer

    • id返回
    • 由WorkerPool Consumer并发的返回给serviceA,B,C
  • Service A ,B,C,D (各业务线服务)

  • Disruptor框架:可以用它来提高业务并发性能

posted @ 2021-06-27 16:14  沉梦匠心  阅读(71)  评论(0)    收藏  举报