ScyllaDB 基于大小的 Tablet 负载均衡:原理、配置参数与 tablet 尺寸对账机制
2026/9/14 8:15:51 网站建设 项目流程

ScyllaDB 基于大小的 Tablet 负载均衡:原理、配置参数与 tablet 尺寸对账机制

【免费下载链接】scylladbNoSQL data store using the Seastar framework, compatible with Apache Cassandra and Amazon DynamoDB项目地址: https://gitcode.com/GitHub_Trending/sc/scylladb

ScyllaDB 的 tablet 负载均衡器从"按磁盘容量均分 tablet 数量"演进为"按 tablet 实际磁盘大小均衡磁盘利用率",这一演进由仓库中的设计文档 size-based-load-balancing.md 完整描述,其核心实现位于 tablet_allocator.cc 与 load_sketch.hh。读完本文,你将掌握 size-based load balancing 的信息采集流程(load_stats)、tablet 尺寸的迁移/拆分/合并对账机制、关键配置参数的默认值与生效方式,以及滚动升级期间通过集群特性优雅回退到容量均衡的设计。

背景:从磁盘容量均衡到按大小均衡

在引入 size-based load balancing 之前,ScyllaDB 执行的是基于磁盘的均衡(disk based balancing):按节点磁盘容量与 tablet 数量进行分配,其隐含假设是每个 tablet 占用相同的磁盘空间。也就是说,某节点上的 tablet 数量与该节点的磁盘总容量(gross disk capacity)成正比。

问题在于,不同 tablet 实际占用的磁盘空间可能差异巨大——热点 tablet 可能远大于平均水平,冷门 tablet 可能几乎为空。在这种假设下做数量均衡,会造成集群内磁盘利用率失衡。Size-based load balancing 的目标正是让集群内各节点的磁盘利用率趋于一致:负载均衡器持续收集所有节点的可用磁盘空间与 tablet 大小信息,并据此增量地计算 tablet 迁移计划,将 tablet 从负载最高的节点/分片迁移到负载最低的节点/分片。

基本运行机制:load_stats 的采集与使用

负载均衡器以后台任务形式运行,且与拓扑协调者(topology coordinator)运行在同一个 shard 上。协调者负责周期性地从集群所有节点采集均衡决策所需的信息,这一信息就是数据结构的load_stats。文档中与负载均衡直接相关的部分是其成员tablet_stats,包含两个字段:

  • tablet_sizes:该节点上所有 tablet 的磁盘大小(字节);
  • effective_capacity:该节点可用磁盘空间与所有 tablet 大小之和。

在源码中,这两个字段对应 locator/tablets.hh 中的tablet_load_stats结构体:

// This is defined as final in the idl layer to limit the amount of encoded data sent via the RPC struct tablet_load_stats { // Sum of all tablet sizes on a node and available disk space. uint64_t effective_capacity = 0; // Contains tablet sizes per table. // The token ranges must be the form (a, b] and only such ranges are allowed std::unordered_map<table_id, std::unordered_map<dht::token_range, uint64_t>> tablet_sizes; ... };

完整的load_stats结构(locator/tablets.hh)还包括按表的统计tables、按节点的原始磁盘容量capacity、关键磁盘利用率标记critical_disk_utilization以及按节点聚合的tablet_stats。节点上报的采集周期由配置项tablet_load_stats_refresh_interval_in_seconds控制,定义于 db/config.cc,默认值为60 秒(即文档中提到的"1 分钟采集间隔"),支持 LiveUpdate 热更新。

协调者拿到这些信息后,计算每个节点、每个 shard 的磁盘负载(磁盘利用率),然后把 tablet 从最繁忙迁移到最空闲的节点与 shard。从源码结构看,这一计算由 locator/load_sketch.hh 中的load_sketch完成:disk_usageused / capacity(0.0 到 1.0 的因子)表示利用率,load_sketch内部按节点组织node_load,每个node_load再按 shard 组织shard_load,并用有序集合_shards_by_load按负载升序索引所有 shard,以便快速定位最忙/最闲的 shard。值得注意的是,load_sketch在计算负载时乐观地把已发起、尚未完成的 tablet 迁移视为已经发生(locator/load_sketch.hh 中注释明确写道"optimistically assuming that they will succeed"),这保证了一轮决策中不会反复挑选同一个迁移目标。

Table balance:均衡的次级目标

负载均衡器的次级目标是达成 table balance(表级均衡),即需要让以下两个比值在各 shard 之间趋于相等:

  • 某 shard 上某表占用的磁盘 / 该表在整 rack 内占用的磁盘总量;
  • 某 shard 的有效容量 / 整个 rack 的有效容量。

如果不做这一层均衡,可能出现某个 shard 承载了某张表的大部分数据。一旦该表是"热表"(访问集中),就会让该 shard 的 CPU 过载。换言之,size-based 均衡不仅在节点间摊平磁盘,也在 shard 间摊平"每表数据份额与容量份额"的比例关系。

load_stats 对账:迁移与 split/merge 后的尺寸一致性

由于load_stats的采集周期为 1 分钟,均衡器开始使用这些信息时,其中记录可能已经过期。过期的原因主要有两类:tablet 迁移表 resize(split 或 merge)。解决办法是在迁移或 resize 发生时同步更新load_stats中的 tablet 尺寸信息:

  • 迁移对账:已发出的 tablet 迁移会在load_stats中把 tablet 尺寸从一个 host "迁移"到另一个 host。这一步对账在 tablet 迁移流程的end_migration阶段完成。源码中end_migration作为 tablet 状态机的一个阶段出现在 service/tablet_allocator.cc,与文档描述一致。
  • split 对账:在 tablet resize 确认(resize finalization)阶段进行。对于 split,对账会把原 tablet 的尺寸一分为二,用两个新 tablet 替换 split 前的原 tablet 尺寸记录。
  • merge 对账:对 merge,则累加 merge 前各 tablet 的尺寸,生成合并后的 tablet 尺寸记录,并从load_stats中移除 merge 前各 tablet 的尺寸。

这套对账机制保证load_stats中记录的尺寸始终"追着"tablet 拓扑的实际变化,而不必等待下一个采集周期。

强制容量均衡:force_capacity_based_balancing

均衡器具备回退到容量均衡(capacity based balancing)的能力,可通过配置参数force_capacity_based_balancing强制启用。开启后:

  • 均衡器不再load_stats查询真实 tablet 尺寸,而是假定每个 tablet 的大小都等于default_target_tablet_size
  • 容量计算改用原始磁盘容量(gross disk capacity,即load_stats结构中的capacity成员),而非有效容量effective_capacity

在 db/config.cc 中可以看到该参数定义:

, force_capacity_based_balancing(this, "force_capacity_based_balancing", liveness::LiveUpdate, value_status::Used, false, "Forces the load balancer to perform capacity based balancing, instead of size based balancing.")

即默认值为false,支持 LiveUpdate。load_sketch侧用一个布尔标志_force_capacity_based_load实现该回退(locator/load_sketch.hh):为真时get_disk_capacity_for_node回落到capacityget_tablet_size直接返回_default_tablet_size

default_target_tablet_size定义于 service/tablet_allocator_fwd.hh,值为5 * 1024 * 1024 * 1024,即5 GiB,这也是 tablet 自动拆分/合并的目标尺寸基准。

此外,force_capacity_based_balancing还承担一个"兜底"角色:在集群特性尚未开启时,均衡器会自己切到容量均衡模式(见下文集群特性一节)。测试用例中也直接验证了这一回退逻辑,例如 test/boost/tablets_test.cc 中通过cfg.db_config->force_capacity_based_balancing.set(true)构造容量均衡场景。

排除 tablet 尺寸不完整的节点

即便有迁移与 resize 对账,load_stats中的 tablet 尺寸信息仍可能与 tablet map 中的当前 tablet 信息不一致。为避免均衡器基于不完整或错误的数据做决策,size-based load balancing不会去平衡那些 tablet 尺寸不完整的节点:这些节点既不会被选为迁移源,也不会被选为迁移目标;均衡器会等待拓扑协调者下一次刷新load_stats后,待正确的尺寸数据到达再参与决策。

唯一的例外是被排除出集群(excluded)的节点:这类节点已下线,无法再上报新鲜的load_stats,但它们仍需要被"排干"——通过 tablet rebuild 把 tablet 迁走。因此均衡器必须在 tablet 数据不完整的情况下也对其执行迁移。源码中load_sketchnode_load_has_valid_disk_capacity_has_all_tablet_sizes两个标记追踪节点数据完整性(locator/load_sketch.hh),与"不完整则不参与均衡"的行为相呼应。

集群特性:SIZE_BASED_LOAD_BALANCING 与滚动升级

滚动升级期间,集群全部升级完成可能需要数小时甚至数天。未升级的旧节点上报的load_stats不带 tablet 尺寸。结合上一条规则(均衡器忽略尺寸不完整的节点),如果不加处理,这些节点会在相当长的时间内得不到负载均衡。

因此,size-based load balancing 只在对应集群特性(cluster feature)开启后才真正生效;特性开启之前,均衡器回退到容量均衡。该特性在 gms/feature_service.hh 中声明:

gms::feature size_based_load_balancing { *this, "SIZE_BASED_LOAD_BALANCING"sv };

而回退逻辑可以直接在 service/tablet_allocator.cc 中确认:构造时读取force_capacity_based_balancing配置,随后若集群特性size_based_load_balancing未开启且未强制容量均衡,则把_force_capacity_based_balancing置为true。也就是说,"滚动升级期间自动容量均衡、全量升级后自动切换为按大小均衡"这一行为由特性开关与配置项共同决定,无需人工干预。

Minimal tablet size:避免对未 flush tablet 的过早迁移

表创建后开始接收数据时,可能有一段时期:某些 tablet 的数据已经 flush 到磁盘,而其他 tablet 还没有。此时若按真实尺寸决策,均衡器会把那些"看起来为空"(其实只是还没 flush)的 tablet 从创建节点迁走;等所有 tablet 都 flush 之后,又得重新迁移,产生无谓的早期迁移。

为此引入minimal tablet size概念:均衡器把小于该阈值的 tablet 一律按 minimal tablet size 计。这显著减少了早期无谓迁移。对应配置项为minimal_tablet_size_for_balancing,定义于 db/config.cc:

, minimal_tablet_size_for_balancing(this, "minimal_tablet_size_for_balancing", liveness::LiveUpdate, value_status::Used, service::default_target_tablet_size / 100, "Sets the minimal tablet size for the load balancer. For any tablet smaller than this, the balancer will use this size instead of the actual tablet size.")

默认值为default_target_tablet_size / 100,即 5 GiB 的百分之一(约 51.2 MiB),同样支持 LiveUpdate;该值最终注入到load_sketch_minimal_tablet_size成员参与尺寸计算(locator/load_sketch.hh)。

Balance threshold percentage:何为"已均衡"

均衡器判断一组节点是否已经均衡的方法是:计算负载最高与负载最低节点之间的磁盘负载差,除以最高负载:

delta = (most_loaded - least_loaded) / most_loaded

若该值低于阈值,则认定这些节点已处于均衡状态,无需再发起迁移。阈值通过size_based_balance_threshold_percentage配置项设置,定义于 db/config.cc:

, size_based_balance_threshold_percentage(this, "size_based_balance_threshold_percentage", liveness::LiveUpdate, value_status::Used, 1.0, "Sets the maximum difference in percentages between the most loaded and least loaded nodes, below which the load balancer considers nodes balanced.")

默认值为1.0(百分比),支持 LiveUpdate。在均衡器构造时,该百分比被除以 100 转为比例存入_size_based_balance_threshold(service/tablet_allocator.cc)。调低该值会追求更严格的均衡(迁移更频繁),调高则减少迁移量但容忍更大的利用率差异。

相关配置参数汇总

以下参数均定义于 db/config.cc,且均为 LiveUpdate(可在线修改、无需重启):

配置项默认值作用
tablet_load_stats_refresh_interval_in_seconds60load_stats采集刷新周期(秒),决定均衡信息的最大滞后
force_capacity_based_balancingfalse强制容量均衡:假定所有 tablet 等大小(5 GiB)、使用原始磁盘容量而非有效容量
size_based_balance_threshold_percentage1.0最高与最低负载节点差值相对最高负载的百分比阈值,低于该值视为已均衡
minimal_tablet_size_for_balancingdefault_target_tablet_size / 100(约 51.2 MiB)小于该值的 tablet 按该值计,避免未 flush tablet 的过早迁移

源码与测试索引

想进一步深入实现时,可以从以下入口切入:

  • 均衡算法主体:service/tablet_allocator.cc,其中TabletLoadBalancer构造时读取上述配置并决定均衡模式;
  • 负载模型:locator/load_sketch.hh,load_sketch维护节点/shard 两级负载视图,并提供容量回退(_force_capacity_based_load)与在途迁移的乐观记账;
  • 数据结构:locator/tablets.hh 的table_load_statstablet_load_statsload_stats
  • 集群特性声明:gms/feature_service.hh;
  • 单元/集成测试:test/boost/tablets_test.cc(容量均衡回退场景)与 test/boost/tablets_test.cc(阈值参数场景);性能测试入口见 test/perf/tablet_load_balancing.cc。

小结

ScyllaDB 的 size-based load balancing 是一套围绕"磁盘利用率"的均衡机制:以拓扑协调者周期性采集的load_stats(tablet 尺寸 + 有效容量)为输入,通过迁移与 split/merge 对账保证输入的新鲜度,通过"不完整节点除外 + excluded 节点例外"保证决策安全,通过集群特性SIZE_BASED_LOAD_BALANCING保证滚动升级期间的平滑过渡,并通过 minimal tablet size 与 balance threshold percentage 两个参数控制迁移的触发时机与收敛标准。配合force_capacity_based_balancing的显式回退能力,整套机制在异构容量、混合版本集群中都能保持行为可预测。

【免费下载链接】scylladbNoSQL data store using the Seastar framework, compatible with Apache Cassandra and Amazon DynamoDB项目地址: https://gitcode.com/GitHub_Trending/sc/scylladb

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询