跳到内容

第 5 卷 / 第 20 章 / 第 2 课

20.2 近实时索引、同步、分片与搜索运维 ​

搜索索引通常是权威数据库的派生视图。它可以短暂陈旧、可以重建,却不能悄悄成为库存、价格或权限的第二个裁判。

近实时来自 Refresh,不是写入失败 ​

Lucene 以不可变 segment 组织索引,新文档先进入内存索引结构。Elasticsearch 还为每个 shard copy 记录 translog,用于恢复尚未纳入 Lucene commit 的操作。refresh 让新的 segment 可搜索,后台 merge 再合并小 segment。

Elasticsearch 的 index API 返回成功后,文档不一定立刻能被 search API 命中。默认 refresh 行为依部署与索引活跃状态而异,不能把“永远 1 秒”写死。需要 read-after-write 搜索体验时,可评估 refresh=wait_for,让写请求等待一次使其修改可见的 refresh;频繁强制 refresh=true 会制造大量小 segment 并增加 merge 成本。

如果 index.refresh_interval=-1 禁用了自动刷新,wait_for 可能一直等待,直到其他操作触发 refresh。等待本身不会让被关闭的定时器重新开工。refresh 参数说明

还要区分:

  • refresh:让最近操作可搜索;
  • flush:执行 Lucene commit,并开始新一代 translog;
  • merge:合并不可变 segment,清理已删除文档的物理占用;
  • replica acknowledgement:决定索引写入的副本确认条件。

这些动作有不同的完成条件。默认 index.translog.durability=request 会在写入成功确认前持久化 translog;这与等待 refresh 可见、定期 flush 减少恢复重放量是三件事。Translog 说明

Primary Shard 决定数据切分 ​

文档 ID 或 routing 值映射到 primary shard,副本 shard 保存该 primary 的复制数据。搜索请求由 coordinating node 发往相关 shard copy,再合并各 shard 的 top results。

text
query
  -> shard 0 top-k
  -> shard 1 top-k
  -> shard 2 top-k
  -> coordinator merge/rerank

Primary shard 太少会限制并行与容量,太多则增加 heap、文件句柄、cluster state、scatter/gather 和恢复成本。副本提高故障容忍与潜在读吞吐,不会增加写入数据的分片数。

自定义 routing 可让同一租户/实体查询只访问部分 shard,却也可能制造热点和超大 shard。规划应使用真实文档大小、查询 fan-out、恢复时间和增长曲线,而不是固定“每 shard 多少 GB”的万能数字。

数据库到搜索索引的同步 ​

可靠链路通常是:

text
database transaction
  -> outbox/WAL/CDC
  -> durable event log
  -> idempotent indexer
  -> search index
  -> checkpoint + lag metrics

事件至少携带稳定实体 ID、source version 和删除语义。Indexer 对同一实体乱序事件应拒绝旧版本覆盖新版本;删除不能只从源表缺席推断,应传播 tombstone 或显式删除事件。

删除后的版本也有保留期限。Elasticsearch 的 index.gc_deletes 控制删除版本信息保留时间;清除后,过期更新可能把文档重新建出来。需要覆盖最大重放窗口的应用 tombstone/版本水位,或能证明旧事件不会再次到达的有序处理协议。Delete API

批量请求还要逐项检查 errors、items[*].status 和错误原因:HTTP 200 不等于所有文档写入成功。可重试失败项应带原实体 ID 与版本,checkpoint 不能越过尚未成功处理且未被可靠转交的日志位置。Bulk API

重建时应通过连接器协议取得一致快照及其增量位置,先保护日志保留,再在回填期间捕获增量。应用顺序或版本条件要防止快照旧值覆盖已经应用的新值;随手读取当前时间或某个 offset,不能证明它与快照衔接。

Reindex 用新索引和 Alias 切换 ​

修改 analyzer、字段类型或主分片规划时,通常创建新版本索引:

text
products-v3 (current alias target)
products-v4 (backfill + catch up + verify)

流程:

  1. 创建显式 mapping/settings 的 v4;
  2. 从一致快照全量回填;
  3. 追上增量并记录 checkpoint;
  4. 对比数量、抽样文档、过滤和相关性;
  5. 协调写入者和在途请求,在最后追平后原子切换读写 alias;
  6. 保持旧投影可追平,验证可回退窗口,再删除 v3。

假设练习索引 v3、v4 已存在,products 当前仅指向 v3,且上述校验已完成,可向 POST /_aliases 提交下面的请求体。must_exist 使旧 alias 不存在时整组动作失败,避免只完成添加:

json
{
  "actions": [
    { "remove": { "index": "products-v3", "alias": "products", "must_exist": true } },
    { "add": { "index": "products-v4", "alias": "products", "is_write_index": true } }
  ]
}

Alias 原子切换只解决路由元数据的一次变更,不会补齐 v4 的缺失数据,也不会追回已发往 v3 的写请求。切换后若 v3 停止接收增量,回退前仍需追平;否则只是把用户送回旧数据。Alias 说明

双写 v3/v4 仍需处理一边成功一边失败;基于同一 CDC 日志分别投影通常更容易重放和审计。

搜索结果不能直接裁决交易 ​

用户在搜索页看到“有库存”,点击下单时必须回权威交易库重新校验并原子扣减。权限撤销若要求立即生效,也不能只等待索引 refresh。

搜索服务应声明 freshness SLO。下面是假设目标,需要按实际风险与容量验收:

  • 99% 商品更新在 30 秒内可搜;
  • 删除/下架在 10 秒内从公共结果移除;
  • 权限强校验在返回详情或执行操作时由权威服务完成。

不同字段可有不同风险与降级路径。

深分页与结果一致性 ​

from + size 越深,每个 shard 需要保留并返回更多候选,协调节点成本迅速增加。面向滚动列表优先使用 search_after 和稳定 tie-breaker;需要跨多页保持一致视图时结合 point in time(PIT)。

后续页应携带上一页最后一条结果的完整 sort 数组,包括 tie-breaker,并使用最新返回的 PIT ID;query 与 sort 保持不变。PIT 会保留所需旧 segment,应设置有限的 keep_alive,用完关闭。PIT 过期后需重新开始一次分页,不能把旧游标拼到新视图上。分页说明

排序字段必须稳定且确定。只按分数时,相同分数文档在 refresh、replica 或 shard 状态变化后可能换序。

词法、向量与混合检索 ​

向量检索擅长语义相似,却不天然保证精确编号、否定词、最新事实或权限过滤。词法检索擅长精确 term 与可解释过滤。混合检索通常:

text
authorized, filtered lexical candidates + vector candidates
  -> score fusion / RRF / learned reranker
  -> final policy check

权限与租户边界应约束两路候选;尤其不能先把越权文档送给外部 reranker,再靠末尾过滤补救。若要求即时撤权,返回前还需权威权限校验。向量 top-k 后再过滤可能不足 k 条,即使语料中存在足够合规结果;应选择引擎支持的预过滤方式,并评估过滤条件下的召回。kNN 过滤说明

Embedding 模型版本应写入索引元数据;升级模型往往需要重新计算向量和评估。向量召回同样需要离线 judgement、延迟和内存/磁盘成本测试,不能只看几条演示查询。

运维指标 ​

至少监控:

  • indexing rate、reject、bulk error 与 CDC lag;
  • refresh、segment count、merge time/throttle;
  • shard size、allocation、recovery 与 cluster health;
  • search p50/p95/p99、timeout、cancel 和 shard failures;
  • query fan-out、slow log、cache 与 heap/GC;
  • zero-result rate、Recall/nDCG 采样与权限漏出检查;
  • source version 与 index checkpoint 差距;
  • 全量重建和 alias 回退耗时。

集群绿色只说明 shard 分配状态,不证明数据已与权威源同步,也不证明搜索质量正确。

参考 ​

第五卷从关系模型、存储与事务,一直推进到缓存和搜索派生视图。完成后应能用一致性、可恢复性和运维证据说明数据系统的边界,而不只是列出产品名称。

Built with VitePress | Software Systems Atlas