1
0
mirror of synced 2026-02-20 11:57:58 +08:00
Files
SnowFlake-IdGenerator/README.md
2021-04-09 22:00:22 +08:00

267 lines
14 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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.
# 雪花算法里最好用的主键ID新算法
## 💎 技术支持
开源地址1https://github.com/yitter/idgenerator
开源地址2https://gitee.com/yitter/idgenerator
QQ群646049993
## 为什么用雪花ID
❄ 因为大厂都在用,推特、百度、美团、滴滴等等。
❄ 雪花ID是走向分布式架构的垫脚石如果只会Guid和数据库自增怎敢说会分布式系统架构。
❄ 雪花ID适合小项目、大项目、超级大项目。
## 💎 本算法介绍
<font color="#11aaff" size="5">❄</font> 这是一个优化的雪花算法雪花漂移生成的ID更短、速度更快。
<font color="#11aaff" size="5">❄</font> 原生支持 C#/Java/Go/Rust/C 等语言,并提供 PHP、Python、Node.js、Ruby 等语言多线程安全调用库(FFI)。
<font color="#11aaff" size="5">❄</font> 支持 k8s 等容器环境自动扩容(自动注册 WorkerId
<font color="#11aaff" size="5">❄</font> 可在单机或分布式环境中生成唯一ID。
<font color="#11aaff" size="5">❄</font> 这是计算机历史上最全面的雪花ID生成器未来会超越自己。目前还未发现更好的或许你可以😀
## 需求来源
<font color="green" size="5">💧</font> 作为架构设计的你,想要解决数据库主键唯一的问题,特别是在分布式系统多数据库的时候。
<font color="green" size="5">💧</font> 你希望这个主键是用最少的存储空间索引速度更快Select、Insert 和 Update 更迅速。
<font color="green" size="5">💧</font> 你要考虑在分库分表(合库合表)时,主键值可直接使用,并能反映业务时序。
<font color="green" size="5">💧</font> 如果这样的主键值太长,超过前端 js Number 类型最大值,须把 Long 型转换为 String 型,你会觉得有点沮丧。
<font color="green" size="5">💧</font> 尽管 Guid 能自增,但占用空间大,索引速度慢,你也不想用它。
<font color="green" size="5">💧</font> 应用实例可能超过50个每个并发请求可达10W/s。
<font color="green" size="5">💧</font> 在容器环境部署应用(水平扩展、自动扩容)。
<font color="green" size="5">💧</font> 不想依赖 redis 的自增操作。
<font color="green" size="5">💧</font> 你希望系统运行 100 年以上。
## 传统算法问题
❌ 生成的ID太长。
❌ 瞬时并发量不够。
❌ 不能解决时间回拨问题。
❌ 不支持后补生成前序ID。
❌ 可能依赖外部存储系统。
## 新算法特点
<font color="green" size="5">✔</font> 整形数字随时间单调递增不一定连续长度更短用50年都不会超过 js Number类型最大值。默认配置
<font color="green" size="5">✔</font> 速度更快是传统雪花算法的2-5倍0.1秒可生成50万个基于8代低压i7
<font color="green" size="5">✔</font> 支持时间回拨处理。比如服务器时间回拨1秒本算法能自动适应生成临界时间的唯一ID。
<font color="green" size="5">✔</font> 支持手工插入新ID。当业务需要在历史时间生成新ID时用本算法的预留位能生成5000个每秒。
<font color="green" size="5">✔</font> 不依赖任何外部缓存和数据库。k8s环境下自动注册 WorkerId 的动态库依赖 redis
<font color="green" size="5">✔</font> 基础功能,开箱即用,无需配置文件、数据库连接等。
## 性能数据
(参数10位自增序列1000次漂移最大值)
| 连续请求量 | 5K | 5W | 50W |
| ---- | ---- | ---- | ---- |
| 传统雪花算法 | 0.0045s | 0.053s | 0.556s |
| 雪花漂移算法 | 0.0015s | 0.012s | 0.113s |
💍 极致性能500W/s~3000W/s。所有测试数据均基于8代低压i7计算
## 如何处理时间回拨
🔶 当发生系统时间回拨时算法采用过去时序的预留序数生成新的ID。
🔶 回拨生成的ID序号默认靠前也可以调整为靠后。
🔶 允许时间回拨至本算法预设基数(参数可调)。
## 💎 ID组成
* 本算法生成的ID由3部分组成沿用雪花算法定义
* +-------------------------+--------------+----------+
* | 1.相对基础时间的时间差 | 2.WorkerId | 3.序列数 |
* +-------------------------+--------------+----------+
* +-------------------------+---- 6 bits ---+- 6 bits -+
*
* 第1部分时间差是生成ID时的系统时间减去 BaseTime 的总时间差(毫秒单位)。
* 第2部分WorkerId是区分不同机器或不同应用的唯一ID最大值由 WorkerIdBitLength默认6限定。
* 第3部分序列数是每毫秒下的序列数由参数中的 SeqBitLength默认6限定。
## 💎 ID示例
🟣 本算法生成的 ID 是一串整数最多8字节。以下是基于默认配置生成的ID
```
129053495681099 (本算法运行1年)
387750301904971 (运行3年)
646093214093387 (运行5年)
1292658282840139 (运行10年)
9007199254740992 (js Number 最大值)
165399880288699493 (普通雪花算法生成的ID)
```
🟣 本算法生成的 ID 值,是 js Number 最大值的 1%-10%,是普通雪花算法值的千分之一,而计算能力却超过普通雪花算法。
🟣 js Number 类型最大数值9007199254740992本算法在保持并发性能5W+/0.01s和最大64个 WorkerId6bit的同时能用70年才到 js Number Max 值。
### 长度估算
```
💍 每增加 1位 WorkerIdBitLength 或 SeqBitLength生成的ID数字值将会乘以2基础长度可参考前“ID示例”反之则除以2。
```
### 能用多久
🔵 在默认配置下ID可用 71000 年不重复。
🔵 在支持 1024 个工作节点时ID可用 4480 年不重复。
🔵 在支持 4096 个工作节点时ID可用 1120 年不重复。
## 💎 参数设置
<font color="#11aaff" size="5">❄</font> <font color=blue>***WorkerIdBitLength***</font>,机器码位长,决定 WorkerId 的最大值默认值6取值范围 [1, 19],实际上有些语言采用 无符号ushort(uint16) 类型接收该参数所以最大值是16如果是采用有符号short(int16)则最大值为15。
<font color="#11aaff" size="5">❄</font> <font color=blue>***WorkerId***</font>,机器码,**最重要参数**无默认值必须由外部设定默认情况下最大值63理论最大值 2^WorkerIdBitLength-1实际上根据语言的实现不同可能会限定在 65535 或 32767原理同 WorkerIdBitLength 的规则。不同机器或不同应用实例不可相同你可通过应用程序配置该值也可通过调用外部服务获取值。针对自动注册WorkerId需求本算法提供默认实现通过 redis 自动注册 WorkerId 的动态库详见“Tools\AutoRegisterWorkerId”。
<font color="#11aaff" size="5">❄</font> <font color=blue>***SeqBitLength***</font>序列数位长默认值6取值范围 [3, 21]建议不小于4决定每毫秒生成的 ID 个数。规则要求WorkerIdBitLength + SeqBitLength 不超过 22。
<font color="#11aaff" size="5">❄</font> <font color=blue>***MinSeqNumber***</font>最小序列数默认值5取值范围 [5, MaxSeqNumber]每毫秒的前5个序列数对应编号0-4是保留位其中1-4是时间回拨相应预留位0是手工新值预留位。
<font color="#11aaff" size="5">❄</font> <font color=blue>***MaxSeqNumber***</font>,最大序列数,设置范围 [MinSeqNumber, 2^SeqBitLength-1]默认值0表示最大序列数取最大值2^SeqBitLength-1不为0时用该设置值为最大序列数一般无需设置最大序列数除非多机共享WorkerId分段生成ID此时还要正确设置最小序列数
## 💎 常规集成
1⃣ 用单例模式调用。外部集成方使用更多的实例并行调用本算法不会增加ID产出效能因为本算法采用单线程模式生成ID。
2⃣ 指定唯一的 WorkerId。必须由外部系统确保 WorkerId 的全局唯一性,并赋值给本算法入口方法。
3⃣ 单机多实例部署时使用不同 WorkerId。并非所有实现都支持跨进程的并发唯一保险起见在同一主机上部署多应用实例时请确保各 WorkerId 唯一。
4⃣ 异常处理。算法会抛出所有 Exception外部系统应 catch 异常并做好应对处理,以免引发更大的系统崩溃。
5⃣ 认真理解 IdGeneratorOptions 的定义,这对集成和使用本算法有帮助。
6⃣ 使用雪花漂移算法。虽然代码里包含了传统雪花算法的定义并且你可以在入口处指定Method=2来启用传统算法但仍建议你使用雪花漂移算法Method=1默认的毕竟它具有更好的伸缩力和更高的性能。
7⃣ 不要修改核心算法。本算法内部参数较多,逻辑较为复杂,在你尚未掌握核心逻辑时,请勿尝试修改核心代码且用于生产环境,除非通过大量细致、科学的测试验证。
## 💎 配置变更
配置变更指是系统运行一段时间后再变更运行参数IdGeneratorOptions选项值请注意
🔴 1.最重要的一条原则是BaseTime **只能往前**(比老值更小、距离现在更远)赋值,原因是往后赋值极大可能产生相同的时间戳。[**不推荐**在系统运行之后调整 BaseTime]
🔴 2.任何时候增加 WorkerIdBitLength 或 SeqBitLength都是可以的但是慎用 “减小”的操作,因为这可能导致在未来某天生成的 ID 与过去老配置时相同。[允许在系统运行之后**增加**任何一个 BitLength 值]
🔴 3.如果必须减小 WorkerIdBitLength 或 SeqBitLength 其中的一项,一定要满足一个条件:新的两个 BitLength 之和要大于 老的值之和。[**不推荐**在运行之后缩小任何一个 BitLength 值]
🔴 4.上述3条规则并未在本算法内做逻辑控制集成方应根据上述规则做好影响评估确认无误后再实施配置变更。
## 自动注册WorkerId
🔍 唯一ID生成器依赖WorkerId当业务服务需要水平无差别复制时就要求它能自动注册全局唯一WorkerId然后才能根据它生产唯一ID。
🔍 本算法提供一个开源动态库go语言实现能在容器 k8s或其它容器化集群 环境下,通过 redis 自动注册 WorkerId。
🔍 通过redis注册WorkerId并不是唯一的方法。你也可以自己开发一个配置中心服务各个应用服务启动时通过配置中心获取唯一 WorkerId。
🔍 当然如果你的服务不需要自动扩展你就不必自动注册WorkerId而是为每个应用手工设定一个唯一值。
动态库下载链接https://gitee.com/yitter/idgenerator/attach_files/662372/download/regworkerid_lib_v1.0.zip
动态库接口定义:
```
// 注册一个 WorkerId会先注销所有本机已注册的记录
// ip: redis 服务器地址
// port: redis 端口
// password: redis 访问密码,可为空字符串“”
// maxWorkerId: 最大 WorkerId
extern __declspec(dllexport) GoInt32 RegisterOne(char* ip, GoInt32 port, char* password, GoInt32 maxWorkerId);
// 注销本机已注册的 WorkerId
extern __declspec(dllexport) void UnRegister();
// 检查本地WorkerId是否有效0-有效,其它-无效)
extern __declspec(dllexport) GoInt32 Validate(GoInt32 workerId);
```
## 已实现的语言
| 语言 | github | gitee |
| ---- | ---- | ---- |
| 🌲 C# | [查看示例][1] | [查看示例][11] |
| 🌲 Java | [查看示例][2] | [查看示例][21] |
| 🌲 Go| [查看示例][3] | [查看示例][31] |
| 🌲 Rust | [查看示例][4] | [查看示例][41] |
| 🌲 C | [查看示例][5] | [查看示例][51] |
| 🌲 C (PHP扩展) | [查看示例][7] | [查看示例][71] |
| 🌲 V | [查看示例][6] | [查看示例][61] |
| 🌲 D | [查看示例][72] | [查看示例][73] |
## 为什么不用大厂的?
❄ 首先,大厂们不但自己用,而且开源:[百度][81] | [美团][82] | [滴滴][83] | [雪花ID鼻祖-推特][80]。
❄ 然而,大厂的雪花算法分为“经典算法”和“号段算法”两种,其中“号段算法”依赖网络或外部存储系统,不适合“非大厂”。
❄ 至于其“经典算法”在“ID长度和生成性能”方面未做过优化而这正式本算法——雪花漂移算法的核心所在。
[1]: https://github.com/yitter/idgenerator/tree/master/%23.NET
[2]: https://github.com/yitter/idgenerator/tree/master/Java
[3]: https://github.com/yitter/idgenerator/tree/master/Go
[4]: https://github.com/yitter/idgenerator/tree/master/Rust
[5]: https://github.com/yitter/idgenerator/tree/master/C
[6]: https://github.com/yitter/idgenerator/tree/master/ZeOthers/Vlang
[7]: https://github.com/yitter/idgenerator/tree/master/PHP
[11]: https://gitee.com/yitter/idgenerator/tree/master/%23.NET
[21]: https://gitee.com/yitter/idgenerator/tree/master/Java
[31]: https://gitee.com/yitter/idgenerator/tree/master/Go
[41]: https://gite.com/yitter/idgenerator/tree/master/Rust
[51]: https://gitee.com/yitter/idgenerator/tree/master/C
[61]: https://gitee.com/yitter/idgenerator/tree/master/ZeOthers/Vlang
[71]: https://gitee.com/yitter/idgenerator/tree/master/PHP
[72]: https://github.com/yitter/idgenerator/tree/master/D
[73]: https://gitee.com/yitter/idgenerator/tree/master/D
[80]: https://github.com/twitter-archive/snowflake
[81]: https://github.com/baidu/uid-generator
[82]: https://github.com/Meituan-Dianping/Leaf
[83]: https://github.com/didi/tinyid