ScyllaDB 大分区排查与治理:system.large_partitions 表、阈值配置与 LARGE_DATA_VIRTUAL_TABLES 虚拟表机制全解析 ScyllaDB 大分区排查与治理system.large_partitions 表、阈值配置与 LARGE_DATA_VIRTUAL_TABLES 虚拟表机制全解析【免费下载链接】scylladbNoSQL data store using the Seastar framework, compatible with Apache Cassandra and Amazon DynamoDB项目地址: https://gitcode.com/GitHub_Trending/sc/scylladb导读大分区Large Partitions是 ScyllaDB 生产集群中最常见的性能隐患之一单个分区过大往往导致单个 shard 延迟升高、内存分配告警甚至拖慢整个节点。本篇文章围绕 ScyllaDB 官方排查文档 docs/troubleshooting/large-partition-table.rst 展开完整讲解system.large_partitions系统表的查询方法、全部字段语义、scylla.yaml中的阈值配置并深入剖析 ScyllaDB 2026.2 引入的LARGE_DATA_VIRTUAL_TABLES虚拟表机制——大分区记录如何从 SSTable 元数据中读取、如何随 SSTable 迁移以及升级后如何快速填充虚拟表。读完本文你将能够在自己的集群中定位大分区、解读诊断数据并安全完成从旧物理表到新虚拟表的升级过渡。什么是大分区以及它为什么会成为问题ScyllaDB 是共享无shard-per-core架构的 NoSQL 数据库每个节点内部按照 token 范围把数据切分到多个 shard 上。一个分区partition的全部数据在正常情况下应当只由一个 shard负责。当某个分区的数据量或行数异常膨胀例如单个分区达到几百 MB 甚至 GB 级就会出现以下典型症状单个 shard 延迟变长承载大分区的 shard 需要处理远超平均水平的数据其读写路径、压缩compaction和内存占用都显著高于其他 shard。官方文档建议此时查看 ScyllaDB Monitoring Stack 中 ScyllaDB Overview Metrics 仪表盘观察各 shard 的负载分布监控栈的具体安装与指标说明见 docs/operating-scylla 目录下的相关文档。日志中出现超大内存分配告警例如seastar_memory - oversized allocation: 2842624 bytes, please report这类告警意味着某次内存分配超过了 seastar 内存分配器常规的分配上限通常由超大的行、单元格cell或集合collection触发。如果你的集群出现上述任一症状第一步就是检查是否存在大分区。ScyllaDB 提供了system.large_partitions系统表以及同族的system.large_rows、system.large_cells来追踪这些数据。检测机制何时才会被记录理解大分区表之前必须先明确它的检测前提大分区只有在被存储进单个 SSTable时才会被检测到。ScyllaDB 并不会跨多个 SSTable 去累加同一个逻辑分区的数据。只要每个 SSTable 中的任意单个分区没有超过大分区告警阈值即便同一逻辑分区的数据被分散在多个 SSTable 中也不会被记为大分区。但是文档同时给出了一个重要提醒随着时间推移compaction尤其是Size-Tiered Compaction StrategySTCS会把分散在多个 SSTable 中的同一分区数据合并到单个 SSTable 中此时该分区就会跨越大分区阈值、被检测出来。这意味着大分区表反映的是单个 SSTable 内的分区实际占用而不是逻辑分区的总大小分区被检测到的时间点取决于它何时被集中写入同一个 SSTableflush 或 compaction 之后对于使用 STCS 的表大分区问题可能在 compaction 之后才暴露排查时要有预期。从源码看检测逻辑位于 db/large_data_handler.cc 的large_data_handler::maybe_record_large_partitions()它同时比较partition_size _partition_threshold_bytes大小超阈值和rows _rows_count_threshold行数超阈值任一成立即触发记录对应的统计计数定义在 db/large_data_handler.hh 的large_data_handler::stats中partitions_bigger_than_threshold、rows_bigger_than_threshold、cells_bigger_than_threshold、collections_bigger_than_threshold。为了不阻塞主写入路径记录操作通过一个容量为 16 的信号量max_concurrency 16异步限流执行源码注释中给出的估算依据是按每 1MB 至多一条日志、平均 4ms 日志延迟、目标支撑 1GB/s 写带宽计算并发度 4 即够用16 留足了余量。查看大分区查询system.large_partitions全量查询在任意节点上执行 CQL 查询即可看到该节点已检测到的全部大分区SELECT * FROM system.large_partitions;示例输出keyspace_name | table_name | sstable_name | partition_size | partition_key | compaction_time | dead_rows | range_tombstones | rows ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- demodb | tmcr | md-6-big-Data.db | 1188716932 | {key: pk{000400000001}, token:-4069959284402364209} | 2018-07-23 08:10:34 | 0 | 0 | 100 testdb | tmcr | md-7-big-Data.db | 1234567 | {key: pk{000400000001}, token:-3169959284402457813} | 2018-07-23 08:10:34 | 0 | 0 | 100101字段语义各列的含义如下表所示参数说明keyspace_name承载大分区的 keyspace 名称table_name包含大分区的表名sstable_name包含大分区的 SSTable 名称形如md-6-big-Data.dbpartition_size该 SSTable 中这个分区的大小字节partition_key用于标识大分区的分区键值含 token 信息dead_rows该 SSTable 中此分区内的死行dead rows数量range_tombstones该 SSTable 中此分区内的范围墓碑range tombstone数量rows该分区内的行数包括范围墓碑compaction_time最近一次 compaction 发生的时间需要注意dead_rows、range_tombstones两列并非在所有版本都填充。从 db/large_data_handler.cc 可以看到这两列由range_tombstone_and_dead_rows_detection集群特性控制特性启用后_record_large_partitions回调切换为internal_record_large_partitions_all_data()写入完整的三项统计否则只写入rows见internal_record_large_partitions()。按 keyspace / 表过滤大分区表记录很多时可以按 keyspace 和表名过滤。例如查找 keyspacedemodb、表tmcr中的大分区SELECT * FROM system.large_partitions WHERE keyspace_name demodb AND table_name tmcr;示例输出keyspace_name | table_name | sstable_name | partition_size | partition_key | compaction_time | dead_rows | range_tombstones | rows -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- demodb | tmcr | md-6-big-Data.db | 1188716932 | {key: pk{000400000001}, token:-4069959284402364209} | 2018-07-23 08:10:34 | 0 | 0 | 1942重要表是节点本地的system.large_partitions是每节点本地的系统表。查询它只会返回当前查询节点上的结果。因此排查时必须在每个节点上分别执行查询或者借助自动化脚本例如 scylla-gdb / nodetool 之外的批量 CQL 脚本逐节点采集才能获得集群全貌。这一点在使用虚拟表实现后依然成立只是数据来源从物理系统表变成了 SSTable 元数据。配置检测阈值大分区检测的判定阈值在scylla.yaml配置文件中设置。官方文档给出的两个核心参数参数默认值作用compaction_large_partition_warning_threshold_mb1000MB分区大小超过该值即记为大分区compaction_rows_count_warning_threshold100000行分区内行数超过该值即记为大分区分区只要满足大小超阈值或行数超阈值任一条件就会被写入system.large_partitions表并在 ScyllaDB 日志中生成一条 warning日志相关文档见 docs/troubleshooting/log-level.rst。注意源码中判断使用的是严格大于partition_size _partition_threshold_bytes、rows _rows_count_threshold恰好等于阈值不会被记录。例如同时调整两个阈值为 500MB / 50000compaction_large_partition_warning_threshold_mb: 500 compaction_rows_count_warning_threshold: 50000在仓库默认的 conf/scylla.yaml 中这两个参数以注释形式给出默认值同区域还定义了一组更细粒度的相关参数排查大分区时一并了解会很有帮助# Log a warning when writing partitions larger than this value # compaction_large_partition_warning_threshold_mb: 1000 # Reject writes to partitions whose on-disk size exceeds this threshold (MB). # Set to 0 to disable. large_partition_fail_threshold_mb: 2000 # Log a warning when writing rows larger than this value # compaction_large_row_warning_threshold_mb: 10 # Reject writes to rows whose on-disk size exceeds this threshold (MB). # Set to 0 to disable. large_row_fail_threshold_mb: 20 # Log a warning when writing cells larger than this value # compaction_large_cell_warning_threshold_mb: 1 # Reject writes with cell value size exceeding this threshold (MB). # Set to 0 to disable. large_cell_fail_threshold_mb: 2 # When true, soft limit violations detected by the coordinator-side large data # guardrail check are reported to the client as CQL warnings in the response # frame. When false, only server-side logging is performed. large_data_cql_warnings: true # Log a warning when row number is larger than this value # compaction_rows_count_warning_threshold: 100000 # Reject writes to partitions whose on-disk row count exceeds this threshold. # Set to 0 to disable. rows_count_fail_threshold: 200000可以看到 ScyllaDB 对大数据的管控分为**软限制warn 阈值与硬限制fail 阈值**两层以compaction_large_partition_warning_threshold_mb/compaction_rows_count_warning_threshold为代表的软限制负责记录 日志告警即写入大分区表并产生 warning以large_partition_fail_threshold_mb/rows_count_fail_threshold为代表的硬限制guardrail超过后直接拒绝写入值为 0 表示禁用对应源码 db/large_data_handler.cc 中的enforce_threshold()命中 fail 阈值时在 replica 侧抛出replica::large_data_exception在 coordinator 侧抛出exceptions::invalid_request_exception命中 warn 阈值时通过large_data_logger打印日志并可在large_data_cql_warnings: true时随 CQL 响应帧向客户端返回形如Large data guardrail: Soft limit violation for partition, cell的警告生成逻辑见 db/large_data_handler.cc 的large_data_soft_violation_warning()。这些参数的类型定义位于 db/config.hhcompaction_large_partition_warning_threshold_mb、compaction_rows_count_warning_threshold、compaction_large_data_records_per_sstable等并在运行时通过utils::transforming_value_updater动态绑定到cql_table_large_data_handler的阈值字段上意味着修改配置并热加载后无需重启即可生效。存储 Schema 与数据过期表结构大分区记录存储在系统表中可以用DESCRIBE TABLE查看其完整 schemaDESCRIBE TABLE system.large_partitions;CREATE TABLE system.large_partitions ( keyspace_name text, table_name text, sstable_name text, partition_size bigint, partition_key text, compaction_time timestamp, dead_rows bigint, range_tombstones bigint, rows bigint, PRIMARY KEY ((keyspace_name, table_name), sstable_name, partition_size, partition_key) ) WITH CLUSTERING ORDER BY (sstable_name ASC, partition_size DESC, partition_key ASC)这个主键与排序设计是有讲究的分区键(keyspace_name, table_name)让按 keyspace 表过滤的查询上文示例可以直接路由到对应分区聚类键按sstable_name ASC, partition_size DESC排序使得同一张表内最大的分区排在最前方便直接挑出最严重的记录相同 keyspace/table/SSTable 下partition_size与partition_key共同保证记录唯一性——同一个分区在一个 SSTable 内只保留一条记录。从源码看写入语句在 db/large_data_handler.cc 的do_insert_large_data_entry()中动态构造INSERT INTO system.large_{type}s (keyspace_name, table_name, sstable_name, {type}_size, partition_key, compaction_time, ...) VALUES (...) USING TTL 2592000。其中 2592000 秒正好等于 30 天。数据过期TTL 30 天为了防止陈旧数据长期占用空间并干扰判断system.large_partitions表中的所有行插入时都带有30 天TTL 2592000 秒的存活时间。超过 30 天后记录自动过期消失。与此同时SSTable 生命周期事件也会主动维护该表当某个 SSTable 被 compaction 合并、删除时db/large_data_handler.cc 的maybe_delete_large_data_entries()会根据该 SSTable 的大数据统计partition_size、rows_in_partition等删除对应记录当 SSTable 因分层tiering等原因改名时maybe_update_large_data_entries_sstable_name()会执行先查旧名行、以新名重插、再删旧行的操作sstable_name是聚类键无法原地更新注释中明确说明了这一点。这两者共同保证表内容与现存 SSTable 保持同步。虚拟表机制LARGE_DATA_VIRTUAL_TABLES特性从 ScyllaDB 2026.2 开始system.large_partitions、system.large_rows、system.large_cells三张表被重新实现为虚拟表virtual tables它们不再从独立的物理系统表中读取而是直接读取存储在每个 SSTable 内部的元数据。集群特性标志LARGE_DATA_VIRTUAL_TABLES的定义见 gms/feature_service.hh。工作原理写入阶段当 SSTable 被写入flush 或 compaction 期间时SSTable writer 会把每种大数据类型中超过阈值的 Top-N 条记录写入 SSTable 的.Scylla元数据文件中的LargeDataRecords组件。读取阶段虚拟表在查询时实时扫描该节点上所有存活 SSTable 的这份元数据汇总后返回结果。跟随迁移因为记录物理上存在于 SSTable 内部所以当 SSTable 在 shard 之间或节点之间迁移时例如 tablet 迁移或 repair大分区记录会自动跟随 SSTable 一起走无需在系统表中再做跨节点复制或迁移。每个 SSTable 中每种大数据类型最多保存的记录条数由配置项compaction_large_data_records_per_sstable控制默认值为 10该参数定义于 db/config.hh。激活流程该过渡由集群级特性标志LARGE_DATA_VIRTUAL_TABLES控制当集群中所有节点都升级到支持该特性的版本后自动启用。特性在某节点启用时会发生三件事旧的物理表system.large_partitions、system.large_rows、system.large_cells被删除drop在原位置注册虚拟表替代实现新的 SSTable 写入停止填充旧的物理表。滚动升级rolling upgrade期间只要集群中还有节点未升级特性就保持禁用状态所有节点继续写入旧的物理表——这保证了升级过程可回滚如果升级需要回退数据依然完整。从源码看虚拟表的注册与激活逻辑位于 db/virtual_tables.cclarge_partitions_virtual_table以及对应的 large rows / large cells 虚拟表继承自streaming_virtual_table遍历每个 SSTable 调用sst-get_large_data_records()获取LargeDataRecords对于没有LargeDataRecords元数据的旧版本 SSTable虚拟表会回退到sst-get_large_data_stat()生成合成记录synthetic row以保持查询结果兼容。当同一个分区同时超过大小与行数阈值时会按类型分别产生两条LargeDataRecords记录partition_size与rows_in_partition虚拟表会把这些记录合并呈现。升级注意事项虚拟表的内容完全来自 SSTable 中保存的LargeDataRecords元数据而旧版本写入的 SSTable 并不包含这份元数据。因此特性启用后在那些旧 SSTable 被 compaction 重写之前虚拟表可能显示为空。为了让虚拟表尽快展示数据官方文档建议在每个节点上执行以下操作之一方式一Upgrade SSTables compaction推荐—— 立即重写 SSTable无需等待常规 compaction 触发条件nodetool upgradesstables --include-all-sstables方式二Major compaction—— 把所有 SSTable 重写为一组新的 SSTable但可能临时增加磁盘占用nodetool compact一旦 SSTable 被重写完成虚拟表就会显示当前的大数据记录。需要权衡的是major compaction 会一次性合并全部 SSTable磁盘峰值占用更高upgradesstables只做逐文件重写、保留原有分层结构对磁盘占用更友好因此文档将其列为推荐方案。延伸从发现到治理的完整链路大分区表只是发现问题的第一步。定位到大分区后官方还提供了配套的深入排查指南 docs/troubleshooting/debugging-large-partition.rstLarge Partitions Hunting帮助进一步分析分区为何膨胀、如何拆分分区键partition key设计来避免热点。仓库中还有同族的system.large_rows/system.large_cells排查文档 docs/troubleshooting/large-rows-large-cells-tables.rst分别针对超大单行与超大单元格/集合。从代码与测试的角度本主题还有两层证据可供深入Guardrail 实现软/硬限制的完整检查路径replica 侧基于 SSTable 元数据索引的check()coordinator 侧直接检查 mutation 内容的check_coordinator()都实现在 db/large_data_handler.hh 的large_data_guardrail中每张表持有一个large_data_record_index索引所有存活 SSTable 的大数据记录测试覆盖仓库中的相关测试可作行为参考例如 test/cqlpy/test_large_data_guardrail.py、test/cqlpy/test_bypass_large_data_guardrails.py 以及 test/cqlpy/test_large_data_guardrail_cql_warnings.py 等覆盖了阈值触发、软/硬限制差异与 CQL 警告返回等场景。小结system.large_partitions是定位大分区的入口查询是节点本地的需逐节点执行记录条件是单 SSTable 内分区大小 1000MB 或行数 100000默认值可在scylla.yaml调整且只在写入/flush/compaction 过程中被检测到记录带 30 天 TTL并随 SSTable 的删除/改名自动维护ScyllaDB 2026.2 起该表变为虚拟表数据直接来自 SSTable 的LargeDataRecords元数据每个 SSTable 每种类型默认保留 Top-10 条记录升级到虚拟表后若旧 SSTable 尚未重写虚拟表可能为空可在每个节点执行nodetool upgradesstables --include-all-sstables推荐或nodetool compact加速填充。掌握这套机制后你就能在集群出现 shard 延迟不均或 oversized allocation 告警时快速定位大分区、判断其规模并借助配置阈值与升级方案完成系统性的治理。【免费下载链接】scylladbNoSQL data store using the Seastar framework, compatible with Apache Cassandra and Amazon DynamoDB项目地址: https://gitcode.com/GitHub_Trending/sc/scylladb创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考