一、分布式系统的id 生成
分布式id 需要保证全局唯一,在此基础上 尽可能的保证有序,语义性。
有序性是为了匹配mysql 总innodb引擎的 数据存储结构 语义性是便于查找问题,例如从id 中可以辨识出业务类型,时间等信息。
二、UUID 分析
UUID 是一种过去比较流流行的分布式id 生成方案,使用方式简单,Mybatis-plus 内置了UUID 主键生成器。
UUID 可以保证唯一性,但是没有顺序,更没有语义含义。
在分布式系统中 UUID 虽然可以使用,但是影响了mysql 数据写入性能。
这个已经不推荐使用了。
三、Snowflake
Twitter 早期开源了Snowflake 的相关方案 是目前应用相对比较广泛的一种方式。
MongoDB 的ObjectId
微信的seqsvr
具体实现每种方案有自己的逻辑,但是本质相同
Snowflake 可以保证唯一性,还能保证顺序,另外具备一定的语义性。
3.1Snowflake 的注意点
1 时间变化
Snowflake 依赖于时间计算,所以你需要保证你的分布式集群机器的是时间一直,否则一定概率会出现重复的id.
那么怎么保证所有的机器时间一致呢,这似乎是一个操作系统层次的问题
推荐一篇论文
Lamport 《Time,Clocks,and the Ording of Events in Distributed System》
Twitter 在文档中建议开启NTP
另外一个国内容易忽略的 是冬时令 切换。
冬时令
当时钟拨慢一个小时,也一定程度会出现重复id
2 id 的可预测性
在安全领域,如果黑客能预测或者伪造id 的时候 ,风险便会暴露,例如 生成token的时候,
Erlang 的版本 的flake基于MAC 地址计算,信息也比较敏感。
3时间位数的限制
一些Snowflake 的时间位数有限制,会在有限的时间内耗尽。
时间戳会一直增加,即使一段时间内没有数据进入,该区间的值也不可用了。
不过这一点可以通过自己实现Snowflake 来实现,根据业务实际生产可预测的未来id。
4 Linux 时间漂移
这个问题类似于 时间变化
linux系统有两个时钟:一个是由主板电池驱动的“Real Time Clock”也叫做RTC或者叫CMOS时钟,硬件时钟。当操作系统关机的时候,用这个来记录时间,但是对于运行的系统是不用这个时间的。另一个时间是 “System clock”也叫内核时钟或者软件时钟,是由软件根据时间中断来进行计数的,内核时钟在系统关机的情况下是不存在的,所以,当操作系统启动的时候,内核时 钟是要读取RTC时间来进行时间同步(有些情况下,内核时钟也可以通过ntp服务器来读取时间)
这两个时钟通常会有一些误差,所以长时间可以导致 这两个时钟偏离的比较多,最简单的保持两个时间同步的方法是用软件测出他们之间的误差率,然后用软件进行修正。在每次重新启动系统的时候,系统都会用 hwclock命令对时间进行同步。如果内核时钟在每一个时间中断都快或者慢的话,可以用adjtimex命令进行调整,使得RTC和内核时间走的快慢一 致。
四、业务系统的id 检测
简单的理解就是 业务系统拿到id 之后不要着急用,在业务逻辑进行检测一下 是够有重复的id
如果有则丢弃。
这种严谨的逻辑 可以保证id唯一,但是同时增加系统的复杂性,这个大家可以根据自己的业务实际考量。
|