-
Notifications
You must be signed in to change notification settings - Fork 8
Easy Migrate Without Code Change
ToplingDB 从 RocksDB fork 而来。为了降低开发成本、避免生态分裂、与 RocksDB 社区共同繁荣,ToplingDB 尽可能最小化对 RocksDB 代码的修改。为此 ToplingDB 设计了"旁路插件化"(Side Plugin)体系,通过 Factory/Product 类的动态注入机制引入第三方实现,将新增代码放在 RocksDB 原有代码之外。其设计动机和架构思路在 Wiki: Motivation To Solution 中有详细阐述。
一个典型的配置文件(如 mytopling.json)包含了数十个模块的定义:
- 插件与扩展:支持在配置或产品中接入自定义比较器、表格式、MemTable、合并算子、Compaction 过滤等,详见 Wiki: AnyPlugin 与 CompactionFilterFactory As SidePlugin
- 高级存储引擎:CSPP MemTable(Crash Safe Parallel Patricia Trie,写并发性能超过 SkipList 30 倍)、ToplingZipTable(CO-Index + PA-Zip 实现内存高压缩)、SingleFastTable(零压缩、最高性能)、DispatcherTable(LSM 各层可配置不同的 TableFactory)
- 分布式 Compact:把压缩卸载到远程 worker 集群,详见 Wiki: Distributed Compaction
- 进程内嵌 WebView:内置 HTTP 服务器,提供可观测性 Dashboard,详见 Wiki: WebView
- Prometheus 监控:Statistics 模块支持 Prometheus 指标暴露,可接入 Grafana Dashboard,详见 Wiki: Grafana 展示
- 在线热更新:通过网页提供的配置入口调整库级 / 列族级可变参数,Dyna MemTable 等可在 SkipList 与 CSPP 等实现间切换,无需重启进程
-
配置模板:通过
${var}引用和${template}继承,复用配置片段,详见 Wiki: Template Object
这是 ToplingDB 功能最完整的使用方式,需要编写一份结构完整的配置文件,并熟悉 Topling 特有组件的含义与参数。新项目建议直接采用程序内的 SidePluginRepo(完整集成),从零教程见 Wiki: 101 - 从零开始使用 ToplingDB。已有 RocksDB 存量则可用下文 Easy Migrate:代码零修改,只需要把编译依赖改成 ToplingDB,即可实现迁移。
为了降低迁移成本,ToplingDB 引入了环境变量 TOPLINGDB_EASY_MIGRATE_CONF。
用户只需设置这个环境变量指向 JSON 或 YAML 配置文件;代码零修改,只需要把编译依赖改成 ToplingDB,在配置里启用相应组件后,即可获得 ToplingDB 的全部性能改进——例如 CSPP MemTable、ToplingZipTable、DispatcherTable 等(具体启用哪些仍取决于你的 YAML/JSON)。
export TOPLINGDB_EASY_MIGRATE_CONF=/path/to/easy_conf.json这个 easy conf 与 SidePluginRepo / 完整集成所用配置文件格式完全相同,只设环境变量即可生效,对应用程序透明。
配置里启用 http.auto_start_http 后,进程加载 Easy Migrate 配置时会按需启动与 WebView 相同的内置Web服务;照常使用数据库即可(只读、辅助副本等用法都算在内),已在跑的实例会自动出现在 Web 面板中按库名浏览,无需为运维面板再写集成代码。具体写法见下文 内置Web(可选)。
- 新项目:优先使用 SidePluginRepo(完整集成)——在进程内加载配置、管理数据库生命周期,并与多库编排、多语言 Binding 等自然配合;入门见 Wiki: 101、总览见 Home。
-
已有 RocksDB 存量:用 Easy Migrate,设
TOPLINGDB_EASY_MIGRATE_CONF,代码零修改、只需要把编译依赖改成 ToplingDB;Web 面板、监控、在线改配置、本文按库路径选配置等,仍靠同一份 JSON/YAML 打开即可。
两种方式的配置文件格式相同。启动阶段若要把自有比较器、表格式、MemTable、合并策略、Compaction 过滤 等接入 Topling,按 AnyPlugin 等专题文档做即可,与是否 Easy Migrate 无冲突;接好后只要远端 Compact 集群能消费同一套配置语义,还可同时开 分布式 Compact。
存量里若仍要在不改业务主路径的前提下,把已在跑的实例手工挂进 SidePluginRepo 做编排,可参考 Wiki:复杂场景集成迁移——这是遗留集成的补救写法,不替代「新项目优先 SidePluginRepo」。
Easy Migrate 的配置文件与 SidePluginRepo / 完整集成 所用格式完全相同,将来若要改成程序内托管 SidePluginRepo,同一份文件可直接复用。需要自定义 Compaction 过滤、分布式 Compact 等时,按对应 Wiki 操作即可,与 Easy Migrate 不互斥(前提仍是 worker 与配置语义一致)。
配置中的 DBOptions/CFOptions 部分同样可以引用配置文件中定义的其他组件(如插件):DBOptions.write_buffer_manager 引用顶层 WriteBufferManager 模块实例;CFOptions.memtable_factory、CFOptions.table_factory 可分别接入 Topling CSPP MemTable(MemTableRepFactory)与 DispatcherTable(先在 TableFactory 里定义具名条目,再在列族选项里引用)。sample-conf/db_bench_enterprise.yaml 集中给出了 WriteBufferManager、cspp、dispatch 等与上述字段配套的完整写法,可作为 WriteBufferManager / CSPP / DispatcherTable 引用方式的权威示例;同目录下其他 db_bench_*.yaml 亦可对照阅读(支持 JSON/YAML 双格式,详见 Wiki: Yaml File)。
与完整集成相同,配置文件顶层可写 http(document_root、listening_ports 等见 Home 与 WebView)。与业务相关的行为如下:
-
http.auto_start_http:仅在为 true 时,加载 Easy Migrate 配置后会自动启动内置Web服务;为 false 或未写则不监听端口,避免无意中对外暴露运维入口。语义与「通过配置文件拉起整套 Topling 服务」时一致。 - 谁在 Web 面板里可见:照常使用数据库(只读、辅助副本等均可),实例会自动出现在 Web 面板中,无需为了让面板认出库而去改业务代码。若你用的是 SidePluginRepo 完整集成,还可以在仓库侧主动登记实例;新项目建议走这条。存量补救写法见 Wiki:复杂场景集成迁移。
示例(节选,YAML):
http:
document_root: /dev/shm/mydb_web
listening_ports: '2011'
auto_start_http: true # 为 true 时才自动启动内置Web下列 YAML 为节选;WriteBufferManager / MemTableRepFactory(CSPP)/ TableFactory(DispatcherTable)的完整定义与参数请对照 db_bench_enterprise.yaml。
# MemTableRepFactory / TableFactory / WriteBufferManager 的完整示例见上方链接的 db_bench_enterprise.yaml
MemTableRepFactory:
cspp:
class: cspp
params:
mem_cap: 1G
TableFactory:
fast:
class: SingleFastTable
params:
indexType: MainPatricia
keyPrefixLen: 0
zip:
class: ToplingZipTable
params:
localTempDir: /dev/shm
sampleRatio: 0.01
dispatch:
class: DispatcherTable
params:
default: fast
readers:
SingleFastTable: fast
ToplingZipTable: zip
level_writers: [fast, fast, zip, zip, zip, zip, zip, zip]
WriteBufferManager:
wbm:
class: WriteBufferManager
params:
buffer_size: 2560M
DBOptions:
default:
write_buffer_manager: "${wbm}" # → 顶层 WriteBufferManager(本文件中的 wbm)
max_background_compactions: 32
max_subcompactions: 1
max_background_flushes: 2
max_total_wal_size: 5G
allow_mmap_reads: false
manual_wal_flush: true
two_write_queues: true
CFOptions:
default:
memtable_factory: "${cspp}" # Topling CSPP MemTable(MemTableRepFactory),见本节上文 Wiki: ToplingCSPPMemTab
table_factory: dispatch # DispatcherTable(引用 TableFactory.dispatch),见本节上文 Home / DispatcherTable 链接
num_levels: 7
write_buffer_size: 2560M
max_write_buffer_number: 4
target_file_size_base: 32M
level_compaction_dynamic_level_bytes: true
disable_auto_compactions: true迁移时若所有库共用一套参数,在 DBOptions、CFOptions 里各写一个名为 default 的配置块即可(这也是按路径匹配失败时的最终兜底名)。可参考 Sui 链上的极简示例 或仓库 sample-conf。
但这里有一个根本问题:
当同一进程或同一台机器里跑着多个路径不同的 DB 实例时,如何让它们各取所需的配置?
答案就在命名空间解析机制中。
下面三个实例路径不同,却很典型——要么在同一进程里各开一个 DB,要么分布在同一批节点上:
/data/order/prod/orders/db
/data/order/prod/items/db
/data/analytics/prod/metrics/db
负载不同,往往需要差异化的 DBOptions(库级) 与 CFOptions(列族级) 组合(不必死记每一项落在哪一类,只需知道两类都可能要调):
-
orders/db(路径后缀):写量大——常见会调大 MemTable / write buffer 等(多在 CFOptions),以及后台 compaction 并行度等(多在 DBOptions)。 -
items/db:读多写少——常见会偏向更快的 SST / 表格式与块相关参数(多在 CFOptions)。 -
metrics/db:批量导入——常见会偏向吞吐与 compaction 策略(CFOptions / DBOptions 都可能涉及)。
在传统接入里,这类差别往往靠应用代码按路径分支组装 Options。Easy Migrate 则把这些意图写进一份全局 JSON/YAML:进程里每个实例照常各自打开库,但都从同一文件里按自己的库路径解析该用的段落(再配合列族名维度的规则,见 §五)。
于是需要一套规则:只靠路径字符串(以及 CF 名),就能稳定区分实例;同时又要支持「后缀相同、前缀不同的一批实例默认共用同一段」(见下)。
典型意图:同一进程里按路径做分区或拆业务线时,同一种库形态的路径往往 后缀一致(例如都以 orders/db、items/db 结尾),只是 前缀(挂载根、租户、集群目录等)随分区而变。这时通常希望 后缀相同的多实例共用一套 DBOptions/CFOptions,只维护较短后缀键(如 orders/db)即可;若某一前缀下必须例外,再把 更长的路径限定名(把多出来的前缀段写进键名)单独开一段,依靠「先尝试更长限定名、命中即停止」覆盖默认值。
这种 「共用相同后缀」 的归并与编程语言里按 namespace(命名空间) 解析符号时「由更完全的限定名试到更一般的名字」的习惯 异曲同工——下文也把路径当作命名空间来读。
Easy Migrate 以 代码零修改、只需要把编译依赖改成 ToplingDB 为前提:配置里拿不到「这是订单库」「这是审计库」这类标签,只能靠 引擎已知的库路径 与 ColumnFamily 名称(内置 Default CF 名固定为 "default",见 §五、§六)。路径字符串本身往往已编码了机房、租户、业务线、环境等层级;核心问题就是:如何仅用这一条路径(加上 CF 名),表达你想调的各级意图。
可以把数据库路径理解成由外到内的限定名:路径 左侧多对应分区/业务等可变前缀,右侧后缀多对应「这一类库」的固定形态(见上一段典型意图)。整体上,更长的限定名(含更多左侧段)更「针对某一前缀」,更短的后缀键更「跨前缀共用」。匹配配置时,从整条路径开始试,再层层去掉最左侧的一段,直到命中配置中的某一项——这和「先找带分区前缀的专用名,再回落到仅后缀的共用名」的直觉一致。
例如 /data/order/prod/orders/db 会依次尝试(与下一节步骤表一致)
/data/order/prod/orders/db、data/order/prod/orders/db、order/prod/orders/db、prod/orders/db、orders/db、db,再必要时落到配置块名 default(见下文)。
将路径的每一段映射为一个命名空间层级。例如 /data/order/prod/orders/db 中,data 是最外层,order 和 prod 是嵌套的中间层,orders/db 是最内层的"实体名"。
配置查找从最长限定名开始,沿 §3.3 的规则逐步去掉最左段、得到越来越短的后缀键名依次尝试,直到命中为止。
给定一个路径,查找过程是从左侧逐级剥离路径分量——每次去掉一个最左边的分量(包括根目录 /)。
对于 /data/order/prod/orders/db:
/data/order/prod/orders/db 第 1 步:全路径(最精确)
data/order/prod/orders/db 第 2 步:去掉根目录 /
order/prod/orders/db 第 3 步:去掉 data
prod/orders/db 第 4 步:去掉 order
orders/db 第 5 步:去掉 prod
db 第 6 步:只剩 basename
"default" 第 7 步:以上都不匹配时的最终兜底
为什么从路径左侧缩短,而不是从末尾一层层往上揭?
因为左侧对应部署拓扑的外层(机房、业务线、环境),右侧才是「这一个库」本身。 若从右边删,第一步就去掉了最能区分实例的那段路径,剩下的前缀无法表达「同一业务线下的不同库」这类常见需求。
路径有多少层,命名空间就有多少级。配置可以在任意一个层级上定义。查找总是从最精确的开始,一旦命中就停止。
假设定义了这些配置:
{
"CFOptions": {
"orders/db": {
"write_buffer_size": "2560M",
"max_write_buffer_number": 4
},
"prod/orders/db": {
"target_file_size_base": "64M"
}
}
}追踪 /data/order/prod/orders/db 的 CFOptions 查找(示例 JSON 仅有 CFOptions):
第 1 步:/data/order/prod/orders/db ×
第 2 步:data/order/prod/orders/db ×
第 3 步:order/prod/orders/db × (配置中未定义该键)
第 4 步:prod/orders/db ✓ 命中 target_file_size_base=64M
查找在此停止。orders/db 级别的 write_buffer_size 不会被匹配到,因为查找在 prod/orders/db 就已经停下了。
Easy Migrate 从整条路径对应的限定名开始尝试配置键(每一步去掉路径最左侧一段,等价于依次尝试越来越短的后缀形态键名):第一次命中某个已定义的键后,查找就结束了,更短后缀上的键不会再被尝试,因此也不会与已命中块做「多段路径键之间的字段合并」。这与 §3.1 的意图一致:默认靠较短后缀键跨前缀共用;只有需要按分区/业务前缀例外时,才把更长限定名单独写出来。
这与「更精确的条目挡住外层共用配置」不是一回事:只有落在同一条缩短链上的键才会相互排斥;若某键压根不会出现在该实例的尝试序列里(例如实例路径末尾是 …/orders,链上永远不会出现 orders/db 这一段),则谈不上「被挡住」,只是从未参与查找。
下面示例刻意使用同一路径族 …/orders/db,使 §3.1 所说的「后缀共用」键 orders/db 与 带更多前缀段的专用覆盖键 sensitive/audit/orders/db 出现在同一条查找链上:
跨分区共用的段落写在仅含后缀的 orders/db:
{
"CFOptions": {
"orders/db": {
"write_buffer_size": "256M",
"max_write_buffer_number": 4
}
}
}审计库路径为 /data/sensitive/audit/orders/db,需要在仍保留「同一查找链」的前提下,对这一前缀下的实例单独覆盖少数字段时,在配置键里写出 比共用后缀更长 的限定名 sensitive/audit/orders/db(把分区差异写进键);命中后会提前结束查找,不会再落到跨分区共用的 orders/db:
{
"CFOptions": {
"orders/db": {
"write_buffer_size": "256M",
"max_write_buffer_number": 4
},
"sensitive/audit/orders/db": {
"disable_auto_compactions": true
}
}
}查找 /data/sensitive/audit/orders/db 时,前几步未定义则继续缩短,直到:
/data/sensitive/audit/orders/db ×
data/sensitive/audit/orders/db ×
sensitive/audit/orders/db ✓ 命中 disable_auto_compactions=true
查找在此停止,更短后缀上的 audit/orders/db、orders/db、db 等键都不会再被尝试,故共用后缀键 orders/db 里的 write_buffer_size 不会被合并进来。若既要沿用 orders/db 中多数字段、又要在某一前缀(如审计分区)下少数字段覆盖,应在专用条目里通过 template / ${template} 等机制显式继承共用片段(见 Wiki: Template Object),而不是依赖多次路径命中自动拼在一起。
对任意库路径,每次去掉最左侧一段路径分量(见 §3.3),用得到的字符串依次去配置里找同名 key,总有一档能对上;以 /data/order/prod/orders/db 为例,路径可拆成根 / 与 5 段,查找顺序为:
步骤 配置 key
──────────────────────────────
1 /data/order/prod/orders/db ← 全路径(最精确)
2 data/order/prod/orders/db ← 去掉根目录 /
3 order/prod/orders/db ← 去掉 data
4 prod/orders/db ← 去掉 order
5 orders/db ← 去掉 prod
6 db ← 只剩 basename(最不精确)
7 "default" ← 最终兜底
要为 ColumnFamily 套不同参数时,在路径后面再接 :列族名 按另一套规则试,见下一章。
ColumnFamily 的配置查找比 DBOptions 多一个维度:列族名。说明:RocksDB 每个库都有一个 Default Column Family,引擎约定其列族名固定为 "default",并非业务像给自定义列族那样另行起名。
对某个 CF 名为 mycf 的 ColumnFamily,查找分两级,每级内部先按 与 §3.3 相同的路径后缀链(由长到短)在键名后接 :mycf 尝试,最后再试不带路径的裸名 mycf:
第一级:带 CF 名的配置
依次在 §3.3 路径后缀链的每一档后拼接 :mycf 尝试,最后再试裸名 mycf:
/data/order/prod/orders/db:mycf
data/order/prod/orders/db:mycf
order/prod/orders/db:mycf
prod/orders/db:mycf
orders/db:mycf
db:mycf
mycf ← 裸名兜底
第二级:回退到内置 Default CF 的配置
如果第一级无一命中,且当前列族名 mycf 不是引擎自带的 "default"(即你在查的是业务列族),则用同样的方式再查一遍,把后缀换成 default——这里的 "default" 指的是 Default Column Family 的固定名字,用来继承「默认列族」上的 CFOptions:
/data/order/prod/orders/db:default
data/order/prod/orders/db:default
order/prod/orders/db:default
prod/orders/db:default
orders/db:default
db:default
default ← 裸名兜底
当正在配置的就是 内置 Default CF(名字只能是 "default")时,第一级查找已经走完 §3.3 整条路径后缀链,不应再进入第二级去重复做一次「再回退到 default」。
这样设计允许非常精细的控制粒度——可以为一个特定路径下的特定列族定制参数,也可以让业务列族在缺省配置时沿用同一路径下针对内置 Default CF(名 "default")写好的那一段。
列族的动态创建与删除在完整集成路径中有专门说明,详见 Wiki: Dynamic Create Drop ColumnFamily。
字符串 "default" 在配置文件里会出现三种含义,写键名时不要搞混:
-
DBOptions/CFOptions下的配置块名:表示「没有更细的命中就用这一段」,常用作全局默认。 -
磁盘路径里的一段目录名:例如
/data/prod/default,只是路径字面量。 -
RocksDB 内置 Default Column Family 的名字:引擎固定为
"default",不是业务给自定义列族起的名字。
实操:路径 basename 已是 default 时,不要再叠一层无意义的同名兜底;正在为内置 Default CF写匹配规则时,走完第一级路径 × :default 链即可,不必再「第二次回退到 default CF」。
如果尚在试验阶段或所有实例负载相似,只需定义 "default":
{
"DBOptions": {
"default": {
"max_background_compactions": 8
}
},
"CFOptions": {
"default": {
"write_buffer_size": "2560M",
"max_write_buffer_number": 4
}
}
}所有 DB 实例都匹配到 "default",所有 CF 都匹配到 "default"。这是迁移代价较低的方式:用户只需要写一份配置,设一个环境变量,重启即可。
当需要为不同库形态定制配置时,常用 多段路径尾缀 做键(例如下面的 orders/db、items/db,与 §3.1「后缀共用」一致):
{
"CFOptions": {
"default": {
"write_buffer_size": "256M",
"max_write_buffer_number": 4
},
"orders/db": {
"write_buffer_size": "5120M",
"max_write_buffer_number": 6
},
"items/db": {
"target_file_size_base": "64M"
}
}
}-
/data/any/prefix/orders/db→ 匹配orders/db,获得更大的 MemTable / write buffer(示例里主要靠write_buffer_size与max_write_buffer_number) -
/data/any/prefix/items/db→ 匹配items/db,获得更大的 SST 文件 - 其他所有实例 → 匹配
default,使用标准的 256M MemTable
对于更复杂的部署,可以用 更长的路径限定名(键名里包含更多路径段)区分业务线或中间目录层级,与 §3.1「必要时长限定名覆盖」一致。假设 DB 路径按业务线组织:
/data/order/db/orders/db
/data/order/db/items/db
/data/analytics/db/metrics/db
在路径键中使用包含业务线段的限定名(如下例中的 order/db/…、analytics/db/…),即可让该业务线下的各实例分别命中对应条目:
{
"CFOptions": {
"order/db/orders/db": {
"max_write_buffer_number": 8,
"level_compaction_dynamic_level_bytes": false
},
"order/db/items/db": {
"max_write_buffer_number": 2
},
"analytics/db/metrics/db": {
"disable_auto_compactions": true,
"level_compaction_dynamic_level_bytes": false
}
}
}-
/data/order/db/orders/db的查找链中会命中order/db/orders/db -
/data/order/db/items/db的查找链中会命中order/db/items/db -
/data/analytics/db/metrics/db的查找链中会命中analytics/db/metrics/db
这样不同业务线的实例使用不同的配置,配置集中管理,修改同一份 JSON/YAML 即可影响所有对应的实例。
某审计实例要求完全禁用后台 compaction,且在同一路径查找链上只使用本条精确键(命中后即停止,更短后缀上的键不会再被尝试):
{
"CFOptions": {
"compliance/audit/db": {
"disable_auto_compactions": true,
"level_compaction_dynamic_level_bytes": true
}
}
}配置写在 compliance/audit/db 这一档即可命中 /data/compliance/audit/db。查找命中后即停止,同一条缩短链上更短后缀处的条目不会被读到;若另有写在其他路径形态下的「共用」键,本来就不在该实例的尝试序列里,则与本次命中无关。
有些时候,用户希望某个 DB 或 CF 完全不受 Easy Migrate 配置的影响——实例侧已有既定参数,不希望再被这份全局配置文件覆盖。
利用命名空间解析「命中即停止」的规则,在适当的层级定义一个空对象 {}即可:
{
"DBOptions": {
"special/db": {},
"default": {
"max_background_compactions": 8
}
},
"CFOptions": {
"special/db:mycf": {},
"default": {
"write_buffer_size": "256M"
}
}
}对于路径为 /data/special/db 的实例,查找在 special/db 命中空对象后不再向下合并,库级选项保持命中前的既有行为。该库下的 CF mycf 同理:special/db:mycf 命中空对象后,不会再回落到配置块名 default 下的那段 CF 配置去填充。
- 面板、监控、在线改配置 能不能用,取决于你有没有在 YAML/JSON 里写
http、Statistics 等,以及auto_start_http是否打开,与「是不是 Easy Migrate」无关。 - 开了面板后,进程里正在使用的数据库实例会自动出现在 Web 面板中,一般不必为展示去改代码。
- 自定义插件、分布式 Compact 按专题 Wiki 做。新项目请直接用 SidePluginRepo,见 Wiki: 101;存量若要把实例手工挂进仓库,可参考 Wiki:复杂场景集成迁移。
- 新项目:以 SidePluginRepo 完整集成为主路径,按 Wiki: 101、Compile And Install 落地。
- 存量项目:可先用 Easy Migrate 验证(代码零修改,只需要把编译依赖改成 ToplingDB);后续若改为程序内托管 SidePluginRepo,同一份配置文件可直接复用,不必推倒重来。
第一阶段:Easy Migrate 快速验证
export TOPLINGDB_EASY_MIGRATE_CONF=./easy_conf.json验证 ToplingDB 在已有工作负载下的性能表现。配置里若已启用 CSPP MemTable、ToplingZipTable 等组件,即可在这一阶段得到对应的性能改进。
第二阶段:引入可观测性
在 继续用 Easy Migrate 的前提下,于同一配置文件中加入 http、auto_start_http: true 与 Statistics 等,即可打开 WebView 与 Prometheus / Grafana,代码零修改即可。若准备做成长期形态、要在程序里托管 SidePluginRepo 或多语言 Binding,宜按 Wiki: 101 直接上新项目推荐路径,不必长期停在「只为存量省事」的集成方式上。
第三阶段:启用在线热更新
利用内置Web提供的动态改参能力,在不重启的情况下微调参数。不同业务线通过本文命名空间机制自然隔离。
第四阶段:引入分布式 Compact
Compaction 成为瓶颈时,可配置 Dcompact 把压缩卸载到 worker 集群。自定义 Compaction 过滤等按 CompactionFilterFactory As SidePlugin 接入后,可与 Easy Migrate 同时采用;关键是 worker 集群能使用同一套配置语义参与远端压缩。
每个阶段都可以停在任意一步;不必一次做完。
从库的完整路径开始,每次去掉最左边一段路径分量,去配置里找有没有同名 key;一旦命中就停止,不再与链上更短后缀处的配置块合并。 全局兜底再用配置块名 default;列族再在 同一路径后缀链的每一档后接 :列族名 尝试,业务列族还可沿该链回退到各档的 :default(内置 Default CF 的固定名)。需要背景可读 Motivation To Solution。