Uber 使用子集群重新设计 M3DB 分片策略,降低故障影响
Uber 重新设计了 M3DB 的分片放置策略,引入了固定大小的子集群,以此来限制节点故障、运维和集群扩容带来的影响。这一改动解决了旧放置模型的一个缺陷——在旧模型中,随着分片依赖关系增多,单节点故障对集群的影响范围可达到 (n-1)/n。
M3DB 是 Uber 的分布式时序数据库,数据被划分为多个分片,并在多个节点间复制。其放置算法决定了分片的所有权,并强制保持副本之间的隔离,例如将副本放置在不同的机架或可用区中。Uber 工程师强调,原有的分片放置模型在中小型集群中表现良好,但随着集群规模增长,运维难度也随之上升。
在旧模型中,只要副本没有被放置在同一隔离组中,任意节点都可以拥有一个分片。这种宽松的配置会形成一个依赖图,一次拓扑变更就会影响到 O(N) 个节点。即使隔离组对应三个可用区且复制因子为 3,一个节点仍可能与集群中多达 66.67% 的节点共享数据。Uber 表示,这会增加数据恢复的工作量,并且使得运维操作只能串行执行。
新模型将节点划分为固定大小的子集群,每个子集群拥有互不重叠的分片空间。以 Uber 的示例来说,一个 12 节点集群,复制因子为 3、每个子集群 6 个节点,包含两个子集群,各自拥有一半分片。在子集群内部,M3DB 仍然会把副本分散部署到不同隔离组。
扩容时需要将分片从原有子集群迁移至新子集群。Uber 使用贪心算法评估从源子集群移除每一个候选分片带来的影响,并选择使剩余节点负载尽可能均匀的分片。这避免了额外的再平衡过程,以及因分片被移动两次而产生的额外网络传输和引导开销。算法的排序复杂度为 (O(S\log S)),模拟评估开销为 (O(S\times N)),其中 S 代表候选分片数量,N 是子集群内的节点数。
M3DB 现有的放置策略文档同样描述了分片迁移流程:目标节点在接管所有权之前从现有对等节点流式传输数据,因此不必要的分片移动会成为一项运维开销。该放置模型同样借助隔离组防止多个副本部署在同一机架或可用区。
子集群方案存在一些约束条件。它要求所有实例权重相等,扩容必须以子集群规模为单位批量进行,并且子集群大小必须是副本因子的整数倍。该方案也不支持通过 AddReplica 接口修改复制因子。扩容期间会短暂出现跨子集群共享分片的情况,同时系统同一时刻只允许存在一个非完整子集群。
Uber 保留了 M3DB 现有的实例级放置操作,没有引入原子化的子集群操作。Uber 团队强调,这保持了与现有工具的兼容性,并避免了触发大量分片同时迁移的大规模引导操作。M3DB 的放置策略现在包含用于子集群放置和每个子集群实例数量的字段。