找回密码
 会员注册
查看: 12|回复: 0

有赞发号器多机房方案

[复制链接]

2万

主题

0

回帖

7万

积分

超级版主

积分
71880
发表于 2024-10-8 09:12:58 | 显示全部楼层 |阅读模式
、、点击关注“有赞coder”获取更多技术干货哦~作者:小朋友团队:中间件团队有赞发号器多机房方案发号器一般用来产生全局唯一 ID,有赞发号器的设计及背景参见文章《如何做一个靠谱的发号器》,本文在此基础上进行扩展,提供多机房发号与集群拆分能力,下文中使用 March 表示发号器服务。图1 展示了改造前发号器双机房的架构,其中:控制台负责管理发号器配置,March 包括主备节点,主节点负责发号,备节点进行灾备,etcd 作为持久化存储。图1. 发号器架构问题根据图1 架构可以看出,将 etcd 跨多机房部署,借助 etcd 本身的就能保证在多机房的数据一致性及可用性,但在实践中还是会碰到一些问题:若只有两个机房,没法实现机房级别的高可用(极端情况下一个机房完全不可用时需要人工恢复)March 单主节点模式,多机房时造成大量的跨机房请求,网络稳定性和时延都会变差March 单主节点不利于水平扩展集群拆分需要停机,运维复杂度高多机房方案针对现有架构碰到的一些问题,进行了如下的改造:图2. 发号器多机房架构图2 架构进行调整后可以发现已经解决了上述的问题中的:1(高可用)、2(跨机房请求)、3(水平扩容) 这些问题,接下来会详细说明方案如何实现及问题4(动态拆分)的解决方案。有经验的读者可能会想到,发号器多机房同时发号只需要在ID 上选取几个bit 位作为机房的标记就万事大吉了,其实有赞的实现并非如此,其中原因牵涉到一些历史背景。读过《如何做一个靠谱的发号器》的读者应该有印象,有赞内部的发号器可以分为两种类型:1. 单纯的 Sequence,即一个不断递增的整数;2. Timestamp 相关的,在可选时间精度的基础上,支持额外加一段 Sequence。这两种类型都支持批量获取,即一次性获取[ id, id + batch_size ) 的区间,这样能大大减少客户端对 March 服务的请求数,发号效率有质地提升。细心的读者可能已经发现使用低位的 bit 作为机房标志是没法兼容现有的缓存机制。如果把机房标志放在高 bit 位呢,这个对于 Timestamp 类型是可行的,并且在原有的设计中 Timestamp 类型已经预留好了机房标志位,该版对此稍做扩展就完成了 Timestamp 的升级,因此本文接下来主要讨论 Sequence 类型的双机房升级。对于 Sequence 类型,将机房标识放在高位上看似能解决问题,但会碰到几个问题:1. 作为标识的位已经被占用,假设ID 只有8位,并且当前已经发号到 0110 0000,那么使用高3位作为机房标识,就可能引起重复发号;2. 本身 Sequence 是为了让生成的ID 近似有序,高位加上后不同机房生成的ID 值相差过大。这里采用分段的思想来处理 Sequence 类型,关键配置包括:配置含义boundary边界长度,生成的 ID 对 boundary 取余后要处于 [lower, upper)区间内,保持所有机房相同lower上边界 (包含边界点的值),取值范围 [0, upper)upper分段的 (不包含边界点的值),取值范围 (lower, boundary]限制条件:不同机房间的区间长度必须相同,并且发号区间不能相交。如果机房1 的配置为 (boundary1, lower1, upper1),机房2 的配置为 (boundary2, lower2, upper2),它们必须满足如下的约束条件:boundary1 == boundary2lower1 != lower2// 假设 lower2 > lower1,需满足如下条件0 id1 mod boundary ≠ id2 mod boundary=> id1 ≠ id2为了方便理解,举个例子来说明双机房下时是如何工作的,假设配置如下:// 机房1 的配置{ "boundary":100, "lower":0, "upper":50}// 机房2 的配置{ "boundary":100, "lower":50, "upper":100}机房1 生成的 ID 序列为:(0, 1, 2, ..., 48, 49, 100, 101, ..., 148, 149, 200, 201, ...);机房2 生成的 ID 序列为:(50, 51, 52, ..., 98, 99, 150, 151, ..., 198, 199, 250, 25, ...)。对于机房1 来说,如果当前生成的最大 id 为 45,需要批量获取 10 个 id,由于区间 [50, 99) 不属于机房1,则需要跳到下一个区间开始生成id, 区间为 [100, 109]。这里需要限制批量获取的数量不能大于子区间的大小,上例中最大一次能获取50 个 id,因此实际中区间长度需要设置的不能太小。扩展&迁移接下来讨论如何在上述方案的基础上实现高效地运维。在原始方案中如果想从发号器服务中拆分出部分 key 到另一个集群需要非常小心谨慎,并且还需要停服务,最可怕的是一些业务在迁移完成后发现还有配置指向老的服务,更不用说一些谁都不敢动的应用。改造后扩展其实比较安全,流程总结为:搭建新的发号器集群在原集群中配置发号区间在新集群中配置发号区间,保证满足约束条件配置发号的初始值,开始发号整个扩展过程中无需停机,并且可以多集群同时工作保证充足的时间验证。迁移只需要在扩展的基础上进行回收操作,简单的说就是在一个集群删除再在另一个集群扩展。虽然理论上已经没问题了,单如果每个步骤完全由人来操作还是容易出错的,所以在有赞内部我们实现了一个控制台,完成约束条件的判断和具体步骤的执行。小结发号器天然具备机房间独立发号的优势,实际开发中还需要考虑对原有功能的兼容、支持在运行中升级、兼顾运维的可操作性。一个可靠的系统还需要尽量减少人的操作,提供一套自动化执行平台,减少运维的负担。扩展阅读深入浅出MySQL crash safe一次大量删除导致 MySQL 慢查的分析数据库连接池配置(案例及排查指南)工作流引擎在有赞 DevOps 中的实践Kubernetes 在有赞的实践Vol.289有赞测试团队近几年在持续交付、质量体系建设以及效率提升方面从0开始做了很多建设,在这个过程中,我们不断梳理、总结,渐渐形成了一本覆盖各个模块的白皮书,现在我们把这些内容对外,也欢迎大家一起交流。《测试实战前沿——有赞测试5年经验全呈现》电子书现已上架,点击「阅读原文」立刻购买。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 会员注册

本版积分规则

QQ|手机版|心飞设计-版权所有:微度网络信息技术服务中心 ( 鲁ICP备17032091号-12 )|网站地图

GMT+8, 2025-1-10 18:04 , Processed in 0.801725 second(s), 25 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表