11. Leaf-segment 分布式ID

2023-11-03

Spring Cloud 微服务系列文章,点击上方合集↑

1. 开头

当应用程序只使用单个数据库时,可以使用数据库自增的方式来生成id,这种方式既简单,查询又快。

然而,当应用程序需要进行分库分表时,即将数据分散到多个数据库和数据表中,使用数据库自增的方式会导致id在不同表中重复,那么就需要使用分布式id来确保不同表中id的唯一性。

分布式id通常有以下几种方式:

  • UUID
  • snowflake 雪花算法
  • 数据库生成(本文的方式)

关于分布式id的几种方式具体可以看美团技术的这篇文档:https://tech.meituan.com/2017/04/21/mt-leaf.html

2. Leaf-segment 数据库方式

这里用美团的 Leaf 数据库号段模式 进行了改造。

美团的 Leaf 号段模式源码地址:https://github.com/Meituan-Dianping/Leaf

选择此种方式的原因有如下:

  • 生成的 id 是连续递增的
  • 对于数据库索引更快
  • 使用更简单

为什么不用雪花算法?雪花算法有个时钟回拨的问题,为了解决这个问题还需要引入redis或zk。同样都是需要借助中间件,那就直接用数据库更方便。

为什么不用uuid?uuid是字符串查询速度慢,而且阅读不友好。

3. 原理分析

使用数据库来生成分布式id相当于一个一个发放编号,需要不断与数据库交互,速度较慢。而美团的号段方式则可以批量获取一段可用编号,避免了频繁的数据库交互,速度更快。可以类比为领取学号,一个一个领需要排队等待,批量发放可以省去排队的时间。

数据库号段模式生成 id 的具体原理如下:

  1. Leaf 服务器从数据库加载当前的号段信息,包括起始值和结束值。

  2. 当有业务系统需要生成 id 时,向 Leaf 服务器发送请求。

  3. Leaf 服务器根据请求判断是否需要重新加载号段。

  4. 如果当前号段已经用完,Leaf 服务器从数据库获取下一个号段。

  5. 获取到新的号段后,Leaf 服务器将其存储在内存,并更新数据库中的当前值。

  6. 返回给业务系统的 id 是号段中的连续整数序列。

通过这种方式,Leaf 可以快速生成一批连续的唯一 id,避免频繁与数据库交互,并保证生成的 id 是唯一的。同时,通过加载新的号段,Leaf 可以满足大规模、高并发的分布式 id 生成需求。

4. 使用

4.1 执行sql

生成leaf_alloc表。

CREATE TABLE `leaf_alloc`  (
  `biz_tag` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
  `max_id` bigint(20) NOT NULL DEFAULT 1,
  `step` int(11) NOT NULL,
  `description` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `update_time` timestamp(0) NOT NULL DEFAULT current_timestamp(0) ON UPDATE CURRENT_TIMESTAMP(0),
  PRIMARY KEY (`biz_tag`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of leaf_alloc
-- ----------------------------
INSERT INTO `leaf_alloc` VALUES ('test', 1, 2000, '测试', '2022-11-14 17:18:12');

SET FOREIGN_KEY_CHECKS = 1;

各个业务不同的发号需求用biz_tag字段来区分,每个biz_tag的ID获取相互隔离,互不影响。

4.2 启动 id-service 服务

这里将生成分布式id做成了一个服务id-service,相关源码在仓库的这个目录下:/sourcecode/spring-cloud-demo/id-service

可以直接通过调用接口来测试获取生成的id。

接口地址:http://localhost:8070/id/generate?key=test

注意:对于不同的业务表,在leaf_alloc数据表使用不同的biz_tag,比如商品表就在leaf_alloc表中插入biz_tagproduct的一条记录,获取id传入参数就是key=product

4.3 服务调用

其它业务模块通过服务调用的方式获取生成的id。

@FeignClient(name = "id-service")
public interface IdService {

    @GetMapping("/id/generate")
    Long generateId(@RequestParam String key);
}
  • 注意不同的业务表传入不同的key。

5. 结语

本文通过Leaf-segment数据库号段的方式生成分布式id,这种方式可以让生成的id从0开始逐一递增,但是需要维护一个leaf_alloc数据表,对于新的业务表需要在leaf_alloc中插入一条新的记录。

有多少张业务表就需要在leaf_alloc表中插入多少条记录。

我们将生成分布式id做成了一个服务id-service,后面分库分表等其它服务会调用id-service这个服务来生成id。


Spring Cloud 微服务系列 完整的代码在仓库的sourcecode/spring-cloud-demo目录下。

gitee(推荐):https://gitee.com/cunzaizhe/xiaohuge-blog

github:https://github.com/tigerleeli/xiaohuge-blog

关注微信公众号:“小虎哥的技术博客”,让我们一起成为更优秀的程序员❤️!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

11. Leaf-segment 分布式ID 的相关文章

  • 分析工具 nvprof简介

    nvprof 是一个可用于Linux Windows和OS X的命令行探查器 使用 nvprof myApp 运行我的应用程序 我可以快速看到它所使用的所有内核和内存副本的摘要 摘要将对同一内核的所有调用组合在一起 显示每个内核的总时间和总
  • 十六进制转二进制

    public static String hexToBinary String hex if hex null hex length 2 0 return null String bString String tmp for int i 0
  • Visual Studio(VS) 编程推荐字体和主题设置

    首先是字体 工具 gt 选项 gt 环境 gt 字体和颜色 具体图如下 选择Consolas的原因 Consolas算是最常见的编码字体了 在很多的编译软件都是这个字体 而且在这个字体下的中英文标点和半角圆角符号也能有比较明显的区别 至于字

随机推荐

  • Java 集合 - Map 接口

    文章目录 1 概述 2 常用 API 3 遍历 Map 集合 4 HashMap 和 Hashtable 5 LinkedHashMap 6 TreeMap 7 Properties 8 Set 集合与 Map 集合的关系 9 总结 1 概
  • C++11/14之模板全特化,偏特化

    目录 模板全特化 偏特化 类模板特化 类模板全特化 a 常规全特化 b 特化成员函数而不是模板 类模板偏特化 局部特化 a 模板参数数量 b 模板参数范围 int const int 比int小 函数模板特化 函数模板全特化 函数模板偏特化
  • LayerNorm的理解

    LayerNorm计算公式 y x E x
  • C语言实现多级反馈队列调度算法

    include
  • java架构师进阶之路

    Java架构师 应该算是一些Java程序员们的一个职业目标了吧 很多码农码了五六年的代码也没能成为架构师 那成为Java架构师要掌握哪些技术呢 总体来说呢 有两方面 一个是基础技术 另一个就是组织能力和提出解决方案能力了 如果你是想成为Ja
  • Netty入门-Channel

    目录 Channel详解 Channel的特点 Channel接口方法 ChannelOutboundInvoker接口 AttributeMap接口 ChannelHandler接口 ChannelInboundHandler接口 Cha
  • 请取件

    Part1前言 最常见的鼠标平移算法是平行于水平面 地面 的 无论相机视角如何 平移时 相机的世界Z值始终不变 因为绝大多数场景都是在观察地面上的物体 而人类的行走总是平行于地面的 但是本文要介绍的另一种小众的平移算法则平行于视锥体的截面
  • JPA使用审计功能新增时, 不自动更新@LastModifiedDate和@LastModifiedBy字段

    JPA使用审计功能新增时 不自动更新 LastModifiedDate和 LastModifiedBy字段 疑问 查询源码 解决方案 疑问 JPA使用审计功能 网上有一大堆demo 但是使用时 会发现创建的时候会自动填写 LastModif
  • Mac安装homebrew报错curl: (7) Failed to connect to raw.githubusercontent.com port 443: Operation

    homebrew安装时 一般直接在终端直接输入命令 usr bin ruby e curl fsSL https raw githubusercontent com Homebrew install master install 但是这个方
  • Numpy/Pytorch之数据类型与强制类型转换

    目录 1 数据类型简介 Numpy Pytorch 2 Python的type 函数 3 Numpy Pytorch的dtype属性 4 Numpy中的类型转换 先聊聊我为什么会用到这个函数 不看跳过 astype 函数 输出 4 Pyto
  • 【线性表的原地逆置】

    目录 前言 一 顺序表 数组 一 双指针 二 单链表 一 模拟顺序表的双指针 交换的节点的值域 二 头插法 改变节点的指针域 三 递归实现 将整体链表反向 整体代码 总结 前言 打怪升级第一天 大家好 今天我们来了解一下数组和单链表的原地逆
  • (mybatis驼峰命名导致映射错误)

    今天在复习mybatis时遇到这样的一个问题 我数据库表的字段和我定义的实体类名不一致 中间有下划线 如下图 实体类 数据库字段 结果会导致部分查询数据是null 于是我首先想到了自己定义一个resultmap映射 给数据库字段取一个别名
  • Android 学习之多状态布局的一种实现方案

    开发应用的过程中 首页的控件越来越多 布局文件的代码已经到了爆表的程度 而且不同状态下首页各个控件的 Visibility 不同 每次新增状态都是一件头疼的事情 时常遗漏控件导致出错 和 YYY 大佬交流讨论后他给出了一种巧妙的方案 特此学
  • 人工智能数学基础:费马引理、罗尔定理、拉格朗日微分中值定理、柯西中值定理

    一 费马 Fermat 引理 费马 Fermat 引理 设函数f x 在点x0的某邻域U x0 内有定义 并且在x0处可导 如果对任意的x U x0 有f x f x0 或f x f xo 那么f x0 0 老猿认为费马引理就是说明 对于某
  • 简单通俗易懂:一个小例子完美解释Naive Bayes(朴素贝叶斯)分类器

    更多深度文章 请关注 https yq aliyun com cloud 最简单的解决方案通常是最强大的解决方案 而朴素贝叶斯就是一个很好的证明 尽管机器学习在过去几年取得了巨大的进步 但朴素贝叶斯已被证明不仅简单 而且快速 准确 可靠 它
  • 从原理到代码实践

    文章目录 1 损失函数原理 1 1 Classification Error 分类错误率 1 2 均方差损失 1 3 交叉熵损失函数 1 3 1 数学原理 1 3 2 代码实现 对于图像分类任务 模型最终是通过softmax操作输出一个概率
  • Java: String与其他数据的相互转化

    1 java lang包中的Byte Short Long Float Double类调用相应的类方法 将由 数字 字符组成的字符序列转化为相应的基本数据类型 public static byte parseByte String s th
  • 如何制作点餐小程序?

    随着移动互联网的发展 点餐小程序的出现越来越受到大家的欢迎 它方便快捷 可以随时随地点餐 特别是在疫情期间更受到了用户的喜爱 那么 如何制作一个点餐小程序呢 下面将会简单介绍一下步骤 并通过一个具体案例来解析运用了哪些技巧提升了效果 一 确
  • 容器 - unordered_map

    unordered map是C Boost库中的内容 这里的unordered指的是散列式的存储方式 unordered库提供了两个散列映射表 unordered map和unordered multimap 利用散列表代替了二叉树的实现
  • 11. Leaf-segment 分布式ID

    Spring Cloud 微服务系列文章 点击上方合集 1 开头 当应用程序只使用单个数据库时 可以使用数据库自增的方式来生成id 这种方式既简单 查询又快 然而 当应用程序需要进行分库分表时 即将数据分散到多个数据库和数据表中 使用数据库