TongSearch存储降本实战:ILM与可搜索快照组合拳

发布时间:2026/10/18 8:13:55
TongSearch存储降本实战:ILM与可搜索快照组合拳 凌晨两点半监控大屏上那条磁盘使用率的曲线还是笔直地顶在 92% 的位置一点面子都不给。我当时负责的 TongSearch 集群正扛着一个核心业务的全量搜索请求索引规模一天涨 90GB三副本一算就是 270GB 的物理消耗按这个速度再有 12 天就要写满。扩容不是不行但哪怕只是加一台数据节点采购审批、机房上架、索引分片重新平衡加起来至少一周才能让集群恢复正常水位。更让我头疼的是这堆数据里真正高频访问的只有最近几天的剩下几十 TB 的冷数据躺在热节点上偶尔被翻一次旧账却长期占着最贵的存储资源。这个局面的解法就是标题里写的那套组合拳用 TongSearch 的 ILM 做索引生命周期管理把温冷数据逐步往廉价存储沉降再用可搜索快照让归档数据“看起来还在线”随时能查、不用还原。这套实践跑完集群磁盘水位降到了 40% 出头查询侧没有出现明显劣化存储成本算下来省了大概六成。这篇就把它整个拆开从原理到配置从踩坑到压测完整过一遍适合正在被索引膨胀追着跑、又舍不得删历史数据的搜索平台负责人和运维同学参考。1. 为什么“存不下”成了必答题1.1 一个典型的容量危机现场以我当时负责的订单检索业务为例业务方要求全量订单保留 180 天可查日增索引大约 90GB初始设计是 3 副本。不看别的单是 180 天的原始数据量就是 90GB × 180 ≈ 16.2TB三副本物理占用接近 49TB。TongSearch 底层基于 Lucene索引在写入主分片之后还会经历段合并、translog 落地这些常规动作实际物理占用通常比逻辑数据量再多出 10%~15%。也就是说真实磁盘需求大约是 54~56TB。这个量级落在原本为“近期数据滚动”设计的集群上很快就撞墙了。表面上业务方说“偶尔查一下半年前的数据”但实际上这种低频查询恰恰是最难处理的——你不能因为这些数据访问率低就删掉因为真的有人会查也不能像热数据那样堆在高速盘上因为九成时间它们都在睡大觉。1.2 先别急着加盘遇到磁盘告警第一反应自然是扩容。但加盘解决的是“当前爆满”的问题解决不了“为什么爆满”的问题。TongSearch 集群里每个节点能承载的分片数量是有上限的数据量上去了光有磁盘不行CPU、堆内内存、文件描述符都要跟着涨。换句话说加一堆节点只是把雪崩往后拖而且拖不了多久。另一个被低估的问题是运维复杂度的上升。节点数从 8 变成 15集群的 master 选举、分片分配、跨节点复制全部进入新的并发水位任何一个节点响应变慢都可能引发分片迁移风暴。我见过不止一个集群在扩容后出现更严重的写阻塞原因就是节点变多之后协调节点压力大增反而把原本平稳的写入链路拖垮了。1.3 为什么不能直接删历史数据有人说低频数据直接删了不就行了业务方那边要做对账审计、客服那边要查几个月前的订单详情、算法团队时不时还要拉一段历史日志做特征回溯这些都是真实存在的查询需求。删数据一时爽后续随便一个业务分析都会变成“对不起数据只保留 30 天”。而且从成本角度看历史数据虽然访问频率低但不等于是垃圾数据。数据是攒出来的资产你要做的是把“保存方式”变得便宜而不是把“数据本身”抛弃。这也是后面 ILM 和可搜索快照存在的根本价值让对的数据在对的时间待在对的存储层上。1.4 传统快照为什么不够用提到降本绝大多数人第一反应是“做快照备份然后删本地索引”。听起来合理操作上也简单定期把索引快照推到备份仓库然后删掉本地数据。但问题是备份库里的数据是不能被 TongSearch 直接查询的。一旦业务方真的来一句“我要查 3 个月前的 XX 订单”你只能老老实实跑一次 restore把快照恢复到集群里。数据量小的集群这么干没问题但如果是几十 TB 的索引从备份仓库拉回来再建索引单是恢复过程就要跑好几个小时。而且恢复期间本就紧张的集群磁盘还会再被撑一轮。传统的快照方案本质上还是“备份—恢复—查询—再删除”的循环操作成本高响应速度完全达不到“随心查”的体验。2. 可搜索快照到底改变了什么2.1 快照不再是“不能动的备份文件”可搜索快照searchable snapshot这个概念简单说就是把快照直接从备份仓库里“挂载”回集群让索引的数据文件不用全部下载到本地也能被检索。查询时TongSearch 会先读本地缓存缓存没命中就去远端存储里拉取对应的数据块拉回来之后在本地留一份缓存下次再查同一批数据就快很多。听起来好像没什么特别关键在于“按需拉取 本地缓存”这个模型它把传统的“全量恢复”变成了“用多少取多少”查询端根本不需要把几十 TB 数据全部搬回本地就能工作。这打破了过去“数据要么在集群里、要么在冷备里”的二选一困境让数据可以长期停留在存储成本更低的远端仓库同时又保持“在线可查”的状态。2.2 部分挂载 vs 完全挂载可搜索快照在实现上分为两种挂载方式完全挂载full mounted和部分挂载partial mounted。完全挂载会把远端仓库里的数据文件完整下载到本地本质上接近一次 restore好处是查询性能等同普通索引坏处是本地磁盘占用没降下来这在降本场景里几乎没有任何意义。真正适合降本的是部分挂载。部分挂载的索引在本地只保留分片的元数据 按需加载的缓存数据数据主体永远放在远端的备份仓库里。本地缓存默认给到每个分片一定配额在这个配额内最近访问过的数据块会常驻本地超出配额或者长时间没被访问的块会被淘汰释放磁盘空间。这样既保住了查询速度又保住了磁盘成本是典型的“以缓存换容量”。2.3 这轮优化里的“降本”到底降在哪先说清楚钱省在哪儿。热节点用的是 NVMe 或者企业级 SSD单价高性能好如果只是保存历史数据完全可以把它们挪到本地 HDD 或者直接放进对象存储里。可搜索快照方案下数据主体放在廉价存储上冷数据查询时会引入一次网络读但换来的是每 GB 存储成本下降到原来的五分之一甚至十分之一。用生活类比来说以前是把全部家当都塞在市中心精装房里房租贵现在把不常用的季节衣物打包送到郊区的自助仓要穿的时候跑一趟取出来穿完再送回去。地方还是那个地方但租金完全不是一个量级。3. ILM 四个阶段怎么设计与实践3.1 阶段总览与数据流向TongSearch 生态里的 ILM 把索引生命周期分成 hot、warm、cold、frozen 四个阶段。每个阶段可以挂不同的 action配置的核心思路是数据越老存储越便宜冗余和性能要求越低。我的落地方案是这样的阶段存储介质副本数主要操作查询响应预期HotSSD 热节点1~3按容量滚动、新索引写入毫秒级WarmHDD 温节点1分片压缩、段合并、只读几十毫秒Cold远端快照仓库 本地小缓存0依赖快照冗余创建可搜索快照、删除本地分片首次秒级缓存命中后百毫秒Frozen远端快照仓库批量缓存0老化淘汰本地缓存更慢但可查可以看到从 warm 进入 cold 开始本地数据就不再全量保留数据真正的“家”从节点磁盘搬到了仓库。这一步操作完成后磁盘释放效果立竿见影。3.2 Hot/Warm 阶段的配置细节hot 阶段的核心是 rollover按数据量或文档数触发新索引切换。我一直用“超过 50GB 或 7 天滚动一次”这类条件来约束避免单个索引过大影响后续 shrink 操作。rollover 条件是支持 OR 组合的只要满足其中一个就会滚动这里要看实际业务量来调整阈值太小会导致索引碎片化太大会让后续 warm 阶段的合并压力大增。warm 阶段的动作就两个核心shrink 把分片数从多个收缩到更少forcemerge 把多个段合并成少数大段。很多人忽略 shrink 的一个前提目标分片数必须是源分片数的因数否则 API 直接报错。另外 forcemerge 一旦执行索引就变成只读了必须在确认业务侧不再对这个阶段的数据发起新写入之后再挂这个动作。3.3 Cold 阶段挂接可搜索快照cold 阶段是这个方案最关键的转折点。ILM 进入 cold 阶段后会执行 searchable_snapshot 动作自动把索引的数据做一份快照推到我们指定的备份仓库然后会把本地分片删除再以“可搜索快照”的形式把同一个索引挂载回集群。配置里我写的策略大致是{ policy: { phases: { hot: { min_age: 0ms, actions: { rollover: { max_size: 50gb, max_age: 7d }, set_priority: { priority: 100 } } }, warm: { min_age: 2d, actions: { shrink: { number_of_shards: 1 }, forcemerge: { max_num_segments: 1 }, set_priority: { priority: 50 } } }, cold: { min_age: 7d, actions: { searchable_snapshot: { snapshot_repository: archive_repo, storage: shared_cache }, set_priority: { priority: 0 } } } } } }这段配置的含义就是索引生成后 7 天进入 cold 阶段交给 searchable_snapshot 动作处理。snapshot_repository 指定我们注册好的仓库storage 指定为 shared_cache对应的就是部分挂载模式数据主体留在仓库本地只做缓存。这个阶段执行完之后你再去看这个索引的 store 大小会发现本地实际占用大幅缩水。3.4 用索引模板把策略串起来策略建好之后不能每次手工去关联得让索引在滚动创建的时候就自动挂上策略这就是索引模板的作用。模板里设置 alias、分片数、副本数这些基础信息同时在 settings 里把它和上文匹配的 ILM policy 绑定。我这边模板里的关键片段是{ index_patterns: [order-log-*], settings: { number_of_shards: 3, number_of_replicas: 1, index.lifecycle.name: searchable_ilm_policy, index.lifecycle.rollover_alias: order-log-write } }这样写的好处是业务方只需要往别名 order-log-write 里写入新数据TongSearch 的 rollover 流程会自动创建新索引新索引自动继承 ILM 策略策略会自动把旧索引推到 warm、cold。整个生命周期管理完全不用人工介入。3.5 挂载后的索引长什么样cold 阶段执行完成后用 GET _cat/indices 去看索引还是那个索引别名、映射、文档数都在。但是如果看 store.size 和 pri.store.size会发现它已经变得非常小因为本地只剩下元数据和部分缓存。真正的数据文件在快照仓库里。对于查询端来说它仍能正常响应不需要你额外做任何“恢复”操作。这一步其实对业务方影响很大在业务方看来数据一点没少随便怎么查在运维方看来磁盘占用实打实降下来了。双方都不需要做任何额外的行为这套方案才能真正落地成功。4. 实操全过程记录4.1 先把备份仓库注册好可搜索快照的前提是有一个稳定的远端仓库。TongSearch 支持多种仓库类型我们生产用的是 S3 兼容的对象存储所以在集群配置里注册仓库是第一步PUT _snapshot/archive_repo { type: s3, settings: { bucket: search-archive-bucket, endpoint: oss-cn-region.internal, access_key: xxx, secret_key: yyy, base_path: searchable_snapshot } }注册完之后建议立刻做一次连通性验证比如创建再删掉一个临时快照仓库里的空快照或者直接列出 bucket 目录确认读写权限。这一步看着简单但仓库配置错误是后面所有问题里最容易爆的雷尤其是自建对象存储endpoint 填成外网地址、访问密钥权限给错都会导致快照任务反复重试、甚至拖累集群状态。4.2 ILM 策略的创建与验证把上面的 ILM 策略丢到集群里执行然后做一次 explain 检查GET order-log-2025.06.01/_ilm/explainexplain 接口会返回这个索引当前处于哪个阶段、正在执行哪个 action如果还有报错会在这里显示具体原因和重试建议。这一步非常推荐排在迁移已有索引之前做先拿一个小索引跑完整流程hot 写入、滚动、进入 warm、执行 shrink、进入 cold、生成可搜索快照、删除本地数据。整套流程大部分情况下不会一次通过提前用小索引把坑踩完比直接拿生产数据试验要稳妥得多。4.3 已有索引如何手工迁移ILM 对新建索引是自动的但对已经存在于集群里、刚挂上策略的老索引需要手动设置滚动或直接让策略生效。我在代码这里指管理脚本里做的操作是把符合条件的历史索引直接改设置让它们立刻从某个阶段开始执行PUT order-log-2025.05.10/_settings { index.lifecycle.indexing_complete: true }或者直接对存量索引调用 move-to-step 接口让 ILM 跳过部分前置动作直接进入需要的阶段POST _ilm/move/order-log-2025.05.10 { current_step: {phase: hot, action: rollover, name: attempt-rollover}, next_step: {phase: warm, action: shrink, name: shrink-index} }这个操作要小心它是一次“快进”跳过的步骤不会自动补齐。比如索引还没做过 forcemerge 就直接进了 cold可能因为段太多导致后续查询时缓存命中率偏低查询耗时会明显增加。4.4 迁移过程中的磁盘变化观察迁移过程中我重点盯了三个指标集群级磁盘水位、单个索引的 store.size、快照任务执行进度。最直接的是 disk 水位。在 cold 阶段把搜索快照建好、本地分片删掉的那一瞬间磁盘使用率会出现一次肉眼可见的跳水。比如我当时观察到节点磁盘占用从 85% 直接降到 63%过了几天随着更多历史索引被 ILM 处理掉整体来到 42% 附近这才敢说方案真的生效了。快照任务用这个接口看GET _snapshot/archive_repo/_status这里要说一句快照任务在 cold 阶段执行期间是会占对象存储的带宽的。如果同时有大量索引一起进入 cold仓库写入可能成为瓶颈。稳妥的做法是错峰操作给集群加一点限速避免把对象存储的带宽打满之后连带影响到其他依赖仓库的备份任务。4.5 查询侧怎么验证“随心查”数据迁移到快照仓库之后业务方最关心的就是“现在查会不会变慢”。我的验证思路很简单挑几个真实业务查询把过滤器限定到不同阶段的老索引上分别看首次查询和第二次查询的耗时。实测下来首次命中缓存之外的冷数据查询耗时确实会从几十毫秒跳到 2~4 秒这个主要受仓库网络带宽和数据块大小影响第二次查询相同范围耗时基本能回到 200~500ms 左右因为数据块已经缓存在本地了。这个结果我提前同步给了业务方让他们知道“偶尔首次查历史数据会慢一点但可接受”算是把预期管理做在了前面。5. 成本账本与关键经验5.1 存储单价差距到底有多大降本这件事不能光靠感觉要算账。我按通用云资源价格折算了一下不同类型存储的每 TB 每月成本大致如下存储类型相对价格系数特点NVMe SSD 热节点10低延迟、高并发、适合高频写入HDD 温节点3~4顺序读写快、随机读一般、单位容量便宜对象存储/S3 兼容1容量弹性、按量付费、读取有网络延迟假设我们有 30TB 逻辑数据需要存 180 天在纯热节点方案里三副本物理占用约 90TB按 NVMe 价格系数 10 来算月成本相当于 900 个“对象存储单位”。切到 ILM 加可搜索快照之后热数据只保留最近几天大约 5TB温数据保留 1~2 个月约 15TB剩下的 10TB 冷数据放进对象存储仓库本地只留少量缓存。综合算下来月成本大约是 5×10 15×3.5 10×1 107.5 个单位相比原来的 900 个单位省了将近九成。当然这只是粗略对比实际还要算网络流量、节点资源空置等情况但量级差异已经很说明问题了。5.2 性能损失能接受吗这个方案最让人犹豫的点是冷数据查询性能。我的观点是冷数据本来就是低频访问如果业务查询真的是高频且对延迟极度敏感那它就不该被定义为冷数据。可搜索快照通过本地缓存已经能顶住大部分“偶尔翻旧账”的查询场景真正需要全量扫冷数据的场景本来也不多。在实施时我额外做了一步给冷索引单独设置更低的副本优先级确保集群发生节点故障时恢复顺序永远是热数据优先。这一步属于集群调优的经验范畴具体做法是在 ILM 策略的 cold 阶段通过 set_priority 来控制让冷索引的优先级尽量低从而保证集群资源永远是热数据优先。5.3 缓存参数怎么定部分挂载模式下本地缓存的大小直接决定查询体验。缓存给得太小冷数据查询几乎每次都要回源拉取首次查询等到起飞缓存给得太大又失去了降本的意义磁盘又会被撑满。我这边给分片级缓存设置了约 15GB 的配额同时配合“按查询访问频率自然淘汰”的策略。实际跑下来日常批量回查历史订单的查询命中率能稳定在 60%~70% 左右剩下未命中的部分走仓库回源耗时也能接受。如果你的冷查询模式是“经常翻同一段时间”缓存命中率还会更高效果更好。缓存参数的查看方式是GET order-log-2025.03.01/_stats/store?levelshardsfilter_path*.store.size再结合监控里 cold 索引的缓存命中率调整 cache_size 到一个合理的值。这里建议每次调整只改 20% 左右观察几天再动避免一次调得过大导致磁盘水位异常反弹。5.4 批量迁移的操作经验在批量处理历史索引时我的做法是分批推进每次最多同时处理 10~15 个索引进入 cold 阶段。这个区间是我在测试环境实测过的“安全水位”超过这个数量对象存储的写入带宽容易被快照任务打满直接导致队列里其他快照任务等待超时。具体节奏是先挑 2~3 个索引做“先遣队”跑通全流程然后每批处理 10 个左右每批之间间隔 10 分钟观察集群的磁盘水位、仓库写入 QPS 和冷索引查询延迟没问题再放大到下一批。整个过程大概花了两天半全部历史索引稳定进入 cold 阶段期间业务查询没有出现任何告警。6. 常见问题与排查技巧实录6.1 快照仓库连接失败或超时这个是最常见的第一个拦路虎。现象是创建仓库或者创建快照时报错提示连不上 bucket 或者认证失败。排查思路很简单先确认对象存储的读写权限再确认网络连通性最后检查 base_path 是否存在。很多时候是自建对象存储的 endpoint 要配成内网地址我最初配成了公网地址导致每次执行快照都超时拖慢了集群节奏。另一个隐蔽的问题是对同一个 bucket 并发执行太多快照任务对象存储可能会主动限流。此时报错信息可能不是“认证失败”而是“RequestTimeTooSkewed”或者“SlowDown”之类的状态码。这时候不要反复重试先看看是不是有大量索引在同时触发了快照把所有待执行策略的索引分批处理限流问题通常就消失了。6.2 第一次查询冷数据慢到不科学冷索引首次查询慢正常的。如果慢到完全不科学比如 10 秒以上优先怀疑是本地缓存配额太小导致每次查询都触发大面积的仓库回源。排查方法是在查询时加上 profiling看耗时是不是全部堆在 fetch 阶段。另一种可能性是快照仓库所在的对象存储和 TongSearch 集群不在同一个可用区或者走的是公网链路。跨网络拉数据带宽和延迟都不可控。这时最好的做法是把对象存储的 endpoint 改成内网或者把仓库迁移到同区域的存储桶上查询性能会立刻好转。6.3 磁盘水位没有降多少有同学反馈说执行完冷阶段之后磁盘还是满的这里要区分两种情况第一ILM 策略可能还没执行到 cold 阶段你只是建好了策略但没让存量索引 move第二部分挂载模式的本地缓存设置过大实际缓存数据把磁盘又占满了。排查方式就是看 explain 和历史索引的 store 大小确认索引都进入了 cold 阶段再看集群里是不是有大量正在执行的 recovery 过程分片在节点间搬来搬去磁盘空间被临时占用得厉害。这种临时占用通常在 recovery 结束后会自动回收不必太紧张。6.4 ILM 策略一直卡在某个阶段不往下走ILM 策略执行不推进第一步永远是看 explain 输出看它卡在哪一步。常见的原因是 shrink 阶段分片数不是源分片数的因数或者 forcemerge 失败导致进入死循环也可能是集群的节点不是数据节点导致某些 action 无法执行。如果是 shrink 报错就重新设置 number_of_shards 为源分片数的因数然后再尝试。如果是 forcemerge 失败先确认索引是不是处于只读状态、有没有阻塞写入的操作把阻塞源解决掉再重试。最后还有一种情况是集群的冷热节点配置没有配好导致 ILM 想往冷阶段迁但找不到满足条件的节点也会卡住需要检查节点属性是否匹配。6.5 误删了恢复中的索引怎么办有一次我在测试过程中误删了一个还在迁移中的索引说实话当时慌了一下担心数据丢没丢。后来验证下来删除一个可搜索快照索引本质上只是把它在集群里的“挂载实例”拿掉远端仓库里真正的快照数据并不会丢。恢复方式也很简单直接用仓库里对应的快照重新挂载一次即可。这给了我们一个天然的数据保护冗余就算本地索引被误删只要仓库里的快照还在随时能挂回来。所以在实施整个方案之前务必确认仓库里已经存有有效快照操作前做一次快照验证心里就有底了。6.6 定期做恢复演练最后提醒一个容易被忽略但很重要的步骤定期做可搜索快照的恢复演练。不是每次迁移都会出错但一旦出问题比如近端仓库上的快照数据因为某些原因缺失了一部分等到业务方真要查数据的时候才发现那就晚了。我的做法是每季度取一个历史索引从仓库重新挂载一份副本到集群查询几个典型条件确认返回数据正常。整个演练成本很低但能确保我们的快照链路是真正可靠的而不是纸上谈兵。这个方案落地到现在快半年了我从里面学到的最大一课是数据管理不能只看“存得下”还要看“存得起、查得到”。以前遇到磁盘告警第一反应是扩容现在我更愿意先想想哪些数据其实可以放到更便宜的层里去。可搜索快照和 ILM 给我的不只是一个降本手段更是一套重新审视数据价值的方法论。如果你现在也在为了磁盘扩容审批焦头烂额不妨先不急着申请新机器把这套组合拳在自己的测试环境跑一遍给数据分层让每份数据都待在该待的位置上。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询