Leaf 详解

  • 参考博客:Leaf:美团分布式ID生成服务开源

Leaf是美团基础研发平台推出的一个分布式ID生成服务

  • 9种分布式ID生成之美团(Leaf)实战

一、Leaf 号段生成

1、Leaf 特性

  • 全局唯一:不会出现重复 ID,且 ID 整体趋势递增
  • 高可用:基于分布式架构,即使 MySQL 宕机,也能容忍一段时间的数据库不可用
  • 高并发低延时:在 CentOS 4C8G 的虚拟机上,远程调用QPS可达5W+,TP99在1ms内
  • 接入简单:可通过 RPC 服务或 HTTP 调用接入

2、Leaf 详解

  • Leaf 采用预分发方式生成 ID:即在 DB 上挂 N 个 Server,每个 Server 启动时,都去 DB 拿固定长度的 ID List,因此完全基于分布式的架构

    同时 ID 由内存分发,所以也很高效

  • Leaf 数据持久化:每次去 DB 拿固定长度的 ID List,然后把最大的 ID 持久化下来

    即:并非每个 ID 都做持久化,仅仅持久化一批 ID 中最大的那个,极大减轻了 DB 持久化的压力

用户通过 Round-robin 方式调用 Leaf Server 的各个服务,当某个 Leaf Server 号段用完后,下一次请求就会从 DB 中加载新的号段,保证了每次加载的号段递增

Leaf Server 加载号段的 SQL 语句如下:

Begin
	UPDATE table SET max_id=max_id+step WHERE biz_tag=xxx
	SELECT tag, max_id, step FROM table WHERE biz_tag=xxx
Commit

问题

  • 更新 DB 时会出现耗时尖刺,系统最大耗时取决于更新 DB 号段的时间
  • 更新 DB 号段时,若 DB 宕机或发生主从切换,会导致一段时间的服务不可用

3、Leaf 优化

(1) Leaf 双 Buffer 优化

解决上述问题:采用异步更新策略,通过双 Buffer 方式,保证无论何时 DB 出现问题,都能有一个 Buffer 号段可以正常对外提供服务,只要 DB 在一个 Buffer 的下发的周期内恢复,就不会影响整个 Leaf 的可用性

问题

  • 号段长度固定:若 Leaf 能在 DB 不可用时维持10分钟正常工作,但若流量增加10倍就只能维持1分钟正常工作了
  • 若号段长度设置的过长,导致缓存中的号段迟迟消耗不完,进而导致更新 DB 的新号段与前一次下发的号段ID跨度过大

(2) Leaf 动态调整 Step 优化

  • 问题分析:假设服务 QPS 为 Q,号段长度为 L,号段更新周期为 T,则 Q * T = L

    • 最开始 L 长度固定,导致随着 Q 的增长,T 会越来越小
    • 但 Leaf 希望 T 固定,因此若 L 可以和 Q 正相关,则 T 就可以趋近一个定值
  • 解决方案:Leaf 每次更新号段时,根据上一次更新号段的周期 T 和号段长度 step,来决定下一次的号段长度 nextStep

    • T < 15min,nextStep = step * 2
    • 15min < T < 30min,nextStep = step
    • T > 30min,nextStep = step / 2

问题:若流量瞬时几十、几百倍的暴增,仍不能满足容忍数据库在一段时间不可用、系统仍能稳定运行的需求

(3) MySQL 高可用优化

  • 问题分析:Leaf 虽然在 DB 层做了些容错方案,但号段方式的 ID 下发,最终还是强依赖 DB
  • 解决方案:在 MySQL 层,Leaf 目前采取半同步方式同步数据,未来追求完全的强一致

    Leaf 采用一个临时方案来保证机房断网场景下的数据一致性:

    • 多机房部署数据库,每个机房一个实例,保证都是跨机房同步数据
    • 半同步超时时间设置到无限大,防止半同步方式退化为异步复制

(4) 未来优化

  • 号段加载优化
    • 目前方案:Leaf 目前重启后的第一次请求还是同步加载 MySQL

      原因:MySQL 中的 Leaf Key 并非一定都被这个 Leaf 服务节点所加载,若每个 Leaf 节点都在初始化加载所有的Leaf Key 会导致号段的大量浪费

    • 未来方案:在 Leaf 服务 Shutdown 时,备份这个服务节点近一天使用过的 Leaf Key 列表,这样重启后会预先从MySQL 加载 Key List 中的号段
  • 单调递增:只要保证同一时间、同一个 Leaf Key 都从一个 Leaf 服务节点获取 ID,即可保证递增

    注意:Leaf 服务节点切换时,旧 Leaf 服务用过的号段需要废弃
    方案:路由逻辑,可采用主备的模型或每个 Leaf Key 配置路由表的方式来实现

二、Leaf 雪花算法生成

通过时间+机器号+自增 ID的组合来实现完全分布式的 ID:

  • 1 位为 0
  • 2-42 位是相对时间戳,通过当前时间戳减去一个固定的历史时间戳生成
  • 43-52 位是机器号 workerID,每个 Server 的机器 ID 不同
  • 53-64 位是自增 ID

注:Leaf 在第一次从 Zookeeper 拿取 workerID 后,会在本机文件系统上缓存一个 workerID 文件,即使 ZooKeeper 出现问题,同时恰好机器也在重启,也能保证服务的正常运行

三、号段与雪花的对比

  • 号段模式:低位趋势增长,较少的 ID 号段浪费,能够容忍 MySQL 的短时间不可用
  • Snowflake 模式:完全分布式,ID 有语义

github 仓库:Meituan-Dianping/Leaf

本文地址:https://blog.csdn.net/yin__ren/article/details/109625402

(0)
上一篇 2022年3月21日
下一篇 2022年3月21日

相关推荐