ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

ScyllaDB SSTable 3.x 格式全解析:从 sstable_format 参数到数据文件、索引与统计的磁盘布局

ScyllaDB SSTable 3.x 格式全解析:从 sstable_format 参数到数据文件、索引与统计的磁盘布局 ScyllaDB SSTable 3.x 格式全解析从 sstable_format 参数到数据文件、索引与统计的磁盘布局【免费下载链接】scylladbNoSQL data store using the Seastar framework, compatible with Apache Cassandra and Amazon DynamoDB项目地址: https://gitcode.com/GitHub_Trending/sc/scylladbScyllaDB 在 3.x 系列中采用了与 Apache Cassandra 3.0 完全一致的 SSTable 格式同时在此基线上发展出md、me、ms、mt等多个变体。本文以 docs/architecture/sstable/sstable3/sstable-format.rst 为主线结合该目录下的数据文件、索引、统计、摘要等配套格式文档与仓库源码系统讲解 3.x SSTable 的格式变体选择、组件文件构成、磁盘二进制布局以及升级迁移路径帮助读者掌握从scylla.yaml配置到单个字节如何落盘的完整知识链。与 Cassandra 3.0 的兼容性SSTable 可直接迁移ScyllaDB 对 3.x SSTable 格式的支持原则很明确与 Apache Cassandra 3.0 的 SSTable 格式保持一致。这意味着一个非常实用的操作路径是将 Cassandra 数据目录中的 SSTable 文件直接放入 ScyllaDB 的 uploads 目录执行nodetool refresh命令即可把数据摄入到对应表中无需任何格式转换。这种兼容性让从 Cassandra 到 ScyllaDB 的数据迁移、以及两个系统之间共享数据文件成为可能。不过仔细观察会发现一个关键差异ScyllaDB 维护的 SSTable 数量更多、单个文件更小。原因在于 ScyllaDB 采用 Seastar 框架的 shared-nothing 架构每个 CPU 核shard独立管理自己的一份 SSTable 子集。这种内部 sharding 让每个核可以高效地独立工作避免了多核竞争同一份数据所带来的复杂性和延迟——这正是 sstable-format.rst 所强调的 ScyllaDB 与 Cassandra 在文件组织层面的本质区别。SSTable 格式变体ms / me / mdScyllaDB 3.x SSTable 通过scylla.yaml中的sstable_format参数选择格式变体共有三种值说明ms引入基于 Trie 的 SSTable 索引见 sstable-ms-index.rst是 2026.2 起的新默认格式me3.x 基线格式从 ScyllaDB 2022.2 到 2026.1 的默认格式md更早的 3.x 变体仅用于从既有md集群升级的场景将sstable_format设置为md时该参数会被忽略从源码角度这些版本被完整定义在 sstables/version.hh 中enum class sstable_version_types { ka, la, mc, md, me, ms, mt }; constexpr std::arraysstable_version_types, 7 all_sstable_versions { sstable_version_types::ka, sstable_version_types::la, sstable_version_types::mc, sstable_version_types::md, sstable_version_types::me, sstable_version_types::ms, sstable_version_types::mt, }; constexpr std::arraysstable_version_types, 5 writable_sstable_versions { sstable_version_types::mc, sstable_version_types::md, sstable_version_types::me, sstable_version_types::ms, sstable_version_types::mt, }; constexpr sstable_version_types oldest_writable_sstable_format sstable_version_types::mc;可以看到虽然 ScyllaDB 能够读取ka、la等更古老的历史版本all_sstable_versions共 7 项但可写入版本仅限mc起的 5 个。字符串与版本的映射关系位于 sstables/sstables.ccversion_from_string()与format_from_string()两个解析函数也在同文件实现sstables.cc。值得注意的是 sstables.cc 中的这一行bool has_summary_and_index(sstable_version_types v) { return v ! sstable_version_types::ms v ! sstable_version_types::mt; }它揭示了ms/mt与me/md最根本的结构差异ms和mt不再使用传统的 Index.db 与 Summary.db 组件而是以基于 Trie 的索引组件Partitions.db 与 Rows.db取而代之。当前仓库中的默认配置在本仓库的默认 conf/scylla.yaml 中可以看到如下配置与注释# sstable format version for newly written sstables. # Currently allowed values are me and mt. # If not specified in the config, this defaults to me. # # The difference between me and mt are the data structures used # in the primary index. # In short, mt needs more CPU during sstable writes, # but should behave better during reads, # although it might behave worse for very long clustering keys. # # mt sstable format works even better with column_index_size_in_kb set to 1, # so keep those two settings in sync (either both set, or both unset). sstable_format: mt column_index_size_in_kb: 1这里有两个值得注意的实操点sstable_format影响的是新建SSTable 的格式不会重写已有文件mt与column_index_size_in_kb: 1建议成对设置——更细的索引粒度1 KB配合mt的 Trie 索引在读路径上表现更好。升级到 2026.2 的行为根据 sstable-format.rst 的说明升级不会自动重写已有的 SSTable。从旧版本升级到 2026.2 时现有 SSTable 保持原格式这些旧格式 SSTable 会在下一次 compaction 时被升级为ms格式如需立即转换可在更新节点配置后执行nodetool upgradesstables -a主动触发见 sstable-ms-index.rst。3.x SSTable 的组件文件全景3.x 的 SSTable 从来不是一个孤立的文件而是由一组组件文件共同构成。下表总结了每个组件的作用来源sstables-3-data-file-format.rst文件类型典型文件名描述压缩信息mc-1-big-CompressionInfo.db若启用了压缩则保存压缩算法相关信息数据文件mc-1-big-Data.db存储实际数据校验和mc-1-big-Digest.crc32数据文件的 CRC32 校验和布隆过滤器mc-1-big-Filter.db用于判断特定数据是否可能存在于数据文件中索引mc-1-big-Index.db数据的主索引便于检索统计mc-1-big-Statistics.db关于数据的聚合统计摘要mc-1-big-Summary.db索引文件的抽样可视为粗粒度索引目录mc-1-big-TOC.txt列出当前 SSTable 的所有组件文件文件名中的mc是格式版本前缀mc/md/me等1是 generation 号big表示格式类型format_string映射中big是唯一的格式类型见 sstables/sstables.cc。变体之间的细微差异数据文件本身的磁盘格式对mc、md、me全部适用但三个版本之间存在两个语义层面的修正见 sstables-3-data-file-format.rstmd格式修正了 Statistics 文件中(min|max)_clustering_key字段的语义使其能准确描述 SSTable 中实际存在的聚类前缀范围me格式在 Statistics 文件中新增写入 SSTable 的host_id写节点的 UUID用于限定同样存储在 Statistics 文件中的 commit log replay 位置。从 ScyllaDB 2025.4 起还存在ms-mt格式它是me与 Cassandra 5.0 引入的da格式的混合体——绝大多数组件与me完全相同唯独索引组件Index.db、Summary.db被替换为da使用的基于 Trie 的索引格式Partitions.db、Rows.db。数据文件格式磁盘上的二进制布局设计动机从分区由细胞构成到分区由行构成Cassandra 2.x 的数据文件是一系列分区的序列而分区本质上是一系列细胞cell的序列——每个细胞的名字都由聚类前缀所有聚类列的值加上非主键列名构成。这种设计有两个明显缺陷大量磁盘浪费同一分区内每一行都要在自己的所有细胞名字里重复存储聚类列的值长聚类列下尤为严重解析困难存储引擎必须在不预先知道数量与总大小的情况下自行识别并归组属于同一行的细胞。3.0 格式重新组织了数据每个分区由行row构成行由聚类列值定义行内包含共享该聚类前缀的一批细胞。即从分区 → 细胞变为分区 → 行 → 细胞的三级结构。同时3.0 格式深度依赖表 schema——主键/非主键列、数据类型定宽 vs 变宽、聚类列排序等信息都直接参与编码。三大构建块Building Blocks3.0 格式的磁盘编码大量复用以下三种机制详见 sstables-3-data-file-format.rst可变长整数Varint受 Google Protocol Buffers 内部整数序列化启发占用 1 到 9 个字节数值越小占用越少非常适合大量相对较小的数值增量编码Delta Encoding时间戳、TTL 等值通常很大微秒级 UNIX 时间戳直接以 varint 存储收益有限。因此只完整存储一组对象中的最小时间戳/TTL其余对象存储其与最小值的差值——差值通常小得多能以更少的字节序列化。这些最小值基准来自 Memtable 维护的聚合统计记录最小时间戳、TTL、本地删除时间刷盘时作为增量编码基准并保存在-Statistics.db中可选条目Optional Items部分条目可根据标志位或上下文省略。注意这与 C 的std::optional无关只是格式文档中用来标记可能不出现的约定。分区Partition结构数据文件本质上是连续序列化的分区struct data_file { struct partition[]; };每个分区由头部partition_header、可选的静态行static_row以及一组 unfiltered 对象构成struct partition { struct partition_header header; optionalstruct row static_row; // Has IS_STATIC flag set struct unfiltered unfiltereds[]; };一个关键概念SSTable 中的分区保存的是数据的更新记录mutation而非数据的最终状态。每个分区是一系列按顺序应用的修改插入、更新、删除的集合。unfiltered是按聚类前缀可用clustering_comparator排序的对象它要么是一个行row要么是一个范围墓碑标记range tombstone marker。分区头部Partition Header分区头部格式自 2.x 以来未变struct partition_header { be16 key_length; byte key[key_length]; struct deletion_time deletion_time; };其中deletion_time决定该分区是否整体被删除分区墓碑struct deletion_time { be32 local_deletion_time; be64 marked_for_delete_at; };存活分区的特殊值LIVE (MAX_BE32, MIN_BE64)即字节序列7F FF FF FF 80 00 00 00 00 00 00 00marked_for_delete_at是数据应视为已删除的时间戳通常为 UNIX 纪元以来的微秒数若为MIN_BE64则表示从未标记删除local_deletion_time是墓碑创建时的本地服务器时间戳秒仅在gc_grace_seconds过后用于清理墓碑。行Row结构struct row { byte flags; optionalbyte extended_flags; // only present for non-static rows optionalstruct clustering_block[] clustering_blocks; varint row_body_size; varint prev_unfiltered_size; // for backward traversing optionalstruct liveness_info liveness_info; optionalstruct delta_deletion_time deletion_time; optionalvarint[] missing_columns; cell[] cells; };第一字节flags是以下标志的按位或标志值含义END_OF_PARTITION0x01分区结束其后不再有内容IS_MARKER0x02编码的 unfiltered 是标记而非行HAS_TIMESTAMP0x04行有时间戳liveness_info 非空HAS_TTL0x08行有 TTL / 过期信息HAS_DELETION0x10行有删除信息HAS_ALL_COLUMNS0x20行包含头部中的全部列HAS_COMPLEX_DELETION0x40至少一个复杂列有整体删除EXTENSION_FLAG0x80后续还有一个字节的扩展标志若设置EXTENSION_FLAG紧跟的extended_flags字节是以下标志的按位或标志值含义IS_STATIC0x01行是静态行HAS_SHADOWABLE_DELETION_CASSANDRA0x02Cassandra 的可影墓碑标志已废弃ScyllaDB 不支持遇到会拒绝加载HAS_SHADOWABLE_DELETION_SCYLLA0x80ScyllaDB 专用标志表示存在可影墓碑每个分区最多有一个静态行若存在则位于所有其他行与范围墓碑标记之前并设置EXTENSION_FLAG与IS_STATIC静态行按定义不含任何聚类信息。聚类块Clustering Blocks非静态行带有一组聚类块表示各聚类列的值struct clustering_block { varint clustering_block_header; simple_cell[] clustering_cells; };编码方式为将所有聚类列按每批 32 个最后一批可以少于 32分组对批内每个列用 64 位整数中的 2 个 bit 编码其细胞是否为 null 或 empty高位置位表示 null低位置位表示 empty。null表示该列在当前行没有值empty表示值存在但为空如text/blob类型的零长度。行的聚类细胞永远不会是null但这种编码同样用于范围墓碑标记其中聚类细胞可能只有前缀。聚类块的数量不存储在数据文件中——可以从 schema 直接推导。尺寸与前向/后向遍历聚类块之后以varint存储序列化行的大小即最后一个聚类块之后的字节到下一个unfiltered的flags字节不含之间的字节数。下一个varint是前一个 unfiltered的大小可能是行或范围墓碑标记用于支持向后遍历。Liveness 信息与删除信息liveness_info在HAS_TIMESTAMP标志存在时出现struct liveness_info { varint delta_timestamp; optionalvarint delta_ttl; optionalvarint delta_local_deletion_time; };它用于区分死行无活细胞且主键 liveness 为空与活行但所有非主键列为 null无活细胞但主键 liveness 非空。可以把它理解为 2.x 数据格式中 CQL row marker 的改进版——只作用于主键列不影响行内容。时间戳、TTL 与本地删除时间都以上文所述的 delta 编码存储基准来自 Memtable 统计的最小值。对于死行标记或已过期的 liveness 信息TTL 使用特殊值 -1。若行被删除HAS_DELETION则存储 delta 编码的删除时间注意字段顺序与分区头部相反struct delta_deletion_time { varint delta_marked_for_delete_at; varint delta_local_deletion_time; };可影墓碑Shadowable TombstonesCassandra 每行只维护一个墓碑若其可影则设置HAS_SHADOWABLE_DELETION_CASSANDRA。由于 Cassandra 的可影删除支持存在已知问题ScyllaDB 在常规墓碑之外额外维护一个独立的可影墓碑——即 ScyllaDB 写入的 SSTable 中一行最多可以有两个墓碑。若第二个墓碑存在则设置 ScyllaDB 专用扩展标志HAS_SHADOWABLE_DELETION_SCYLLA0x80。注意Cassandra 不认识这个标志会将这些文件视为无效。之所以安全是因为可影墓碑只可能出现在物化视图Materialized Views表中而物化视图表本就不应在 ScyllaDB 与 Cassandra 之间导出导入。缺失列编码Missing Columns Encoding若未设置HAS_ALL_COLUMNS则missing_columns字段编码缺失列的索引。需要理解的是HAS_ALL_COLUMNS并不要求行包含表 schema 中的全部列而是指行包含当前 Memtable 中被填充过的列的超集。例如表有 5 个非聚类列 a–eMemtable 中所有记录只填充了 a、b、c那么一行只要包含 a、b、c 就会设置HAS_ALL_COLUMNS。这个已填充列超集信息同样保存在-Statistics.db中。编码策略针对列集合大小做了优化超集列数 64用 64 位整数作位图为缺失列置位整体存为一个varint超集列数 ≥ 64先写超集列数与当前行列数之差varint再根据当前行列数是否小于超集一半决定编码存在列还是缺失列的索引——总是编码数量更少的一方。因此字段名虽叫missing_columns实际存的可能是存在列索引但无论如何都可以还原出缺失列列表。简单细胞与复杂细胞任何非聚类列要么是简单列每行最多关联一个细胞要么是复杂列可关联任意数量细胞目前复杂列即非冻结集合non-frozen collection。所有聚类列都是简单列。由于已经编码了填充列信息每个细胞按定义非 null但仍可能 empty。简单细胞布局struct simple_cell : cell { byte flags; optionalvarint delta_timestamp; optionalvarint delta_local_deletion_time; optionalvarint delta_ttl; optionalcell_path path; // only in cells nested into complex_cells optionalstruct cell_value value; };flags字节的标志标志值含义IS_DELETED_MASK0x01细胞是墓碑IS_EXPIRING_MASK0x02细胞会过期HAS_EMPTY_VALUE_MASK0x04细胞值为空墓碑尤其如此USE_ROW_TIMESTAMP_MASK0x08细胞时间戳与所属行相同USE_ROW_TTL_MASK0x10细胞 TTL 与所属行相同IS_DELETED_MASK与IS_EXPIRING_MASK互斥。细胞时间戳、删除时间、TTL 在不同于行值对应掩码未设置时才单独存储为 delta varint。值本身分定宽与变宽两类编码定宽类型int、boolean等无需存储长度长度可从 schema 推导变宽类型text、blob等则需前缀长度struct cell_value { optionalvarint length; byte value[]; };复杂细胞是多个简单细胞的容器用cell_path区分struct complex_cell : cell { optionalstruct delta_deletion_time complex_deletion_time; varint items_count; struct simple_cell[items_count]; };complex_deletion_time表示对整个复杂细胞如整个集合的删除其存在与否由行的HAS_COMPLEX_DELETION标志决定——注意该标志只要任一复杂列有整体删除就会被置位因此实际会为所有复杂列写出该字段目前cell_path唯一实现是集合list 用自动生成的timeuuidmap 用当前 map keyset 用实际值此时complex_cell_item.value为空。范围墓碑标记Range Tombstone Marker范围墓碑覆盖一片/一段行。自 3.0 起它们以成对的标记存储——一个开始标记加一个结束标记因此每个墓碑对应两个有序的unfiltered。这种设计简化了合并按聚类前缀排序后开始标记一定位于被覆盖行之前结束标记位于其后。读取器遍历时只需维护至多一个范围墓碑删除标记若已填充则其后的行都被视为已删除直到遇到结束标记。标记分为两种range_tombstone_bound_marker表示单个边界range_tombstone_boundary_marker表示两个相邻范围墓碑之间的分界编码为开结束、闭开始类型既省磁盘1 个标记代替 2 个又简化合并逻辑。布局如下struct range_tombstone_marker { byte flags IS_MARKER; byte kind_ordinal; be16 bound_values_count; struct clustering_block[] clustering_blocks; varint marker_body_size; varint prev_unfiltered_size; };kind_ordinal取bound_kind枚举的序号enum class bound_kind : uint8_t { EXCL_END_BOUND 0, INCL_START_BOUND 1, EXCL_END_INCL_START_BOUNDARY 2, STATIC_CLUSTERING 3, CLUSTERING 4, INCL_END_EXCL_START_BOUNDARY 5, INCL_END_BOUND 6, EXCL_START_BOUND 7 };bound marker 取 {0, 1, 6, 7} 之一boundary marker 取 2 或 5。与行不同范围墓碑标记必须存储聚类前缀中的非 null 列数bound_values_count因为其尾部列可以为 null——而行总是完整前缀长度从 schema 推导。bound marker 带一个 delta 编码的deletion_timeboundary marker 则带两个end 与 start 各一个。索引文件格式从 Index.db 到 promoted index三层检索路径SSTable 的索引文件与摘要文件共同构成高效定位机制详见 sstables-3-index.rstSummary.db常驻内存保存索引键的抽样指向索引文件中的位置区间Index.db按序列出数据文件中的键及其位置Data.db实际数据。搜索一个键时先用 Summary 定位索引文件中可能含该键的相对较短的区间再读取该区间并查找具体键。索引条目索引文件是条目的长序列struct index_file { struct index_entry entries[]; }; struct index_entry { be16 key_length; char key[key_length]; varint position; // decoded into a 64-bit integer varint promoted_index_length; // decoded into a 32-bit integer byte promoted_index[promoted_index_length]; };key是分区键position是分区在数据文件中的位置。与 2.x 相比3.0 索引文件的主要变化是新增了offsets数组与end_open_marker结构。Promoted Index提升索引对于大分区仅靠起始位置无法高效定位列区间因此会附带所谓的promoted index按column_index_size_in_kb默认 64 KB为粒度对分区采样为每个块给出聚类前缀范围。promoted 之名源于历史它最初是独立存储的列索引在 Cassandra 1.2 时被提升进索引文件内部使定位一列所需的 seek 从 3 次降为 2 次。promoted_index_length为该字段之后到当前index_entry末尾的字节数为 0 表示无 promoted index。struct promoted_index { varint partition_header_length; // decoded into a 64-bit integer struct deletion_time deletion_time; varint promoted_index_blocks_count; // decoded into a 32-bit integer struct promoted_index_block blocks[promoted_index_blocks_count]; be32 offsets[promoted_index_blocks_count]; };partition_header_length是数据文件中分区键、分区墓碑及静态行若有的序列化长度可让读取器直接跳过分区前缀跳到第一行deletion_time是分区deletion_time的副本无论存活还是墓碑。之所以在索引中保留副本是因为借助 promoted index 我们可能直接跳到超大分区的中间此时不希望再读分区开头来获取分区墓碑promoted_index_blocks_count可为 0小分区或 ≥ 2存储单个块没有意义。每个 promoted index 块struct promoted_index_block { struct clustering_prefix first_name; struct clustering_prefix last_name; varint offset; varint delta_width; byte end_open_marker_present; optionalstruct deletion_time end_open_marker; };first_name/last_name是块边界聚类列前缀。其clustering_prefix结构首字节kind是bound_kind枚举序号4CLUSTERING表示对应行0/1/2 表示范围墓碑标记size仅对范围墓碑标记出现kind ! 4因为行的聚类前缀总是完整的、数量可由 schema 推导offset是块相对当前分区在数据文件中的起始位置的偏移width是当前 promoted index 块在索引文件中长度的 delta 编码值。基值为column_index_size_in_kb配置默认 64 KB 65536该基值不随文件存储、恒等于 65536。由于实际块大小可能小于 64 KBdelta 可能为负因此该值应按有符号处理end_open_marker_present是布尔字节指示是否序列化后面的end_open_marker。当当前块在数据文件中对应的 unfiltered 区间包含一个范围墓碑开始标记、但其配对结束标记落在块外时该结构存在此时块的结束边界落在两个范围墓碑标记之间取INCL_START_BOUND或EXCL_END_INCL_START_BOUNDARY类型的范围墓碑标记并携带该开放边界的删除时间。读取器读取切片时若只遇到结束标记而没有开始标记就会用end_open_marker中的删除时间合成对应切片起始边界的开始标记——这保证了迭代器式读取永远看到成对的标记最后的offsets数组与promoted_index_blocks_count等长第一个偏移恒为 0其余为各块相对promoted_index.blocks起点的偏移。它可以脱离整个 promoted index 单独读取从而支持对 promoted index 做二分查找把搜索复杂度从 O(N) 降到 O(log N)。column_index_size_in_kb的默认值及注释可在 conf/scylla.yaml 中看到。统计文件格式Statistics.db 的四种元数据Statistics 文件保存 SSTable 的元数据共四类详见 sstables-3-statistics.rstValidation metadata校验元数据类型 0——用于校验 SSTable 正确性包含创建该 SSTable 的分区器名称modified UTF-8 编码字符串与布隆过滤器误判概率bloom_filter_fp_chancebe64 doubleCompaction metadata压缩元数据类型 1——序列化的 HyperLogLogPlus用于估算 SSTable 分区键数量缺失时可用 Summary 文件推算Statistics统计类型 2——加载到内存、用于加速读取与压缩的信息Serialization header序列化头类型 3——保存 SSTable 的 schema 信息。文件由两部分构成先是目录表TOC按type字段排序每项含typebe32 整数与offsetbe32该元数据在文件中的起始偏移随后是按顺序排列的元数据条目。Statistics 条目包含的关键字段partition_sizes与column_countsEstimatedHistogram前者统计分区未压缩大小字节后者统计每分区细胞数commit_log_upper_bound/commit_log_lower_boundCommitLogPositionsegment_id 段内位置用于限定数据的 commit log 回放位置min_timestamp/max_timestamp数据最小/最大时间戳通常为 UNIX 纪元以来的微秒数min_local_deletion_time/max_local_deletion_time秒min_ttl/max_ttlcompression_rate压缩率 压缩后大小 / 未压缩大小tombstones细胞墓碑直方图StreamingHistogram键为墓碑的本地删除时间levelSSTable 的 LCS 层级repaired_at最近修复时间相对 1970-01-01 的毫秒差min_clustering_key/max_clustering_keySSTable 中存在的聚类键前缀最小/最大值自md格式起语义有效。注意聚类行总是完整聚类键范围墓碑可能有部分前缀分区墓碑隐式覆盖整个无界聚类范围因此空前缀表示无界范围has_legacy_counters、number_of_columns、number_of_rowscommit_log_intervals提交日志区间数组版本 MB 起host_id写入节点的 UUID版本 MC/MD 起用于限定文件中所有 commit log 位置——这正是me格式引入的字段。序列化头serialization header保存 schema 相关信息min_timestamp、min_local_deletion_time、min_ttlvint、分区键类型单列时为该列类型否则为 CompositeType、聚类键类型数组、静态列与常规列的列表每列含列名与类型。类型编码为带 vint 长度前缀的 UTF-8 字节串跳过前导空白第一段非空白字符为类型名若不含.则自动前缀org.apache.cassandra.db.marshal.随后从该类取 instance 静态字段若类型名后紧跟(则调用getInstance静态方法并传入剩余字符串作为参数。文档列出了 Ascii、Boolean、Bytes、Composite、CounterColumn、Date、Decimal、Double、Duration、Float、Frozen、InetAddress、Int32、Integer、List、Long、Map、Reversed、Set、Short、SimpleDate、Timestamp、Time、TimeUUID、Tuple、User、UTF8、UUID、Vector 等类型及其是否参数化。摘要文件格式Summary.db 的粗粒度索引Summary 文件保存键的抽样用于检索的第一阶段详见 sstables-3-summary.rst。每个 summary 条目指向索引文件中一页index page条目从而只需读取并搜索索引的一小部分。摘要文件设计为整体常驻内存因此必须足够小这带来摘要大小与索引页基数每页覆盖的索引条目数之间的权衡——抽样级别sampling level负责调节该平衡。3.0 的 Summary 格式与 2.0 相比变化极小唯一明显变化是不再存储段边界信息。与数据、索引文件不同Summary 文件不使用可变长整数struct summary { struct summary_header header; struct summary_entries_block summary_entries; struct serialized_key first; struct serialized_key last; };头部字段min_index_intervalbe32索引摘要条目之间平均分区数的下界值越小、满采样时进入摘要的分区越多entries_countbe32offsets与entries的个数summary_entries_sizebe64summary_entries结构的完整大小sampling_levelbe321 到BASE_SAMPLING_LEVEL128之间的值表示保留了多少原始摘要条目即(samplingLevel / BASE_SAMPLING_LEVEL) * ((1 / indexInterval) * numKeys)size_at_full_samplingbe32若抽样级别等于min_index_interval时摘要应有的条目数。条目块由offsets数组与entries数组组成struct summary_entries_block { uint32 offsets[header.entries_count]; struct summary_entry entries[header.entries_count]; }; struct summary_entry { byte key[]; // variable-length. be64 position; };offsets从summary_entries_block起点计算offsets[0] sizeof(uint32) * header.entries_count。注意 offsets 使用本机字节序ScyllaDB 中总是小端这与 SSTable 其他文件统一大端的惯例不同——其目的是与常见小端机器上 Cassandra 写出的 Summary 文件、以及罕见大端机器上 ScyllaDB 写出的文件互操作。summary_entry不存储键长度可从 offsets 推导最后一个条目的长度由它的 offset 与summary_entries_size计算。结构末尾的first/last是serialized_keybe32 长度 键字节保存索引/数据文件中的第一个与最后一个键。ms 格式基于 Trie 的索引ms格式详见 sstable-ms-index.rst用基于 Trie 的分区索引取代了me/md沿用的 Cassandra 3.0 索引格式带来的收益包括更低的内存占用——每个 SSTable 的常驻索引数据更少更快的分区查找——索引遍历更高效更小的磁盘索引文件——共享键前缀减少了冗余存储。配置方式分两种场景新集群2026.2 及以后ms是默认sstable_format无需额外配置升级集群沿用scylla.yaml中既有格式若要切换为ms在 conf/scylla.yaml 中加入sstable_format: ms更新节点配置后新建的 SSTable 即使用ms格式已有 SSTable 不会自动转换而是在下一次 compaction 时重写为ms也可用nodetool upgradesstables -a主动触发转换。小结格式选择与运维要点回到本文的核心问题——如何理解并选用 3.x SSTable 格式兼容性3.x 格式与 Cassandra 3.0 一致SSTable 可直接从 Cassandra 目录迁移到 uploads 目录并nodetool refresh摄入变体选择sstable_format决定新建文件的格式——md是历史升级专用设置会被忽略me是 2022.2–2026.1 的基线ms自 2026.2 起成为默认mt是仓库默认配置中使用的 Trie 索引变体conf/scylla.yaml升级路径旧格式文件不会自动重写将在下次 compaction 时升级为ms或用nodetool upgradesstables -a主动转换组件体系一个 SSTable 由 Data、Index、Summary、Filter、Statistics、Digest、CompressionInfo、TOC 等组件构成ms/mt用 Trie 索引组件Partitions.db、Rows.db取代 Index.db 与 Summary.db源码见 sstables/sstables.cc磁盘布局数据文件的核心是 varint delta encoding optional items 三件套以及分区 → 行 → 细胞的三级模型索引文件通过 promoted index 与 offsets 数组把大分区内定位复杂度降到 O(log N)。进一步的格式细节可继续阅读本目录下的配套文档数据文件格式、索引文件格式、统计文件格式、摘要文件格式 与 ms Trie 索引并在 sstables/ 目录下的源码中对照实现。【免费下载链接】scylladbNoSQL data store using the Seastar framework, compatible with Apache Cassandra and Amazon DynamoDB项目地址: https://gitcode.com/GitHub_Trending/sc/scylladb创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表