learn.lianglianglee.com/文章/分布式唯一 ID 解析.md.html
2022-05-11 18:52:13 +08:00

1763 lines
34 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<!-- saved from url=(0046)https://kaiiiz.github.io/hexo-theme-book-demo/ -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no">
<link rel="icon" href="/static/favicon.png">
<title>分布式唯一 ID 解析.md.html</title>
<!-- Spectre.css framework -->
<link rel="stylesheet" href="/static/index.css">
<!-- theme css & js -->
<meta name="generator" content="Hexo 4.2.0">
</head>
<body>
<div class="book-container">
<div class="book-sidebar">
<div class="book-brand">
<a href="/">
<img src="/static/favicon.png">
<span>技术文章摘抄</span>
</a>
</div>
<div class="book-menu uncollapsible">
<ul class="uncollapsible">
<li><a href="/" class="current-tab">首页</a></li>
</ul>
<ul class="uncollapsible">
<li><a href="../">上一级</a></li>
</ul>
<ul class="uncollapsible">
<li>
<a href="/文章/AQS 万字图文全面解析.md">AQS 万字图文全面解析.md.html</a>
</li>
<li>
<a href="/文章/Docker 镜像构建原理及源码分析.md">Docker 镜像构建原理及源码分析.md.html</a>
</li>
<li>
<a href="/文章/ElasticSearch 小白从入门到精通.md">ElasticSearch 小白从入门到精通.md.html</a>
</li>
<li>
<a href="/文章/JVM CPU Profiler技术原理及源码深度解析.md">JVM CPU Profiler技术原理及源码深度解析.md.html</a>
</li>
<li>
<a href="/文章/JVM 垃圾收集器.md">JVM 垃圾收集器.md.html</a>
</li>
<li>
<a href="/文章/JVM 面试的 30 个知识点.md">JVM 面试的 30 个知识点.md.html</a>
</li>
<li>
<a href="/文章/Java IO 体系、线程模型大总结.md">Java IO 体系、线程模型大总结.md.html</a>
</li>
<li>
<a href="/文章/Java NIO浅析.md">Java NIO浅析.md.html</a>
</li>
<li>
<a href="/文章/Java 面试题集锦(网络篇).md">Java 面试题集锦(网络篇).md.html</a>
</li>
<li>
<a href="/文章/Java-直接内存 DirectMemory 详解.md">Java-直接内存 DirectMemory 详解.md.html</a>
</li>
<li>
<a href="/文章/Java中9种常见的CMS GC问题分析与解决.md">Java中9种常见的CMS GC问题分析与解决.md.html</a>
</li>
<li>
<a href="/文章/Java中9种常见的CMS GC问题分析与解决.md">Java中9种常见的CMS GC问题分析与解决.md.html</a>
</li>
<li>
<a href="/文章/Java中的SPI.md">Java中的SPI.md.html</a>
</li>
<li>
<a href="/文章/Java中的ThreadLocal.md">Java中的ThreadLocal.md.html</a>
</li>
<li>
<a href="/文章/Java线程池实现原理及其在美团业务中的实践.md">Java线程池实现原理及其在美团业务中的实践.md.html</a>
</li>
<li>
<a href="/文章/Java魔法类Unsafe应用解析.md">Java魔法类Unsafe应用解析.md.html</a>
</li>
<li>
<a href="/文章/Kafka 源码阅读笔记.md">Kafka 源码阅读笔记.md.html</a>
</li>
<li>
<a href="/文章/Kafka、ActiveMQ、RabbitMQ、RocketMQ 区别以及高可用原理.md">Kafka、ActiveMQ、RabbitMQ、RocketMQ 区别以及高可用原理.md.html</a>
</li>
<li>
<a href="/文章/MySQL · 引擎特性 · InnoDB Buffer Pool.md">MySQL · 引擎特性 · InnoDB Buffer Pool.md.html</a>
</li>
<li>
<a href="/文章/MySQL · 引擎特性 · InnoDB IO子系统.md">MySQL · 引擎特性 · InnoDB IO子系统.md.html</a>
</li>
<li>
<a href="/文章/MySQL · 引擎特性 · InnoDB 事务系统.md">MySQL · 引擎特性 · InnoDB 事务系统.md.html</a>
</li>
<li>
<a href="/文章/MySQL · 引擎特性 · InnoDB 同步机制.md">MySQL · 引擎特性 · InnoDB 同步机制.md.html</a>
</li>
<li>
<a href="/文章/MySQL · 引擎特性 · InnoDB 数据页解析.md">MySQL · 引擎特性 · InnoDB 数据页解析.md.html</a>
</li>
<li>
<a href="/文章/MySQL · 引擎特性 · InnoDB崩溃恢复.md">MySQL · 引擎特性 · InnoDB崩溃恢复.md.html</a>
</li>
<li>
<a href="/文章/MySQL · 引擎特性 · 临时表那些事儿.md">MySQL · 引擎特性 · 临时表那些事儿.md.html</a>
</li>
<li>
<a href="/文章/MySQL 主从复制 半同步复制.md">MySQL 主从复制 半同步复制.md.html</a>
</li>
<li>
<a href="/文章/MySQL 主从复制 基于GTID复制.md">MySQL 主从复制 基于GTID复制.md.html</a>
</li>
<li>
<a href="/文章/MySQL 主从复制.md">MySQL 主从复制.md.html</a>
</li>
<li>
<a href="/文章/MySQL 事务日志(redo log和undo log).md">MySQL 事务日志(redo log和undo log).md.html</a>
</li>
<li>
<a href="/文章/MySQL 亿级别数据迁移实战代码分享.md">MySQL 亿级别数据迁移实战代码分享.md.html</a>
</li>
<li>
<a href="/文章/MySQL 从一条数据说起-InnoDB行存储数据结构.md">MySQL 从一条数据说起-InnoDB行存储数据结构.md.html</a>
</li>
<li>
<a href="/文章/MySQL 地基基础:事务和锁的面纱.md">MySQL 地基基础:事务和锁的面纱.md.html</a>
</li>
<li>
<a href="/文章/MySQL 地基基础:数据字典.md">MySQL 地基基础:数据字典.md.html</a>
</li>
<li>
<a href="/文章/MySQL 地基基础:数据库字符集.md">MySQL 地基基础:数据库字符集.md.html</a>
</li>
<li>
<a href="/文章/MySQL 性能优化:碎片整理.md">MySQL 性能优化:碎片整理.md.html</a>
</li>
<li>
<a href="/文章/MySQL 故障诊断:一个 ALTER TALBE 执行了很久,你慌不慌?.md">MySQL 故障诊断:一个 ALTER TALBE 执行了很久,你慌不慌?.md.html</a>
</li>
<li>
<a href="/文章/MySQL 故障诊断:如何在日志中轻松定位大事务.md">MySQL 故障诊断:如何在日志中轻松定位大事务.md.html</a>
</li>
<li>
<a href="/文章/MySQL 故障诊断:教你快速定位加锁的 SQL.md">MySQL 故障诊断:教你快速定位加锁的 SQL.md.html</a>
</li>
<li>
<a href="/文章/MySQL 日志详解.md">MySQL 日志详解.md.html</a>
</li>
<li>
<a href="/文章/MySQL 的半同步是什么?.md">MySQL 的半同步是什么?.md.html</a>
</li>
<li>
<a href="/文章/MySQL中的事务和MVCC.md">MySQL中的事务和MVCC.md.html</a>
</li>
<li>
<a href="/文章/MySQL事务_事务隔离级别详解.md">MySQL事务_事务隔离级别详解.md.html</a>
</li>
<li>
<a href="/文章/MySQL优化优化 select count().md">MySQL优化优化 select count().md.html</a>
</li>
<li>
<a href="/文章/MySQL共享锁、排他锁、悲观锁、乐观锁.md">MySQL共享锁、排他锁、悲观锁、乐观锁.md.html</a>
</li>
<li>
<a href="/文章/MySQL的MVCC多版本并发控制.md">MySQL的MVCC多版本并发控制.md.html</a>
</li>
<li>
<a href="/文章/QingStor 对象存储架构设计及最佳实践.md">QingStor 对象存储架构设计及最佳实践.md.html</a>
</li>
<li>
<a href="/文章/RocketMQ 面试题集锦.md">RocketMQ 面试题集锦.md.html</a>
</li>
<li>
<a href="/文章/SnowFlake 雪花算法生成分布式 ID.md">SnowFlake 雪花算法生成分布式 ID.md.html</a>
</li>
<li>
<a href="/文章/Spring Boot 2.x 结合 k8s 实现分布式微服务架构.md">Spring Boot 2.x 结合 k8s 实现分布式微服务架构.md.html</a>
</li>
<li>
<a href="/文章/Spring Boot 教程:如何开发一个 starter.md">Spring Boot 教程:如何开发一个 starter.md.html</a>
</li>
<li>
<a href="/文章/Spring MVC 原理.md">Spring MVC 原理.md.html</a>
</li>
<li>
<a href="/文章/Spring MyBatis和Spring整合的奥秘.md">Spring MyBatis和Spring整合的奥秘.md.html</a>
</li>
<li>
<a href="/文章/Spring 帮助你更好的理解Spring循环依赖.md">Spring 帮助你更好的理解Spring循环依赖.md.html</a>
</li>
<li>
<a href="/文章/Spring 循环依赖及解决方式.md">Spring 循环依赖及解决方式.md.html</a>
</li>
<li>
<a href="/文章/Spring中眼花缭乱的BeanDefinition.md">Spring中眼花缭乱的BeanDefinition.md.html</a>
</li>
<li>
<a href="/文章/Vert.x 基础入门.md">Vert.x 基础入门.md.html</a>
</li>
<li>
<a href="/文章/eBay 的 Elasticsearch 性能调优实践.md">eBay 的 Elasticsearch 性能调优实践.md.html</a>
</li>
<li>
<a href="/文章/不可不说的Java“锁”事.md">不可不说的Java“锁”事.md.html</a>
</li>
<li>
<a href="/文章/互联网并发限流实战.md">互联网并发限流实战.md.html</a>
</li>
<li>
<a href="/文章/从ReentrantLock的实现看AQS的原理及应用.md">从ReentrantLock的实现看AQS的原理及应用.md.html</a>
</li>
<li>
<a href="/文章/从SpringCloud开始聊微服务架构.md">从SpringCloud开始聊微服务架构.md.html</a>
</li>
<li>
<a href="/文章/全面了解 JDK 线程池实现原理.md">全面了解 JDK 线程池实现原理.md.html</a>
</li>
<li>
<a href="/文章/分布式一致性理论与算法.md">分布式一致性理论与算法.md.html</a>
</li>
<li>
<a href="/文章/分布式一致性算法 Raft.md">分布式一致性算法 Raft.md.html</a>
</li>
<li>
<a class="current-tab" href="/文章/分布式唯一 ID 解析.md">分布式唯一 ID 解析.md.html</a>
</li>
<li>
<a href="/文章/分布式链路追踪:集群管理设计.md">分布式链路追踪:集群管理设计.md.html</a>
</li>
<li>
<a href="/文章/动态代理种类及原理,你知道多少?.md">动态代理种类及原理,你知道多少?.md.html</a>
</li>
<li>
<a href="/文章/响应式架构与 RxJava 在有赞零售的实践.md">响应式架构与 RxJava 在有赞零售的实践.md.html</a>
</li>
<li>
<a href="/文章/大数据算法——布隆过滤器.md">大数据算法——布隆过滤器.md.html</a>
</li>
<li>
<a href="/文章/如何优雅地记录操作日志?.md">如何优雅地记录操作日志?.md.html</a>
</li>
<li>
<a href="/文章/如何设计一个亿级消息量的 IM 系统.md">如何设计一个亿级消息量的 IM 系统.md.html</a>
</li>
<li>
<a href="/文章/异步网络模型.md">异步网络模型.md.html</a>
</li>
<li>
<a href="/文章/当我们在讨论CQRS时我们在讨论些神马.md">当我们在讨论CQRS时我们在讨论些神马.md.html</a>
</li>
<li>
<a href="/文章/彻底理解 MySQL 的索引机制.md">彻底理解 MySQL 的索引机制.md.html</a>
</li>
<li>
<a href="/文章/最全的 116 道 Redis 面试题解答.md">最全的 116 道 Redis 面试题解答.md.html</a>
</li>
<li>
<a href="/文章/有赞权限系统(SAM).md">有赞权限系统(SAM).md.html</a>
</li>
<li>
<a href="/文章/有赞零售中台建设方法的探索与实践.md">有赞零售中台建设方法的探索与实践.md.html</a>
</li>
<li>
<a href="/文章/服务注册与发现原理剖析Eureka、Zookeeper、Nacos.md">服务注册与发现原理剖析Eureka、Zookeeper、Nacos.md.html</a>
</li>
<li>
<a href="/文章/深入浅出Cache.md">深入浅出Cache.md.html</a>
</li>
<li>
<a href="/文章/深入理解 MySQL 底层实现.md">深入理解 MySQL 底层实现.md.html</a>
</li>
<li>
<a href="/文章/漫画讲解 git rebase VS git merge.md">漫画讲解 git rebase VS git merge.md.html</a>
</li>
<li>
<a href="/文章/生成浏览器唯一稳定 ID 的探索.md">生成浏览器唯一稳定 ID 的探索.md.html</a>
</li>
<li>
<a href="/文章/缓存 如何保证缓存与数据库的双写一致性?.md">缓存 如何保证缓存与数据库的双写一致性?.md.html</a>
</li>
<li>
<a href="/文章/网易严选怎么做全链路监控的?.md">网易严选怎么做全链路监控的?.md.html</a>
</li>
<li>
<a href="/文章/美团万亿级 KV 存储架构与实践.md">美团万亿级 KV 存储架构与实践.md.html</a>
</li>
<li>
<a href="/文章/美团点评Kubernetes集群管理实践.md">美团点评Kubernetes集群管理实践.md.html</a>
</li>
<li>
<a href="/文章/美团百亿规模API网关服务Shepherd的设计与实现.md">美团百亿规模API网关服务Shepherd的设计与实现.md.html</a>
</li>
<li>
<a href="/文章/解读《阿里巴巴 Java 开发手册》背后的思考.md">解读《阿里巴巴 Java 开发手册》背后的思考.md.html</a>
</li>
<li>
<a href="/文章/认识 MySQL 和 Redis 的数据一致性问题.md">认识 MySQL 和 Redis 的数据一致性问题.md.html</a>
</li>
<li>
<a href="/文章/进阶Dockerfile 高阶使用指南及镜像优化.md">进阶Dockerfile 高阶使用指南及镜像优化.md.html</a>
</li>
<li>
<a href="/文章/铁总在用的高性能分布式缓存计算框架 Geode.md">铁总在用的高性能分布式缓存计算框架 Geode.md.html</a>
</li>
<li>
<a href="/文章/阿里云PolarDB及其共享存储PolarFS技术实现分析.md">阿里云PolarDB及其共享存储PolarFS技术实现分析.md.html</a>
</li>
<li>
<a href="/文章/阿里云PolarDB及其共享存储PolarFS技术实现分析.md">阿里云PolarDB及其共享存储PolarFS技术实现分析.md.html</a>
</li>
<li>
<a href="/文章/面试最常被问的 Java 后端题.md">面试最常被问的 Java 后端题.md.html</a>
</li>
<li>
<a href="/文章/领域驱动设计在互联网业务开发中的实践.md">领域驱动设计在互联网业务开发中的实践.md.html</a>
</li>
<li>
<a href="/文章/领域驱动设计的菱形对称架构.md">领域驱动设计的菱形对称架构.md.html</a>
</li>
<li>
<a href="/文章/高效构建 Docker 镜像的最佳实践.md">高效构建 Docker 镜像的最佳实践.md.html</a>
</li>
</ul>
</div>
</div>
<div class="sidebar-toggle" onclick="sidebar_toggle()" onmouseover="add_inner()" onmouseleave="remove_inner()">
<div class="sidebar-toggle-inner"></div>
</div>
<script>
function add_inner() {
let inner = document.querySelector('.sidebar-toggle-inner')
inner.classList.add('show')
}
function remove_inner() {
let inner = document.querySelector('.sidebar-toggle-inner')
inner.classList.remove('show')
}
function sidebar_toggle() {
let sidebar_toggle = document.querySelector('.sidebar-toggle')
let sidebar = document.querySelector('.book-sidebar')
let content = document.querySelector('.off-canvas-content')
if (sidebar_toggle.classList.contains('extend')) { // show
sidebar_toggle.classList.remove('extend')
sidebar.classList.remove('hide')
content.classList.remove('extend')
} else { // hide
sidebar_toggle.classList.add('extend')
sidebar.classList.add('hide')
content.classList.add('extend')
}
}
function open_sidebar() {
let sidebar = document.querySelector('.book-sidebar')
let overlay = document.querySelector('.off-canvas-overlay')
sidebar.classList.add('show')
overlay.classList.add('show')
}
function hide_canvas() {
let sidebar = document.querySelector('.book-sidebar')
let overlay = document.querySelector('.off-canvas-overlay')
sidebar.classList.remove('show')
overlay.classList.remove('show')
}
</script>
<div class="off-canvas-content">
<div class="columns">
<div class="column col-12 col-lg-12">
<div class="book-navbar">
<!-- For Responsive Layout -->
<header class="navbar">
<section class="navbar-section">
<a onclick="open_sidebar()">
<i class="icon icon-menu"></i>
</a>
</section>
</header>
</div>
<div class="book-content" style="max-width: 960px; margin: 0 auto;
overflow-x: auto;
overflow-y: hidden;">
<div class="book-post">
<p id="tip" align="center"></p>
<div><h1>分布式唯一 ID 解析</h1>
<h1>业界常见解决方案</h1>
<h2>UUID</h2>
<p>[uuid](https://en.wikipedia.org/wiki/Universally_unique_identifier#:~:text=A universally unique identifier (UUID,are for practical purposes unique.))</p>
<p>1 个 UUID 是 1 个 16 字节128 位)的数字; 为了方便阅读,通常将 UUID 表示成如下的方式:</p>
<pre><code>123e4567-e89b-12d3-a456-426614174000
</code></pre>
<p>缺点:</p>
<ul>
<li>ID 太长,占用空间较大</li>
<li>索引效率低</li>
<li>不能保证趋势递增,不适合做 DB 主键MySQL 聚簇索引下插入不是顺序的,会导致随机 IO 增多,性能下降)</li>
</ul>
<h2>Snowflake</h2>
<p><img src="assets/7da3ae4242abfa72a421c42c203f60fc.png" alt="img" /></p>
<p>缺点:</p>
<ul>
<li>强依赖机器时间,如果时间回拨 Id 可能会重复</li>
<li>不是严格的趋势递增,极端情况在机器时间不同步的情况下后生成的 Id 可能会小于先生成的 Id即只能在 worker 级别保证递增</li>
<li>服务需要保证 workerId 唯一(如果需要保证严格唯一的话会比较麻烦,简单可以基于服务 IP 跟 Port 来生成,但由于 workerId 只有 10 位,因此 workerId 可能会重复)</li>
</ul>
<h2>Redis 生成 Id</h2>
<p>可以使用 Redis 的原子操作 <code>INCR</code> 或者 <code>INCRBY</code> 来实现</p>
<p>优点:</p>
<ul>
<li>性能较好</li>
<li>Redis 单线程,没有线程安全问题,能保证 ID 趋势递增</li>
</ul>
<p>缺点:</p>
<ul>
<li>如果 Redis 需要迁移的话,需要保证迁移过程中的数据一致性,难度较大</li>
<li>Redis 持久化如果使用 RDB因此 Redis 重启会丢数据,导致 ID 重复</li>
</ul>
<h2>美团 Leaf</h2>
<p>原文:<a href="https://tech.meituan.com/2017/04/21/mt-leaf.html">https://tech.meituan.com/2017/04/21/mt-leaf.html</a></p>
<h3>Leaf Segment</h3>
<p><img src="assets/e580a878ec16acc8f844511714b13ef3.png" alt="img" /></p>
<p>使用 DB 号段保证唯一Leaf Node 启动时或者在号段快用完时会从 DB 重新申请一段号段。</p>
<p>缺点:</p>
<ul>
<li>只能保证在 Leaf Node 级别趋势递增,不能保证全局趋势递增</li>
<li>ID 不够随机,能够泄露发号数量的信息,不太安全</li>
<li>DB 宕机会造成整个系统不可用</li>
</ul>
<h3>Leaf Snowflake</h3>
<p><img src="assets/e8d26bd2d44edc4fceb04946d2aa2fa6.png" alt="img" /></p>
<p>ID 生成方式类似 Snowflake。</p>
<p>workerId 使用 Zookeeper 顺序结点的特性来实现,保证 workerId 唯一。</p>
<p>周期性上报时间给 Zookeeper启动时做时间检验时间回拨则告警。</p>
<h2>微信序列号生成器</h2>
<p>原文:<a href="https://mp.weixin.qq.com/s/JqIJupVKUNuQYIDDxRtfqA">https://mp.weixin.qq.com/s/JqIJupVKUNuQYIDDxRtfqA</a></p>
<p><img src="assets/b6898ae957c5e7e18bb9423e3eb069e9.png" alt="img" /></p>
<p><img src="assets/fa9a638feba86105210f05a5fbe5b332.png" alt="img" /></p>
<p>可以看出,微信序列号生成器是在用户级别趋势递增。像微信这么大的消息量,如果像美团 Leaf Segment 一样在业务级别递增的话,那么序列号生成器肯定会成为性能瓶颈;而且美团 Leaf Segment 并不能保证全局趋势递增,并不能适用 IM Timeline 模型。</p>
<p>优点:</p>
<ul>
<li>Section 级别的并发,大大提高了并发</li>
<li>完美解决了 IM Timeline 模型下需要严格趋势递增 ID 的问题</li>
</ul>
<p>缺点:</p>
<ul>
<li>重客户端,架构复杂,开发维护成本大</li>
</ul>
<h2>百度 UidGenerator</h2>
<p>原文:<a href="https://github.com/baidu/uid-generator/blob/master/README.zh_cn.md">https://github.com/baidu/uid-generator/blob/master/README.zh_cn.md.html</a></p>
<p>基于 Snowflake</p>
<p><img src="assets/4f283011d42f61af16fc6afa62ec6e17.png" alt="img" /></p>
<p>使用 RingBuffer 缓存 UID并通过双 RingBuffer+CacheLine 补齐方式提高并发,解决了伪共享问题</p>
<p><img src="assets/0d12e661cf87691541331a85da5471f5.png" alt="img" /></p>
<p>workerId 由 MySQL 自增 Id 分配。</p>
<p>通过借用未来时间来解决 Sequence 的并发限制,即每秒只能有 8192 个并发,超过则需要使用未来的时间来生成。</p>
<p>时间不是取的机器时间,而是用启动时间自增来实现。</p>
<p>缺点:</p>
<ul>
<li>默认可用时间太少,只有 8.7 年如果加大时间workerId 又太少(因为 workerId 用完就丢弃,目前还没提供复用策略)</li>
<li>如果重启的时候时间回拨,虽然能保证 ID 唯一,但 ID 可能会变小,不是严格的趋势递增</li>
<li>timeBits &amp; workerBits 规则固定,如果不同业务需要不同生成规则需要重新搭建一套</li>
<li>以库的形式提供,使用配置复杂</li>
</ul>
<h2><a href="https://docs.mongodb.com/v3.2/reference/method/ObjectId/">MongoDB ObjectID</a></h2>
<p>原文:<a href="https://docs.mongodb.com/v3.2/reference/method/ObjectId/">https://docs.mongodb.com/v3.2/reference/method/ObjectId/</a></p>
<p><img src="assets/58cca17a55dc6efa621534985d387095.png" alt="img" /></p>
<ul>
<li>1 ~ 4时间戳</li>
<li>5 ~ 7机器 Host Name 的 MD5 值</li>
<li>8 ~ 9进程 Id</li>
<li>10 ~ 12递增计数器</li>
</ul>
<p>缺点:</p>
<ul>
<li>占用存储空间多</li>
<li>不能保证趋势递增</li>
</ul>
<h1>解决分布式唯一 ID 的一个想法</h1>
<p>本方案参考百度 UidGenerator解决了 workerId 无法复用的问题</p>
<p>使用 Snowflake利用 MySQL 自增 Id 分配 workerId并复用 workerId同时利用时间号段保证时间趋势递增</p>
<p>使用 Snowflake64bit 的 Id 设计如下:</p>
<p><img src="assets/ec7292b67ed394620430ebe861dca39c.png" alt="img" /></p>
<p>因此,最多有 2^10 = 1024 个 workerId分配 WorkerId 的 DB Schema 设计如下:</p>
<pre><code class="language-sql">CREATE TABLE IF NOT EXISTS `worker_node_tab`
(
id BIGINT NOT NULL AUTO_INCREMENT COMMENT 'worker id',
ip CHAR(64) NOT NULL COMMENT 'host IP',
port CHAR(64) NOT NULL COMMENT 'host port',
last_timestamp TIMESTAMP NOT NULL COMMENT 'last timestamp',
duration_step TIMESTAMP NOT NULL COMMENT 'duration',
mtime TIMESTAMP NOT NULL COMMENT 'modified time',
ctime TIMESTAMP NOT NULL COMMENT 'created time',
PRIMARY KEY(id)
) COMMENT='WorkerID Assigner for UID Generator',ENGINE = INNODB;
</code></pre>
<p>服务启动流程:</p>
<ol>
<li>往 worker_node_tab 插入自己的 IP&amp;Port 等信息,获取 DB 自增 id设置 workerId = id % 1024</li>
<li>从 worker_node_tab 获取最大的 last_timestamp(max_last_timestamp),并设置 timestamp = max_last_timestamp + duration_step</li>
</ol>
<p>备注:因为百度 UidGenerator workerId 不会重复,因此不用担心 timestamp 重复;我们需要复用 workerId因此必须要保证 timestamp 是趋势递增的</p>
<p>生成 Id 流程:</p>
<ol>
<li>sequence += 1</li>
<li>如果 sequence 还没超过 MAX_SEQUENCE(2^12),则跳到(3)直接生成 Id如果 sequence 大于等于 MAX_SEQUENCE则设置 timestamp += 1, sequence = 0然后跳到(3)生成 Idtimestamp 在本地自增,因此不用担心时间回拨的问题)</li>
<li>生成 IdId = timestamp &lt;&lt; (10 + 12) | workerId &lt;&lt; 12 | sequence</li>
</ol>
<p>duration_step 可以设置为两天(或更长),每隔一天异步到 DB 申请一个时间号段(即设置 DB last_timestamp += duration_step可以做到弱依赖 DB</p>
<h1>参考</h1>
<p>[Universally unique identifier](https://en.wikipedia.org/wiki/Universally_unique_identifier#:~:text=A universally unique identifier (UUID,are for practical purposes unique.))</p>
<p><a href="https://developer.twitter.com/en/docs/basics/twitter-ids">Twitter IDs (snowflake)</a></p>
<p><a href="https://tech.meituan.com/2017/04/21/mt-leaf.html">Leaf——美团点评分布式ID生成系统</a></p>
<p><a href="https://mp.weixin.qq.com/s/JqIJupVKUNuQYIDDxRtfqA">万亿级调用系统:微信序列号生成器架构设计及演变</a></p>
<p><a href="https://github.com/baidu/uid-generator/blob/master/README.zh_cn.md">百度UidGenerator</a></p>
<p><a href="https://docs.mongodb.com/v3.2/reference/method/ObjectId/">MongoDB ObjectID</a></p>
</div>
</div>
<div>
<div style="float: left">
<a href="/文章/分布式一致性算法 Raft.md">上一页</a>
</div>
<div style="float: right">
<a href="/文章/分布式链路追踪:集群管理设计.md">下一页</a>
</div>
</div>
</div>
</div>
</div>
</div>
<a class="off-canvas-overlay" onclick="hide_canvas()"></a>
</div>
<script defer src="https://static.cloudflareinsights.com/beacon.min.js/v652eace1692a40cfa3763df669d7439c1639079717194" integrity="sha512-Gi7xpJR8tSkrpF7aordPZQlW2DLtzUlZcumS8dMQjwDHEnw9I7ZLyiOj/6tZStRBGtGgN6ceN6cMH8z7etPGlw==" data-cf-beacon='{"rayId":"709980452cc98b66","version":"2021.12.0","r":1,"token":"1f5d475227ce4f0089a7cff1ab17c0f5","si":100}' crossorigin="anonymous"></script>
</body>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-NPSEEVD756"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag('js', new Date());
gtag('config', 'G-NPSEEVD756');
var path = window.location.pathname
var cookie = getCookie("lastPath");
console.log(path)
if (path.replace("/", "") === "") {
if (cookie.replace("/", "") !== "") {
console.log(cookie)
document.getElementById("tip").innerHTML = "<a href='" + cookie + "'>跳转到上次进度</a>"
}
} else {
setCookie("lastPath", path)
}
function setCookie(cname, cvalue) {
var d = new Date();
d.setTime(d.getTime() + (180 * 24 * 60 * 60 * 1000));
var expires = "expires=" + d.toGMTString();
document.cookie = cname + "=" + cvalue + "; " + expires + ";path = /";
}
function getCookie(cname) {
var name = cname + "=";
var ca = document.cookie.split(';');
for (var i = 0; i < ca.length; i++) {
var c = ca[i].trim();
if (c.indexOf(name) === 0) return c.substring(name.length, c.length);
}
return "";
}
</script>
</html>