登录
注册
开源
企业版
高校版
搜索
帮助中心
使用条款
关于我们
开源
企业版
高校版
私有云
模力方舟
AI 队友
登录
注册
3月21日 深圳|OpenClaw 线下实战沙龙:招聘、资讯、项目协同三大场景实操,VS ZeroClaw 横向对比评测,别再只会装,来现场跑通真实业务!
代码拉取完成,页面将自动刷新
捐赠
捐赠前请先登录
取消
前往登录
扫描微信二维码支付
取消
支付完成
支付提示
将跳转至支付宝完成支付
确定
取消
Watch
不关注
关注所有动态
仅关注版本发行动态
关注但不提醒动态
24
Star
55
Fork
2
Java技术交流
/
Java技术提升库
代码
Issues
56
Pull Requests
0
Wiki
统计
流水线
服务
JavaDoc
PHPDoc
质量分析
Jenkins for Gitee
腾讯云托管
腾讯云 Serverless
悬镜安全
阿里云 SAE
Codeblitz
SBOM
我知道了,不再自动展开
更新失败,请稍后重试!
移除标识
内容风险标识
本任务被
标识为内容中包含有代码安全 Bug 、隐私泄露等敏感信息,仓库外成员不可访问
001、谈谈常用的分布式ID的设计方案?Snowflake是否受冬令时切换影响?
待办的
#I1WG0K
赵伟风
拥有者
创建于
2020-09-23 21:24
### 考点分析! 今天的问题不仅源自面试的热门考点,并且也存在着广泛的应用场景,我前面给出的回答只是一 个比较精简的典型方案介绍。我建议你针对特定的方案进行深入分析,以保证在面试官可能会深 入追问时能有充分准备;如果恰好在现有系统使用分布式 ID,理解其设计细节是很有必要的。 涉及分布式,很多单机模式下的简单问题突然就变得复杂了,这是分布式天然的复杂性,需要从 不同角度去理解适用场景、架构和细节算法,我会从下面的角度进行适当解读: - 我们的业务到底需要什么样的分布式 ID,除了唯一和有序,还有哪些必须要考虑的要素? - 在实际场景中,针对典型的方案,有哪些可能的局限性或者问题,可以采取什么办法解决 呢? ### 问题回答! **首先,我们需要明确通常的分布式 ID 定义,基本的要求包括:** - 全局唯一,区别于单点系统的唯一,全局是要求分布式系统内唯一。 - 有序性,通常都需要保证生成的 ID 是有序递增的。例如,在数据库存储等场景中,有序 ID 便于确定数据位置,往往更加高效。 目前业界的方案很多,典型方案包括: - 基于数据库自增序列的实现。这种方式优缺点都非常明显,好处是简单易用,但是在扩展性 和可靠性等方面存在局限性。 - 基于 Twitter 早期开源的Snowflake的实现,以及相关改动方案。这是目前应用相对比较广 泛的一种方式,其结构定义你可以参考下面的示意图。  整体长度通常是 64 (1 + 41 + 10+ 12 = 64)位,适合使用 Java 语言中的 long 类型来存储。 头部是 1 位的正负标识位。 紧跟着的高位部分包含 41 位时间戳,通常使用 System.currentTimeMillis()。 后面是 10 位的 WorkerID,标准定义是 5 位数据中心 + 5 位机器 ID,组成了机器编号,以区 分不同的集群节点。 最后的 12 位就是单位毫秒内可生成的序列号数目的理论极限。 Snowflake 的官方版本是基于 Scala 语言,Java 等其他语言的参考实现有很多,是一种非常简 单实用的方式,具体位数的定义是可以根据分布式系统的真实场景进行修改的,并不一定要严格 按照示意图中的设计。 - Redis、Zookeeper、MangoDB 等中间件,也都有各种唯一 ID 解决方案。其中一些设计也 可以算作是 Snowflake 方案的变种。例如,MongoDB 的ObjectId提供了一个 12 byte(96 位)的 ID 定义,其中 32 位用于记录以秒为单位的时间,机器 ID 则为 24 位,16 位用作进程 ID,24 位随机起始的计数序列。 - 国内的一些大厂开源了其自身的部分分布式 ID 实现,InfoQ 就曾经介绍过微信的seqsvr,它 采取了相对复杂的两层架构,并根据社交应用的数据特点进行了针对性设计,具体请参考相 关代码实现。另外,百度、美团等也都有开源或者分享了不同的分布式 ID 实现,都可以进行 参考。 **关于第二个问题,Snowflake 是否受冬令时切换影响?** 我认为没有影响,你可以从 Snowflake 的具体算法实现寻找答案。我们知道 Snowflake 算法的 Java 实现,大都是依赖于 System.currentTimeMillis(),这个数值代表什么呢?从 Javadoc 可 以看出,它是返回当前时间和 1970 年 1 月 1 号 UTC 时间相差的毫秒数,这个数值与夏 / 冬令 时并没有关系,所以并不受其影响。 ### 后续扩展! 如果试图深入回答这个问题,首先需要明确业务场景的需求要点,我们到底需要一个什么样的分 布式 ID? 除了唯一和有序,考虑到分布式系统的功能需要,通常还会额外希望分布式 ID 保证: - 有意义,或者说包含更多信息,例如时间、业务等信息。这一点和有序性要求存在一定关 联,如果 ID 中包含时间,本身就能保证一定程度的有序,虽然并不能绝对保证。ID 中包含 额外信息,在分布式数据存储等场合中,有助于进一步优化数据访问的效率。 - 高可用性,这是分布式系统的必然要求。前面谈到的方案中,有的是真正意义上的分布式, 有得还是传统主从的思路,这一点没有绝对的对错,取决于我们业务对扩展性、性能等方面 的要求。 - 紧凑性,ID 的大小可能受到实际应用的制约,例如数据库存储往往对长 ID 不友好,太长的 ID 会降低 MySQL 等数据库索引的性能;编程语言在处理时也可能受数据类型长度限制。 在具体的生产环境中,还有可能提出对 QPS 等方面的具体要求,尤其是在国内一线互联网公司 的业务规模下,更是需要考虑峰值业务场景的数量级层次需求。 第二,主流方案的优缺点分析。 对于数据库自增方案,除了实现简单,它生成的 ID 还能够保证固定步长的递增,使用很方便。 但是,因为每获取一个 ID 就会触发数据库的写请求,是一个代价高昂的操作,构建高扩展性、 高性能解决方案比较复杂,性能上限明显,更不要谈扩容等场景的难度了。与此同时,保证数据 库方案的高可用性也存在挑战,数据库可能发生宕机,即使采取主从热备等各种措施,也可能出 现 ID 重复等问题。 实际大厂商往往是构建了多层的复合架构,例如美团公开的数据库方案Leaf-Segment,引入了 起到缓存等作用的 Leaf 层,对数据库操作则是通过数据库中间件提供的批量操作,这样既能保 证性能、扩展性,也能保证高可用。但是,这种方案对基础架构层面的要求很多,未必适合普通 业务规模的需求。 与其相比,Snowflake 方案的好处是算法简单,依赖也非常少,生成的序列可预测,性能也非 常好,比如 Twitter 的峰值超过 10 万 /s。 但是,它也存在一定的不足,例如: - 时钟偏斜问题(Clock Skew)。我们知道普通的计算机系统时钟并不能保证长久的一致性, 可能发生时钟回拨等问题,这就会导致时间戳不准确,进而产生重复 ID。 针对这一点,Twitter 曾经在文档中建议开启NTP,毕竟 Snowflake 对时间存在依赖,但是也 有人提议关闭 NTP。我个人认为还是应该开启 NTP,只是可以考虑将 stepback 设置为 0,以 禁止回调。 从设计和具体编码的角度,还有一个很有效的措施就是缓存历史时间戳,然后在序列生成之前进 行检验,如果出现当前时间落后于历史时间的不合理情况,可以采取相应的动作,要么重试、等 待时钟重新一致,或者就直接提示服务不可用。 - 另外,序列号的可预测性是把双刃剑,虽然简化了一些工程问题,但很多业务场景并不适合 可预测的 ID。如果你用它作为安全令牌之类,则是非常危险的,很容易被黑客猜测并利用。 - ID 设计阶段需要谨慎考虑暴露出的信息。例如,Erlang 版本的 flake 实现基于 MAC 地址计 算 WorkerID,在安全敏感的领域往往是不可以这样使用的。 - 从理论上来说,类似 Snowflake 的方案由于时间数据位数的限制,存在与2038 年问题相似 的理论极限。虽然目前的系统设计考虑数十年后的问题还太早,但是理解这些可能的极限是 有必要的,也许会成为面试的过程中的考察点。 如果更加深入到时钟和分布式系统时序的问题,还有与分布式 ID 相关但又有所区别的问题,比 如在分布式系统中,不同机器的时间很可能是不一致的,如何保证事件的有序性?Lamport 在 1978 年的论文(Time, Clocks, and the Ording of Events in a Distributed System)中就有 很深入的阐述,有兴趣的同学可以去查找相应的翻译和解读。
### 考点分析! 今天的问题不仅源自面试的热门考点,并且也存在着广泛的应用场景,我前面给出的回答只是一 个比较精简的典型方案介绍。我建议你针对特定的方案进行深入分析,以保证在面试官可能会深 入追问时能有充分准备;如果恰好在现有系统使用分布式 ID,理解其设计细节是很有必要的。 涉及分布式,很多单机模式下的简单问题突然就变得复杂了,这是分布式天然的复杂性,需要从 不同角度去理解适用场景、架构和细节算法,我会从下面的角度进行适当解读: - 我们的业务到底需要什么样的分布式 ID,除了唯一和有序,还有哪些必须要考虑的要素? - 在实际场景中,针对典型的方案,有哪些可能的局限性或者问题,可以采取什么办法解决 呢? ### 问题回答! **首先,我们需要明确通常的分布式 ID 定义,基本的要求包括:** - 全局唯一,区别于单点系统的唯一,全局是要求分布式系统内唯一。 - 有序性,通常都需要保证生成的 ID 是有序递增的。例如,在数据库存储等场景中,有序 ID 便于确定数据位置,往往更加高效。 目前业界的方案很多,典型方案包括: - 基于数据库自增序列的实现。这种方式优缺点都非常明显,好处是简单易用,但是在扩展性 和可靠性等方面存在局限性。 - 基于 Twitter 早期开源的Snowflake的实现,以及相关改动方案。这是目前应用相对比较广 泛的一种方式,其结构定义你可以参考下面的示意图。  整体长度通常是 64 (1 + 41 + 10+ 12 = 64)位,适合使用 Java 语言中的 long 类型来存储。 头部是 1 位的正负标识位。 紧跟着的高位部分包含 41 位时间戳,通常使用 System.currentTimeMillis()。 后面是 10 位的 WorkerID,标准定义是 5 位数据中心 + 5 位机器 ID,组成了机器编号,以区 分不同的集群节点。 最后的 12 位就是单位毫秒内可生成的序列号数目的理论极限。 Snowflake 的官方版本是基于 Scala 语言,Java 等其他语言的参考实现有很多,是一种非常简 单实用的方式,具体位数的定义是可以根据分布式系统的真实场景进行修改的,并不一定要严格 按照示意图中的设计。 - Redis、Zookeeper、MangoDB 等中间件,也都有各种唯一 ID 解决方案。其中一些设计也 可以算作是 Snowflake 方案的变种。例如,MongoDB 的ObjectId提供了一个 12 byte(96 位)的 ID 定义,其中 32 位用于记录以秒为单位的时间,机器 ID 则为 24 位,16 位用作进程 ID,24 位随机起始的计数序列。 - 国内的一些大厂开源了其自身的部分分布式 ID 实现,InfoQ 就曾经介绍过微信的seqsvr,它 采取了相对复杂的两层架构,并根据社交应用的数据特点进行了针对性设计,具体请参考相 关代码实现。另外,百度、美团等也都有开源或者分享了不同的分布式 ID 实现,都可以进行 参考。 **关于第二个问题,Snowflake 是否受冬令时切换影响?** 我认为没有影响,你可以从 Snowflake 的具体算法实现寻找答案。我们知道 Snowflake 算法的 Java 实现,大都是依赖于 System.currentTimeMillis(),这个数值代表什么呢?从 Javadoc 可 以看出,它是返回当前时间和 1970 年 1 月 1 号 UTC 时间相差的毫秒数,这个数值与夏 / 冬令 时并没有关系,所以并不受其影响。 ### 后续扩展! 如果试图深入回答这个问题,首先需要明确业务场景的需求要点,我们到底需要一个什么样的分 布式 ID? 除了唯一和有序,考虑到分布式系统的功能需要,通常还会额外希望分布式 ID 保证: - 有意义,或者说包含更多信息,例如时间、业务等信息。这一点和有序性要求存在一定关 联,如果 ID 中包含时间,本身就能保证一定程度的有序,虽然并不能绝对保证。ID 中包含 额外信息,在分布式数据存储等场合中,有助于进一步优化数据访问的效率。 - 高可用性,这是分布式系统的必然要求。前面谈到的方案中,有的是真正意义上的分布式, 有得还是传统主从的思路,这一点没有绝对的对错,取决于我们业务对扩展性、性能等方面 的要求。 - 紧凑性,ID 的大小可能受到实际应用的制约,例如数据库存储往往对长 ID 不友好,太长的 ID 会降低 MySQL 等数据库索引的性能;编程语言在处理时也可能受数据类型长度限制。 在具体的生产环境中,还有可能提出对 QPS 等方面的具体要求,尤其是在国内一线互联网公司 的业务规模下,更是需要考虑峰值业务场景的数量级层次需求。 第二,主流方案的优缺点分析。 对于数据库自增方案,除了实现简单,它生成的 ID 还能够保证固定步长的递增,使用很方便。 但是,因为每获取一个 ID 就会触发数据库的写请求,是一个代价高昂的操作,构建高扩展性、 高性能解决方案比较复杂,性能上限明显,更不要谈扩容等场景的难度了。与此同时,保证数据 库方案的高可用性也存在挑战,数据库可能发生宕机,即使采取主从热备等各种措施,也可能出 现 ID 重复等问题。 实际大厂商往往是构建了多层的复合架构,例如美团公开的数据库方案Leaf-Segment,引入了 起到缓存等作用的 Leaf 层,对数据库操作则是通过数据库中间件提供的批量操作,这样既能保 证性能、扩展性,也能保证高可用。但是,这种方案对基础架构层面的要求很多,未必适合普通 业务规模的需求。 与其相比,Snowflake 方案的好处是算法简单,依赖也非常少,生成的序列可预测,性能也非 常好,比如 Twitter 的峰值超过 10 万 /s。 但是,它也存在一定的不足,例如: - 时钟偏斜问题(Clock Skew)。我们知道普通的计算机系统时钟并不能保证长久的一致性, 可能发生时钟回拨等问题,这就会导致时间戳不准确,进而产生重复 ID。 针对这一点,Twitter 曾经在文档中建议开启NTP,毕竟 Snowflake 对时间存在依赖,但是也 有人提议关闭 NTP。我个人认为还是应该开启 NTP,只是可以考虑将 stepback 设置为 0,以 禁止回调。 从设计和具体编码的角度,还有一个很有效的措施就是缓存历史时间戳,然后在序列生成之前进 行检验,如果出现当前时间落后于历史时间的不合理情况,可以采取相应的动作,要么重试、等 待时钟重新一致,或者就直接提示服务不可用。 - 另外,序列号的可预测性是把双刃剑,虽然简化了一些工程问题,但很多业务场景并不适合 可预测的 ID。如果你用它作为安全令牌之类,则是非常危险的,很容易被黑客猜测并利用。 - ID 设计阶段需要谨慎考虑暴露出的信息。例如,Erlang 版本的 flake 实现基于 MAC 地址计 算 WorkerID,在安全敏感的领域往往是不可以这样使用的。 - 从理论上来说,类似 Snowflake 的方案由于时间数据位数的限制,存在与2038 年问题相似 的理论极限。虽然目前的系统设计考虑数十年后的问题还太早,但是理解这些可能的极限是 有必要的,也许会成为面试的过程中的考察点。 如果更加深入到时钟和分布式系统时序的问题,还有与分布式 ID 相关但又有所区别的问题,比 如在分布式系统中,不同机器的时间很可能是不一致的,如何保证事件的有序性?Lamport 在 1978 年的论文(Time, Clocks, and the Ording of Events in a Distributed System)中就有 很深入的阐述,有兴趣的同学可以去查找相应的翻译和解读。
评论 (
0
)
登录
后才可以发表评论
状态
待办的
待办的
进行中
已完成
已关闭
负责人
未设置
Java老郑
qianfeng_laozheng
负责人
协作者
+负责人
+协作者
标签
未设置
标签管理
里程碑
05.Java分布式微服务阶段面试题
未关联里程碑
Pull Requests
未关联
未关联
关联的 Pull Requests 被合并后可能会关闭此 issue
分支
未关联
分支 (
-
)
标签 (
-
)
开始日期   -   截止日期
-
置顶选项
不置顶
置顶等级:高
置顶等级:中
置顶等级:低
优先级
不指定
严重
主要
次要
不重要
参与者(1)
1
https://gitee.com/beike-java-interview-alliance/java-interview.git
git@gitee.com:beike-java-interview-alliance/java-interview.git
beike-java-interview-alliance
java-interview
Java技术提升库
点此查找更多帮助
搜索帮助
Git 命令在线学习
如何在 Gitee 导入 GitHub 仓库
Git 仓库基础操作
企业版和社区版功能对比
SSH 公钥设置
如何处理代码冲突
仓库体积过大,如何减小?
如何找回被删除的仓库数据
Gitee 产品配额说明
GitHub仓库快速导入Gitee及同步更新
什么是 Release(发行版)
将 PHP 项目自动发布到 packagist.org
评论
仓库举报
回到顶部
登录提示
该操作需登录 Gitee 帐号,请先登录后再操作。
立即登录
没有帐号,去注册