分布式全局唯一id实现-4 springCloud-MyBatis-Plus集成美团分布式全局id(leaf)

news2025/3/10 15:54:04

前言:美团的leaf集成了db分段生成id和雪花算法生成分布式id,本文对其实现部分细节展开讨论,leaf 的具体实现请参考:https://tech.meituan.com/MT_Leaf.html;

1 使用db分段id:

leaf 的分段id本质上是使用了id的区间段,看下id 区间段表:

CREATE TABLE `leaf_alloc` (
  `biz_tag` varchar(128) NOT NULL DEFAULT '',
  `max_id` bigint(20) NOT NULL DEFAULT '1',
  `step` int(11) NOT NULL,
  `description` varchar(256) DEFAULT NULL,
  `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`biz_tag`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
  • 使用biz_tag 作为业务的隔离;
  • 使用max_id 作为下一段id 的起始值;
  • 使用step 作为每段id 的长度
    在这里插入图片描述
    id 的获取过程:
  • 每次项目启动后,(开启了分段id 的开关)去获取分段id后,放入到系统的内存中
  • 当使用的时候,通过http 请求接口:/api/segment/get/{key} 得到id,其中key对应leaf_alloc的biz_tag ;
  • 获取本次使用的id 段SegmentBuffer,然后+1得到本次使用的id 并返回(如果本段的id 使用超过了10% 则去申请下一段id);

2 雪花算法id:

使用雪花算法生成的id 也是由时间戳+机器位+序列号组成的64位数字id,其中值得注意的是workId,会在每次项目启动的使用先去zookeeper中,通过ip+port 组成的key 去获取是否已经注册过,如果已经注册过则直接使用,否则注册持久有序的节点,以此来保证workId 唯一性;
看下SnowflakeZookeeperHolder 类中init 方法:

public boolean init() {
    try {
         CuratorFramework curator = createWithOptions(connectionString, new RetryUntilElapsed(1000, 4), 10000, 6000);
         curator.start();
         Stat stat = curator.checkExists().forPath(PATH_FOREVER);
         if (stat == null) {
         		
             //不存在根节点,机器第一次启动,创建/snowflake/ip:port-000000000,并上传数据
             zk_AddressNode = createNode(curator);
             //worker id 默认是0
             updateLocalWorkerID(workerID);
             //定时上报本机时间给forever节点
             ScheduledUploadData(curator, zk_AddressNode);
             return true;
         } else {
             Map<String, Integer> nodeMap = Maps.newHashMap();//ip:port->00001
             Map<String, String> realNode = Maps.newHashMap();//ip:port->(ipport-000001)
             //存在根节点,先检查是否有属于自己的根节点
             List<String> keys = curator.getChildren().forPath(PATH_FOREVER);
             for (String key : keys) {
                 String[] nodeKey = key.split("-");
                 realNode.put(nodeKey[0], key);
                 nodeMap.put(nodeKey[0], Integer.parseInt(nodeKey[1]));
             }
             //   private String listenAddress = null;//保存自身的key ip:port
             Integer workerid = nodeMap.get(listenAddress);
             if (workerid != null) {
                 //有自己的节点,zk_AddressNode=ip:port
                 zk_AddressNode = PATH_FOREVER + "/" + realNode.get(listenAddress);
                 workerID = workerid;//启动worder时使用会使用
                 if (!checkInitTimeStamp(curator, zk_AddressNode)) {
                     throw new CheckLastTimeException("init timestamp check error,forever node timestamp gt this node time");
                 }
                 //准备创建临时节点
                 doService(curator);
                 updateLocalWorkerID(workerID);
                 LOGGER.info("[Old NODE]find forever node have this endpoint ip-{} port-{} workid-{} childnode and start SUCCESS", ip, port, workerID);
             } else {
                 //表示新启动的节点,创建持久节点 ,不用check时间
                 String newNode = createNode(curator);
                 zk_AddressNode = newNode;
                 String[] nodeKey = newNode.split("-");
                 workerID = Integer.parseInt(nodeKey[1]);
                 doService(curator);
                 updateLocalWorkerID(workerID);
                 LOGGER.info("[New NODE]can not find node on forever node that endpoint ip-{} port-{} workid-{},create own node on forever node and start SUCCESS ", ip, port, workerID);
             }
         }
     } catch (Exception e) {
         LOGGER.error("Start node ERROR {}", e);
         try {
             Properties properties = new Properties();
             properties.load(new FileInputStream(new File(PROP_PATH.replace("{port}", port + ""))));
             workerID = Integer.valueOf(properties.getProperty("workerID"));
             LOGGER.warn("START FAILED ,use local node file properties workerID-{}", workerID);
         } catch (Exception e1) {
             LOGGER.error("Read file error ", e1);
             return false;
         }
     }
     return true;
 }

ip 获取已激活网卡的IP地址,端口号来自于:leaf.snowflake.port 的设置;

3 MyBatis-Plus集成:

目前已经了解了分布式id 的生成方式,只需要在需要的项目中,创建package com.baomidou.mybatisplus.core.incrementer 包,并创建DefaultIdentifierGenerator 类:重写nextId 方法,通过http 访问获取id 的接口得到id即可。

package com.baomidou.mybatisplus.core.incrementer;

import com.alibaba.fastjson2.JSONObject;
import com.xiaoju.uemc.tinyid.client.utils.TinyId;
import lombok.extern.slf4j.Slf4j;

import java.util.Map;

@Slf4j
public class DefaultIdentifierGenerator implements IdentifierGenerator {
    @Override
    public Long nextId(Object entity) {
        Object o = null;
        if (null != entity) {
            Map<String, Object> eMap = JSONObject.parseObject(JSONObject.toJSONString(entity), Map.class);

            if (eMap.containsKey("bizTag")) {
                o = eMap.get("bizTag");
            }
        }
        if (null == o) {
            o = "leaf-segment-test";
        }
        Long id = http 方法访问 /api/segment/get/{key} 或者 /api/snowflake/get/{key} 得到id;
        return id;
    }

}

4 总结:

  • leaf 的分段id 通过leaf_alloc 中biz_tag作为业务分隔,使用max_id和step 来每次获取一段int 类型的id值,并且使用双buffer 的方式保证高效性和解决id服务短暂不可用的问题;
  • leaf 的雪花算法通过向zookeeper 注册持久有序的节点,依次来作为workId 机器位的获取,通过ip+port 作为key ,来判断是否相同服务。

美团leaf 的 git 参考地址:git clone git@github.com:Meituan-Dianping/Leaf.git

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/559221.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

5。STM32裸机开发(5)

嵌入式软件开发学习过程记录&#xff0c;本部分结合本人的学习经验撰写&#xff0c;系统描述各类基础例程的程序撰写逻辑。构建裸机开发的思维&#xff0c;为RTOS做铺垫&#xff08;本部分基于库函数版实现&#xff09;&#xff0c;如有不足之处&#xff0c;敬请批评指正。 &…

二本4年测试经验,3面阿里艰苦经历(定薪25K),上岸那天我哭了...

前言 4月准备跳槽&#xff0c;先后面试了各大小公司&#xff0c;拿了一些小offer&#xff0c;面试的公司大部分都能过&#xff0c;但是做人总是要用梦想吧&#xff0c;没有梦想和咸鱼有什么区别&#xff0c;最终把目标放在了阿里&#xff0c;准备了大概3个月的时间&#xff0c…

mysql45讲笔记

不一定要都学&#xff0c;有些感觉用不到&#xff0c;有选择的学&#xff01;&#xff01;&#xff01; 文章目录 mysql45讲1.mysql基础架构2.mysql日志系统3.事务隔离4.索引类型1.哈希表2.有序数组3.二叉搜索树4.B 树 5.索引重点概念覆盖索引索引下推最左前缀原则 6.全局锁表级…

ERP系统是什么?ERP实施顾问怎么做?

ERP实施顾问怎么做&#xff1f; 首先想要从事相关行业&#xff0c;必须先了解什么是ERP&#xff0c;ERP系统功能模块是怎样的&#xff0c;而后才能进行ERP实施顾问的工作。 一、ERP是什么 ERP系统主要是干什么的&#xff1f;ERP系统&#xff0c;简单理解就是一套记账、做账软…

“全球金融科技大会——中国金融业开源技术应用与发展论坛”在北京举行

3月28日&#xff0c;“全球金融科技大会——中国金融业开源技术应用与发展论坛”在北京新动力金融科技中心举行。 会议现场 人民银行科技司二级巡视员杨富玉&#xff0c;开放原子开源基金会理事长孙文龙&#xff0c;中国金电党委书记、董事长周逢民为大会致辞。北京市西城区区…

(转载)MATLAB智能算法30个案例分析(3)——基于遗传算法的BP神经网络优化算法

1 理论基础 1.1 BP神经网络概述 BP网络是一类多层的前馈神经网络。它的名字源于在网络训练的过程中&#xff0c;调整网络的权值的算法是误差的反向传播的学习算法&#xff0c;即为BP学习算法。BP算法是Rumelhart等人在1986年提出来的。由于它的结构简单&#xff0c;可调整的…

docker+redis哨兵模式(一主二从三哨兵)- docker-compose

一、docker-compose 安装&#xff1a; sudo apt-get update #安装最新的docke-ce sudo apt-get install docker-ce # 下载最新的docker-compose curl -L https://github.com/docker/compose/releases/download/1.25.0-rc4/docker-compose-uname -s-uname -m -o /usr/local…

面试字节,过关斩将直接干到 3 面,结果被吊打了?

人人都有大厂梦&#xff0c;对于软件测试员来说&#xff0c;BAT 为首的一线互联网公司肯定是自己的心仪对象&#xff0c;毕竟能到这些大厂工作&#xff0c;不仅薪资高待遇好&#xff0c;而且能力技术都能够得到提升&#xff0c;最关键的是还能够给自己镀上一层金&#xff0c;让…

网络通信概述 -了解网络编程,什么是ip和端口,url

网络&#xff1a;网络就是一种辅助双方或者多方能够连接到一起的工具。 左&#xff1a;单机游戏&#xff08;无网络&#xff09; 右&#xff1a;网络游戏 网络编程&#xff1a;网络编程就是&#xff0c;让在不同的电脑上的软件能够进行数据传递&#xff0c;即进程之间的通信。…

一名8年测试工程师,因为偷偷接私活被····

接私活 对程序员这个圈子来说是一个既公开又隐私的话题&#xff0c;不说全部&#xff0c;应该大多数程序员都有过想要接私活的想法&#xff0c;当然&#xff0c;也有部分得道成仙的不主张接私活。但是很少有人在公开场合讨论私活的问题&#xff0c;似乎都在避嫌。就跟有人下班后…

【WAF绕过】姿势总结(一)

【WAF绕过】姿势总结&#xff08;一&#xff09; 方法 Payload 编码 1、进行url编码&#xff08;少数waf不会进行URL解码,部分waf进行一次url解码>可对payload进行二次url编码&#xff09; 2、Unicode编码&#xff1a;单引号 %u0027、%u02b9、%u02bc 3、部分十六进制编…

Python可视化神器Seaborn入门系列——kdeplot

Seaborn是基于matplotlib的Python可视化库。 它提供了一个高级界面来绘制有吸引力的统计图形。Seaborn其实是在matplotlib的基础上进行了更高级的API封装&#xff0c;从而使得作图更加容易&#xff0c;不需要经过大量的调整就能使你的图变得精致。但应强调的是&#xff0c;应该…

ChatGPT 火爆全球,我们能抓住的下一个风口在哪?

中国互联网行业正面临着巨大的压力和挑战&#xff0c;但也孕育着新的发展机遇。当下正值ChatGPT火爆&#xff0c;整个互联网行业充满了机遇和挑战&#xff0c;身处其中的我们能抓住什么呢&#xff1f; 思你所思&#xff0c;帮大家整理出了五大风口&#xff01;希望对大家有所帮…

html SpeechSynthesis文字转语音

web 页面使用speechSynthesis实现文字转语音 网页语音 API 的SpeechSynthesis 接口是语音服务的控制接口&#xff1b;它可以用于获取设备上关于可用的合成声音的信息&#xff0c;开始、暂停语音&#xff0c;或除此之外的其他命令。 属性 SpeechSynthesis 也从它的父接口继承属…

腾讯云服务器选择购买流程(一步步详细配置)

腾讯云服务器购买流程直接在官方活动上选择比较合适&#xff0c;在云服务器CVM或轻量应用服务器页面自定义购买费用比较贵&#xff0c;但是自定义购买云服务器CPU内存带宽配置选择范围广&#xff0c;活动上购买只能选择固定的活动机&#xff0c;选择范围窄&#xff0c;但是云服…

数据结构 -- 队列

1、Queue队列 先进先出 2、双端队列 --- Deque Deque的实现类是LinkedList,ArrayDeque,LinkedBlockingDeque。 ArrayDeque底层实现是数组&#xff0c;LinkedList底层实现是链表。 双端队列可以作为普通队列使用&#xff0c;也可以作为栈使用。Java官方推荐使用Deque替代Stac…

【flask + sqlalchemy】连接clickhouse数据库的踩的坑,在这里记录一下

文章目录 前言1. 发现问题2. 复盘2.1 上面试一次错误的问题记录2.2 flask使用clickhouse2.2.1 配置2.2.2 orm2.3 如何插入数据 前言 使用clickhouse有一段时间了&#xff0c;现在要重构一个项目&#xff0c;重度依赖clickhouse&#xff0c;现在终于理顺了&#xff0c;记录一下…

数据库管理-第七十七期 再探分布式(20230523)

数据库管理 2023-05-23 第七十七期 再探分布式1 单机分布式2 分布式改造3 尝试改造一个订单系统3.1 表类型和分片键选择3.2 扩展分片3.3 业务扩展 总结 第七十七期 再探分布式 上一次系统探讨分布式数据库还是在第三十六期&#xff0c;经过大半年的“进步”加上中间参加了不少…

Linux启动过程的问题解决

文章目录 Linux启动过程的问题解决忘记root密码的解决因文件系统错误而无法启动 Linux启动过程的问题解决 当我们在使用Linux时&#xff0c;可能会因为某些设置或突然断电等原因导致文件系统出现错误&#xff0c;从而导致Linux无法正常启动。但这并不意味着我们需要重新安装系…

ASEMI代理长电可控硅MAC97A8图片,MAC97A8大小

编辑-Z 长电可控硅MAC97A8参数&#xff1a; 型号&#xff1a;MAC97A8 VDRM/VRRM&#xff1a;600V IT(RMS)&#xff1a;1A ITSM&#xff1a;8A 栅极电流&#xff08;峰值&#xff09;&#xff1a;1A 栅极电压&#xff08;峰值&#xff09;&#xff1a;5V 栅极功率&#…