欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Leaf 详解

程序员文章站 2022-06-17 18:57:21
参考博客:Leaf:美团分布式ID生成服务开源Leaf是美团基础研发平台推出的一个分布式ID生成服务一、Leaf 号段生成1、Leaf 特性全局唯一:不会出现重复 ID,且 ID 整体趋势递增高可用:基于分布式架构,即使 MySQL 宕机,也能容忍一段时间的数据库不可用高并发低延时:在 CentOS 4C8G 的虚拟机上,远程调用QPS可达5W+,TP99在1ms内接入简单:可通过 RPC 服务或 HTTP 调用接入2、Leaf 详解Leaf 采用预分发方式生成 ID:即在 ....

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

一、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 持久化的压力

Leaf 详解

用户通过 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 详解
问题

  • 号段长度固定:若 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 雪花算法生成

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

相关标签: 分布式