# Snowflake ID 雪花算法ID

雪花 ID(Snowflake ID)是一个用于**分布式系统**中生成唯一 ID 的算法，由 Twitter 公司提出。它的设计目标是在分布式环境下高效地生成全局唯一的 ID，具有一定的有序性。

##### 所以这就很容易回答为什么要使用雪花 ID 替代数据库自增 ID的问题了
数据库自增 ID 只适用于单机环境，但如果是分布式环境，是将数据库进行分库、分表或数据库分片等操作时，那么数据库自增 ID 就有问题了。


<LinkCard
  title="分布式场景下使用雪花算法生成ID"
  description="ID生成服务多节点部署,生成重复ID如何解决?"
  href="/software-engineer/distributed/snowflake-work-id"
/>

##### 另一个问题: 使用 UUID 替代雪花 ID 可以吗？
如果单从唯一性来考虑的话，那么 UUID 和雪花 ID 的效果是一致的，二者都能保证分布式系统下的数据唯一性，但是即使这样，也不建议使用UUID,因为：
- 可读性问题：UUID内容很长，但没有业务含义，就是一堆看不懂的“乱序字母”。
- 性能问题：UUID是字符串类型，而字符串类型在数据库的查询中效率很低。

### 什么是雪花算法ID
##### 雪花ID结构
符号位 + 时间戳 + 机器ID + 序列号

- 符号位：最高位是符号位，始终为 0，1 表示负数，0 表示正数，ID 都是正整数，所以固定为 0。
- 时间戳：由 41 位组成，精确到毫秒级。可以使用该 41 位表示的时间戳来表示的时间可以使用 69 年。
- 机器ID：由 10 位组成，用于表示机器节点的唯一标识符。在同一毫秒内，不同的节点生成的 ID 会有所不同。
- 序列号：由 12 位组成，用于标识同一毫秒内生成的不同 ID 序列。在同一毫秒内，可以生成 4096 个不同的 ID。

一共**64**位数字

### 雪花算法问题
时间回拨问题：雪花算法生成的 ID 依赖于系统的时间戳，要求系统的时钟必须是单调递增的。如果系统的时钟发生回拨，可能导致生成的 ID 重复。时间回拨是指系统的时钟在某个时间点之后突然往回走(人为设置)，即出现了时间上的逆流情况

节点 ID 依赖问题：雪花算法需要为每个节点分配唯一的节点 ID 来保证生成的 ID 的全局唯一性。节点 ID 的分配需要有一定的管理和调度，特别是在动态扩容或缩容时，节点 ID 的管理可能较为复杂

##### 如何解决时间回拨问题
再维护一个本地时钟缓存，用于记录当前时间戳。这个本地时钟会定期与系统时钟进行同步，如果检测到系统时钟往前走了(出现了时钟回拨)，则将本地时钟调整为系统时钟。

具体实现可以看[百度的UidGenerator](https://github.com/baidu/uid-generator),百度在实现上, UidGenerator通过借用未来时间来解决sequence天然存在的并发限制; 采用RingBuffer来缓存已生成的UID, 并行化UID的生产和消费, 同时对CacheLine补齐，避免了由RingBuffer带来的硬件级「伪共享」问题. 最终单机QPS可达600万。详情参见[此链接](https://github.com/baidu/uid-generator/blob/master/README.zh_cn.md)