Elasticsearch分布式搜索:分片、写入、查询与生产实践

发布时间:2026/11/6 15:03:51

Elasticsearch分布式搜索:分片、写入、查询与生产实践 上一篇把 ES 的基本盘铺完了倒排索引怎么建、文档怎么落盘、节点有哪几种角色。但真上手做项目就会发现那些知识只够让一个单机实例跑起来。数据量一过千 GB、节点数超过三台问题立刻换了一副面孔明明返回result: created却查不到集群莫名其妙变黄分片卡在UNASSIGNED几个小时不动翻到第 200 页直接抛异常。这篇“分布式搜索 ES”系列的第二篇专门拆这些“上生产才会撞上”的部分分片和副本在物理上怎么摆、一条写入要经过几道关、一次查询为什么要跳两趟、集群在一致性跟可用性之间怎么取值以及出问题时按什么顺序去看那些命令。内容偏中高级适合已经能建索引、会写 DSL但对着几百个分片和一堆黄色告警无从下手的人。纯新手也能读只是建议先补一下索引、文档、映射这几个基础概念再回来不然会有点吃力。下面所有参数和命令都基于 7.x 之后的版本更早的版本在集群选举和一致性参数上差别不小别直接套。1. 分片与副本分布式的基本单位到底怎么定1.1 分片不是越多越好先算清三笔账很多人第一次建索引习惯性把number_of_shards设成 10 或者 20理由是“以后数据会涨”。这个思路在单机上没错在分布式搜索里是灾难。一个分片在底层就是一个独立的索引库实例它有自己的段文件、自己的日志文件、自己的文件句柄还有一份常驻在堆里的段元数据。分片数上去了每个节点的文件句柄数、堆占用、集群状态体积会同步膨胀而集群状态是要在主节点之间同步、并且推给每一个节点的。第一笔账是堆。业内比较稳妥的经验值是每 1GB 堆内存承载 20 个以内的分片超过这个数主节点维护集群状态的延迟会明显上升你会开始看到cluster state update相关的慢日志。一个 8GB 堆的节点理论上限就是 160 个分片这个数字包含主分片和副本。第二笔账是单个分片的大小。业界共识区间是10GB 到 50GB我个人的偏好是 20~30GB。太小了分片数量爆炸每次查询要打到几十上百个分片上做归并协调节点的 CPU 直接被打满太大了单分片恢复时间变长一个 100GB 的分片从磁盘重建副本可能要几十分钟这段时间里集群是降级状态。第三笔账是磁盘余量。底层合并段的时候同一份数据在磁盘上会短暂存在两份加上副本本身占空间实际占用经常是原始数据的 2.2~2.5 倍。所以规划磁盘时别按 80% 算留到 60%~70% 比较稳。默认的低水位线是 85%、高水位线 90%、洪泛线 95%一旦越过洪泛线索引会被强制设成只读写入直接失败那个报错我见过太多次了。举个实际算过的例子原始数据 2TB1 个副本目标是单分片 25GB 左右。2TB / 25GB ≈ 80 个主分片取个整齐的数 72 或者 96 都行能被节点数整除更好。选 72 主分片 1 副本 144 个分片如果 6 个数据节点每个节点 24 个分片堆给到 8GB 以上就很舒服。整套算下来磁盘至少准备 5TB 可用空间。这个推导过程比记住任何结论都重要因为你的数据量、节点数、读写比都跟别人不一样。1.2 主分片数创建后就锁死了但有三条绕路这是 ES 里最容易被新手忽略的一条硬约束主分片数量在索引创建时确定之后不能直接改。原因跟下面的路由公式直接相关改了分片数所有文档的路由结果都会变相当于全量迁移。但这不代表没有补救办法实际项目里常用三条路。第一条是拆分索引split。它把一个索引的每个主分片一分为二或一分为多前提是索引必须设成只读、所有分片必须在同一个节点上底层用的是硬链接而且新的分片数必须是原分片数的整数倍。这条路的限制很硬实际用得不多通常只在小索引上做。第二条是收缩索引shrink。把分片数缩下来同样是只读 同节点。适合那种一开始分多了、数据其实没涨起来的场景。我见过一个项目把 20 个分片缩到 5 个查询延迟降了将近一半纯粹是因为归并的活儿少了。第三条是重建加迁移reindex也是最常用、最没副作用的。新建一个分片数正确的索引把映射和设置拷过去用_reindex把数据搬过去然后切别名。这个方案的好处是顺便能改映射、能重排字段、能调整刷新间隔等于给索引做一次全面体检。代价是要占用一份额外的磁盘和一段时间的集群算力所以务必在低峰期跑并且把_reindex的requests_per_second限速打开。三条路的对比方案能否改分片数前提条件磁盘开销适合场景_split只能增加且为整数倍只读、同节点、硬链接支持约 1 份新数据小索引快速扩容_shrink只能减少且为整数因子只读、同节点约 1 份新数据分片设多了想回收_reindex任意无硬性限制约 1 份新数据 迁移算力附带改映射、初始化新索引提示无论走哪条路最后一定要用别名alias切换让业务代码永远读别名而不是物理索引名。这一步做在前面后面所有重建、迁移、滚动升级都是零停机。1.3 副本不只是备份它还扛读很多人把副本单纯理解成高可用其实它的作用有三个。第一是故障转移主分片所在节点挂了副本能被提升为新的主分片。第二是读吞吐查询默认会在主分片和副本之间轮询1 个副本等于查询并发翻倍。第三是隔离你可以把副本强制调度到另一批机器上让主副本不落在同一个机架。但副本不是白给的。每个副本占一份完整磁盘写入时主分片处理完还要转发给所有副本、等它们确认副本越多写延迟越高。经验值是线上稳定服务 1 个副本就够对读并发特别高的索引可以给到 2 个。有一个非常实用的技巧大批量灌数据的时候先把副本数临时设成 0灌完再调回来。因为初始化过程中每个副本都要做一次完整的段复制这段时间的写入基本没法用。具体操作就是先PUT /index/_settings把number_of_replicas设为 0灌完数据再设回 1让副本在系统空闲时慢慢同步。这个操作我几乎每个项目都会用能省掉大量“批量导入时集群卡住”的抱怨。2. 一条文档的写入旅程从客户端到磁盘2.1 路由计算决定了文档落在哪一片写入的第一步不是写是算。协调节点拿到一条文档先用公式算出它该去哪个分片shard_num hash(_routing) % number_of_primary_shards_routing默认就是文档的_id。这个公式解释了两件事为什么主分片数不能改改了分母所有文档位置全变以及为什么自定义路由要慎重要是按某个业务字段路由这个字段分布不均就会造成热点分片。自定义路由的价值在于“把需要一起查的数据放在同一个分片上”。比如订单和订单明细用订单号做路由两者会落到同一个分片查询时只打一个分片不用跨片归并性能提升非常直观。反过来如果你的路由字段取值高度集中——比如默认值、空串、某个大客户 ID——那所有数据会挤在一个分片上其他分片闲着这就是典型的“热门分片”问题。要做自定义路由先跑一遍字段的基数统计。注意搜索请求可以通过preference参数指定优先使用哪些分片或节点。常用的_local表示优先用本节点上的分片能省一次网络往返适合批处理任务_primary强行走主分片一般用于调试还可以传自定义字符串把同一用户的查询固定到同一组分片提高缓存命中率。2.2 主副本同步什么才算写入成功完整的写入链路是这样的协调节点路由到主分片所在节点主分片先做校验——映射字段类型对不对、有没有触发字段数上限、版本号有没有冲突、有没有超长字段。校验通过后数据同时写进内存缓冲区和事务日志然后把请求并行转发给所有副本分片。副本各自完成后回 ACK主分片收到足够数量的确认才向客户端返回成功。“足够数量”就是wait_for_active_shards控制的。默认值是1意思是只要主分片写成功就算成功不管副本。这个默认值的含义是如果这时候主分片所在节点立刻宕机而副本还没来得及同步这条数据就丢了。想更安全可以设成all或者具体数字代价是可用性下降——副本不够的时候写入会直接失败。我个人线上项目的做法是绝大多数索引保持默认1对于订单、支付这类绝对不能丢的索引设成2对应 1 个副本即等待至少一个副本确认。这是一个很实际的权衡设成all意味着任何一个副本掉线整个索引就写不进去风险和收益不对等。写入还有两个容易被忽略的校验点。一是字段映射的dynamic策略如果设成strict出现未定义字段会直接报错设成true默认则会自动推断类型长期跑下来很可能出现同一字段半数是long半数是text的惨剧然后聚合就报错了。二是单条文档大小默认超过 100MB 会被拒但这个上限意义不大真实建议是单文档别超过 10MB超大的文本块拆成多条存。2.3 refresh、flush、translog、merge 这四件事别搞混这是面试高频题也是实际排障时最容易混淆的一组概念。我用一个类比说清楚把索引库当成一个笔记本内存缓冲区是写在草稿纸上的内容段是正式装订的页码事务日志是边写边记的流水账磁盘上的提交点是合订本的目录。refresh刷新把内存缓冲区里的内容写成一个新的段让搜索能看见。它默认每秒执行一次这就是 ES 号称“近实时”的来源不是实时是 1 秒级别的延迟。refresh 跟持久化没关系它只解决“可见性”。translog事务日志每次写入都会追加到日志里默认每次请求都 fsync。它是真正的持久化保障节点崩溃重启后靠它把内存里的数据补回来。可以改成异步刷盘index.translog.durability: async代价是崩溃时最多丢一个间隔默认 5 秒的数据。flush刷盘做一次完整的提交把段 fsync 到磁盘、写提交点、清空事务日志。触发条件是事务日志达到512MBindex.translog.flush_threshold_size或者每隔 30 分钟。所以并不是每次 refresh 都会 fsync。merge合并后台把很多小段合并成大段同时清理掉被标记删除的文档。段越少查询越快但合并本身非常吃磁盘 IO 和 CPU。刚灌完大批数据的时候查询慢八成是在合并。动作触发时机解决什么主要开销可调参数refresh默认每 1 秒写入可见生成小段段数膨胀index.refresh_intervaltranslog 落盘每次请求默认崩溃恢复磁盘同步index.translog.durabilityflush日志满或定时提交点持久化强制 fsync短时 IO 抖动index.translog.flush_threshold_sizemerge后台自动减少段数、清理删除CPU 磁盘 IOindex.merge.scheduler.max_thread_count理解了这四者很多东西就顺了。比如批量灌数据时把index.refresh_interval设成-1就是为了不生成几千个小段等灌完再手动 refresh 一次段的生成数量能少一两个数量级后面的合并压力也小得多。又比如查询性能突然下降先看段数量如果某分片段数是别人的十倍那大概率是 refresh 太频繁或者合并被限速太狠。关于合并限速机械盘上是必须配的。默认情况下合并线程会用满磁盘带宽导致正常的写入和查询全部被拖慢。设置index.merge.scheduler.max_thread_count: 1在机械盘上是很常见的做法SSD 上可以留默认。另外对于确定不再写入的历史索引比如按月归档的日志索引做一次强制合并_forcemerge?max_num_segments1能把段压成一个查询速度提升非常明显但这一步非常吃资源一定要在业务低峰做并且只对只读索引做。3. 一次查询的两次跳转query then fetch3.1 查询阶段和取回阶段分别干了什么搜索不是“在集群里找一遍”而是跳两趟。第一趟叫查询阶段。协调节点把请求广播到索引的所有分片主副轮询每个分片在本地执行查询算出匹配的文档 ID 和排序值但只返回前from size个 ID 和排序值不返回文档内容。协调节点把所有这些结果汇总、全局排序挑出真正要返回的那size条。第二趟叫取回阶段。协调节点根据文档 ID 反推出它所在的分片向对应分片发起批量取回请求拿到_source组装成最终结果返回。这个设计的好处很明显网络上传的只是 ID 和排序值不是完整文档带宽省了一大截。坏处也藏在细节里每个分片都要返回from size条。假设 10 个分片你要第 100 页from9900, size100每个分片都要吐 10000 条 ID 给协调节点加起来就是 10 万条协调节点还要对 10 万条做一次全排序。这就是深分页昂贵的根本原因不是数据多是放大系数。3.2 为什么相关性打分在分片之间会飘打分依赖词频和逆文档频率而逆文档频率需要“全局文档数”和“包含该词的文档数”。问题在于每个分片只能看到自己那部分数据算出来的是局部频率。同一个查询打到不同分片同一个词的 IDF 不一样最终得分自然有偏差。如果你的业务对排序稳定性要求很高有三条路。第一条是加search_typedfs_query_then_fetch先做一次预查询把全局词频统计出来再算分代价是多一轮往返分片多的时候延迟会明显增加一般不建议线上常开。第二条是让索引只有一个分片小数据量几十 GB 以内的场景完全可行一致性最好。第三条——也是我实际项目里用得最多的——别太依赖纯文本相关性。真实业务里排序通常是“相关性 业务权重”的组合用function_score把销量、时间、权重系数显式加进去比纠结 TF-IDF 的小数点后第三位有意义得多。提示用filter上下文包裹的查询不参与打分还能命中查询缓存。凡是“是/否”的筛选条件状态、类目、时间区间一律放进bool.filter这是性价比最高的一条优化。3.3 深分页的三种姿势别用错场景from size有硬上限默认index.max_result_window是 10000。超过就报Result window is too large。这个上限是可以改的但改大的代价是协调节点的堆内存成倍消耗超过几万的偏移量基本就是自找麻烦。正确做法有三种。滚动scroll适合一次性导出全量数据它会在服务端保留一个快照然后一批批往下拉。缺点是快照占用资源、不反映实时数据而且要记得手动清理超时时间设得太长会拖垮集群。search_after适合“下一页”式的连续翻页它用上一页最后一条的排序值作为游标不需要维护服务端状态效率很高。缺点是只能一页页往下走不能跳到第 50 页。时间点PIT search_after是目前推荐的组合解决了search_after在翻页过程中数据变动导致的重复或漏读问题。方案能跳页服务端状态实时性典型场景from/size能无实时前几页浏览scroll不能有需手动清理快照全量导出、离线任务search_after不能无实时无限下拉PITsearch_after不能有有 TTL一致快照深度翻页 一致性用search_after有个硬要求排序字段必须是唯一的或者在最后补一个_id做兜底否则排序值相同的文档会被跳过或重复。这个坑我踩过一次翻页时偶发丢数据排查了半天才定位到排序键不唯一。4. 一致性、可见性与并发控制4.1 写入一致性在数据安全和可用性之间取值前面提过wait_for_active_shards这里展开说一下怎么选。这个参数的本质是“我愿意为了数据安全牺牲多少可用性”。设成1默认只要主分片活着就能写性能最好风险是主分片刚写完就挂、副本还没同步这条数据就没了。这个窗口非常小毫秒级对绝大多数业务可以接受。设成具体数字2要求至少一个副本确认。适合绝对不能丢的场景代价是副本全部掉线时写入会失败。这里要提醒一句副本掉线是很常见的事——节点重启、磁盘抖动、网络闪断都会触发副本重建那段时间如果卡了2整个写入链路就堵了。所以设成2的索引一定要配合足够的副本数和合理的超时。设成all所有副本都确认才算成功。我基本不推荐收益太小风险太大。配套的还有index.write.wait_for_active_shards可以在索引设置层面设默认值免得每次请求都写一遍。另外这个参数只控制“等待多少个分片活跃”不保证数据已经同步到副本真正的数据安全还得靠副本数 事务日志落盘策略一起看。4.2 近实时可见性快和准的取舍写入成功后立刻查默认是查不到的因为还没 refresh。这在很多业务流程里会造成困惑比如用户下单后跳转到订单列表发现刚下的单不在里面。ES 给了三个层级的控制。refreshtrue表示写入后立即刷新能马上查到代价是每次写都生成一个小段写入吞吐直接腰斩只适合极低频操作。refreshwait_for表示请求挂起等下一次自动刷新完成后返回既不额外生成段又能保证返回时数据可查这是读后写场景的最优解。refreshfalse就是默认行为写完就返回不保证可见。我做过一次压测对比同一个集群全部用refreshtrue和全部用refreshwait_for前者写入吞吐只有后者的三分之一左右而且段数量涨得飞快后续合并压力巨大。所以除非是极端场景一律优先wait_for。另外要注意refreshwait_for的默认超时是一分钟而且如果索引的refresh_interval设成了-1批量导入时的常见设置这个请求会一直挂到超时。这个组合出过不少线上问题用之前先确认刷新间隔。4.3 并发写冲突两种版本控制怎么选ES 的并发控制是乐观锁。每个文档有_seq_no和_primary_term两个字段写入时可以带上if_seq_no和if_primary_term如果文档在这期间被别人改过请求会返回 409 冲突让你重新读取再写。这是最精确的做法适合“读-改-写”的更新逻辑。另一种是外部版本号version_typeexternal把上游系统的版本号比如时间戳带进来ES 只接受版本号更大的写入。这个方式特别适合做数据同步上游数据库有update_time字段同步程序把时间戳当版本号写进 ES重复消费、乱序消费都不会造成脏数据。这是我从一个数据同步项目里学到的最实用的一招比在应用层做去重简单得多。冲突了怎么办如果业务能容忍直接重试几次就够了如果是批量更新用_update_by_query的时候带上conflictsproceed让它跳过冲突文档比整个任务失败好得多。但要记住跳过意味着数据可能不一致得靠后续的全量校对兜底。5. 容量规划与索引设计把问题挡在事前5.1 从数据量反推节点数和堆大小这一块是很多人拍脑袋的重灾区。我给一个可落地的推导顺序。先定堆。堆的设置有一条硬规则不要超过 31GB因为超过之后指针压缩失效实际可用内存反而下降。另一条经验规则是堆不超过物理内存的一半剩下的留给文件系统缓存——搜索性能极度依赖页缓存把内存全给堆是典型的错误做法。所以一个 64GB 内存的机器堆给 31GB 是合理的一个 32GB 的机器堆给 16GB。再定分片。用总数据量除以目标分片大小20~30GB得到主分片数然后保证主分片数 × (1 副本数) ÷ 节点数 ≤ 每 GB 堆 20 个分片。如果算出来超标要么减少分片数把单分片调大要么加节点。最后定磁盘。总数据量 × (1 副本数) × 1.3合并余量得到的是可用空间下限再反推需要多少块盘。别忘了一旦某个节点磁盘越过 85% 低水位分片就不会再往它上面分配了越过 95% 洪泛线它上面的索引会变只读。我见过最惨的一次事故就是磁盘预留不足灌数据灌到 95%几个索引同时变只读业务全线写入失败只能临时扩盘解决。5.2 映射里最烧钱的几个默认值映射设计的坑几乎都和“默认”有关。动态映射会因为一条脏数据给某个字段推断出错误的类型之后所有写入都被拒文本字段默认会同时建text和keyword两个子字段存储直接多一份给不需要检索的字段保留了索引写放大白白增加。我通常的调法是这样几条。只用于精确匹配和聚合的字段直接上keyword顺手加ignore_above: 256防止超长值撑爆索引。只用于展示、不需要检索的大字段比如详情 HTMLindex: false并且关掉doc_values能省下可观的空间。需要全文检索的字段用text但配一个keyword子字段用于排序别忘了给排序字段设norms: false。数值字段如果只用于筛选、不做范围计算可以适当选更小的类型integer能解决的别用long。还有一个必须关掉的东西text字段上的fielddata。默认是关的但总有人为了在text上做聚合把它打开然后某天一个大聚合把整个节点的堆打满。要做文本聚合就用keyword子字段这是唯一正确的做法。配置项默认值建议影响dynamictrue生产索引设strict防止脏字段污染映射indextrue仅展示字段设false省写入放大与磁盘doc_valuestrue不聚合不排序的字段设false省列式存储空间ignore_above无keyword设 256防超长值撑爆索引normstrue仅筛选用途设false省每文档一字节fielddatafalse永远不在text上开极易 OOM5.3 冷热分层让老数据不再抢资源数据是有温度分布的。最近三天的日志每小时被查几百次三个月前的可能一年都不看一次但两者在集群里占着同样的资源。冷热分层的思路是把它们分开。具体做法是给节点打上属性标记比如node.attr.tier: hot和node.attr.tier: warm然后在索引上设index.routing.allocation.require.tier: hot强制分片只能落在对应节点。再配一套生命周期策略热阶段保持正常刷新和 1 个副本超过 7 天进温阶段合并段、降副本、迁移到温节点超过 90 天直接删除。温节点可以用配置低一些的机器甚至用大容量机械盘因为这部分数据只读不写对 CPU 和 IO 的要求低得多。我做过一个日志项目冷热分层之后热节点数量砍掉一半查询 P99 反而降了因为热节点上的分片少了集群状态和归并压力都小了。生命周期的策略模板大概长这样可以直接改改就用PUT _ilm/policy/logs_policy { policy: { phases: { hot: { actions: { rollover: { max_primary_shard_size: 30gb, max_age: 1d }, set_priority: { priority: 100 } } }, warm: { min_age: 7d, actions: { forcemerge: { max_num_segments: 1 }, shrink: { number_of_shards: 1 }, allocate: { require: { tier: warm } }, set_priority: { priority: 50 } } }, delete: { min_age: 90d, actions: { delete: {} } } } } }要注意forcemerge和shrink都很重一定要放在温阶段而不是热阶段并且错开业务高峰。还有rollover的别名必须指向单个索引、并且别名得带is_write_index标记这个细节漏了会一直抱错。6. 生产环境常见故障排查实录6.1 集群变黄变红按这个顺序看先说颜色含义很多人会记反。绿色是所有主分片和副本都分配好了黄色是所有主分片都在但有副本没分配红色是有主分片没分配意味着有数据查不到。所以黄色通常不致命数据完整只是冗余度不够红色必须立刻处理。排查顺序我固定是四步。第一步看整体GET _cluster/health?levelindices直接定位是哪个索引出问题。第二步看分片清单GET _cat/shards?vhindex,shard,prirep,state,unassigned.reason加个过滤只看未分配的。第三步对具体分片做诊断GET _cluster/allocation/explain这个接口会把“为什么没分配”讲得非常清楚包括所有节点的拒绝理由。第四步才是动手根据原因决定是调水位、调过滤条件、还是手动重路由。# 1. 集群整体与逐索引健康状况 GET _cluster/health?levelindices # 2. 只看未分配的分片及其原因 GET _cat/shards?vhindex,shard,prirep,state,unassigned.reasonsstate # 3. 让集群自己解释为什么不分 GET _cluster/allocation/explain # 4. 节点磁盘与分片分布 GET _cat/allocation?v GET _cat/nodes?vhname,heap.percent,disk.used_percent,load_1m注意不要看到黄色就急着手动重路由。手动_reroute会绕过分配器的判断可能把分片塞到一个本来就快满的节点上几天后引发更大的问题。先让allocation/explain把话说完。6.2 未分配分片的典型原因速查原因标记实际含义常见触发处理方向NODE_LEFT节点离线重启、宕机、网络分区等节点回来或调副本数DISK_THRESHOLD磁盘超水位数据增长未及时扩容清理或扩盘临时调水位ALLOCATION_FAILED分配失败段损坏、映射冲突看 explain 详情必要时恢复快照CLUSTER_RECOVERED集群刚恢复全量重启耐心等别急着干预REPLICA_ADDED新增副本调高了副本数等同步完成NO_VALID_SHARD_COPY无可用副本主副本同时丢失从快照恢复AWAITING_INFO等待信息主节点刚选举完等几分钟这张表我贴在运维文档里出问题对着查八成能直接定位。特别说一下DISK_THRESHOLD如果只是临时超了、马上要扩盘可以临时把水位调高应急处理完记得调回来PUT _cluster/settings { transient: { cluster.routing.allocation.disk.watermark.low: 90%, cluster.routing.allocation.disk.watermark.high: 93%, cluster.routing.allocation.disk.watermark.flood_stage: 97% } }调完记得把索引的index.blocks.read_only_allow_delete解除否则即使水位降下来索引还是只读的。这一步最容易漏我见过有人调了水位、等了半天还是写不进去最后发现只读锁没解。6.3 写入被拒绝线程池和批量大小报错es_rejected_execution_exception说明线程池队列满了。写线程池的队列默认是 200搜索线程池默认是 1000队列一满就直接拒绝不做等待。这其实是很好的保护机制——与其让请求堆积把节点拖死不如快速失败让客户端重试。遇到这个错先分清是写入还是查询。写入被拒通常是三种情况批量请求太大一次几万条、集群在合并段、副本同步跟不上。对应的处理是把批量请求控制在 5~15MB别按条数算按体积算检查段数量和合并状态适当降低并发。这里有个反直觉的点批量导入时并发数不是越高越好。我做过对比8 个并发灌数据比 32 个并发的总耗时更短因为高并发下大量请求在队列里排队、触发拒绝和重试实际有效吞吐反而下降。找到那个拐点比一味加并发有用得多。6.4 查询变慢一条从外到内的定位路径查询慢的原因多得数不清我习惯按“从外到内”的顺序排查。先看是不是深分页或大批量聚合from size太大、聚合桶太多再看是不是查询本身写得烂前缀通配符*xxx、正则、脚本查询然后看段数量某分片段数远超别人说明合并跟不上最后看资源和缓存堆压力、查询缓存命中率、页缓存是否够。性能剖析接口profile能给出每个子查询的耗时占比比自己猜高效得多。慢查询日志也一定要开 thresholds 设成 warn 1s、info 500ms 这种量级事后复盘全靠它。PUT /my_index/_settings { index.search.slowlog.threshold.query.warn: 1s, index.search.slowlog.threshold.query.info: 500ms, index.search.slowlog.threshold.fetch.warn: 500ms }还有一个很容易被忽略的点分片分布不均。如果某个节点上的分片数明显多于其他节点它的负载就更高查询会拖后腿。用_cat/allocation看一眼就知道必要时用分配过滤或者重平衡来匀一匀。7. 一份能直接抄的巡检清单与参数模板巡检这事儿与其每次出问题现查不如固定成清单每天跑一遍。我用的清单大致分四块。集群层面看健康状态、节点数、主节点是否稳定有没有频繁选举——那通常意味着网络或 GC 有问题。资源层面看堆使用率长期 75% 以上就该扩容了、磁盘使用率85% 是红线、负载。索引层面看分片数、段数量、未分配分片、只读索引。业务层面看写入拒绝次数、慢查询数量、P99 延迟。对应的几条常用命令GET _cluster/health GET _cat/nodes?vhname,role,heap.percent,disk.used_percent,load_1m,node.role GET _cat/indices?vhindex,health,pri,rep,docs.count,store.sizesstore.size:desc GET _cat/shards?vhindex,shard,prirep,state,nodesstate GET _nodes/stats/thread_pool,indices/fielddata?human一个我反复用的索引模板把前面说的那些“该关的关掉、该限的限上”都写进去了PUT _index_template/app_template { index_patterns: [app-*], template: { settings: { number_of_shards: 6, number_of_replicas: 1, refresh_interval: 5s, index.mapping.total_fields.limit: 1000, index.max_result_window: 10000, index.merge.scheduler.max_thread_count: 1, index.translog.durability: request, index.search.slowlog.threshold.query.warn: 1s }, mappings: { dynamic: strict, properties: { title: { type: text, fields: { raw: { type: keyword, ignore_above: 256 } } }, category: { type: keyword }, price: { type: scaled_float, scaling_factor: 100 }, created: { type: date }, detail: { type: text, index: false } } } } }刷新间隔设成 5 秒而不是默认的 1 秒是我在多数业务索引上的默认选择——写入吞吐能提升一截而 5 秒的可见性延迟在业务上基本感知不到。只有那些强读后写场景的索引才需要单独调回 1 秒并在写入时用wait_for兜底。批量灌数据的时候除了前面说的副本设 0、刷新关掉还有两个配套动作值得一起做把index.translog.durability临时改成async减少每次请求的 fsync灌完之后手动 refresh 一次、把副本调回来、再跑一次强制合并如果是只读的历史数据。这套组合拳下来同样数据量的导入时间通常能压缩到原来的三分之一左右。最后分享一个小习惯我每接一个新集群第一件事不是建索引而是把上面那几条巡检命令跑一遍记下当时的堆、磁盘、段数量作为基线。后面出任何异常跟基线一比问题范围立刻缩小一大半。这套做法比任何监控大盘都来得直接因为它用的是你自己的数据而不是别人的经验值。
延伸阅读

更多相关文章

2026/11/6 15:14:32

C#交互式绘图:图元、坐标变换与鼠标状态机实战

简介:这份C#交互式绘图代码资源面向具备一定C#基础、希望掌握GDI图形编程的开发者,通过完整项目实例解决窗体绘图与用户交互结合的实际问题。压缩包共383个文件,约1.17MB,以84个cs源码文件为核心,配合22个resx与24个re…

2026/11/7 0:08:42

SQLAlchemy电商数据分析实战与优化技巧

1. Python与SQLAlchemy实战:电商销售数据分析全流程作为一名长期从事电商数据分析的Python开发者,我经常需要处理海量销售数据。SQLAlchemy作为Python生态中最强大的ORM工具,能显著提升数据操作效率。今天我将分享如何用SQLAlchemy构建完整的…

2026/11/6 21:24:04

大模型SQL生成优化:解决语法错误与结果不一致问题

1. 问题现象与背景分析最近在Dify平台上使用大模型生成SQL查询时,遇到了两个典型问题:一是生成的SQL语句存在语法错误无法执行,二是相同问题多次询问得到差异较大的答案。这类问题在实际业务场景中尤为棘手,特别是当我们需要将AI生…

2026/11/7 0:28:09

龙游县电工证怎么考网上查询

龙游县电工证怎么考网上查询 你是不是学历不高,担心自己考不了龙游县电工证?别急,这期内容就给你说清楚怎么搞定这个证,还有网上查询怎么操作,别让学历成为你上手电工行业的绊脚石。 一、电工证在龙游县的报考条件有哪些? 先说重点: 学历不是门槛…

2026/11/7 0:28:09

电力电缆证在哪复审多少钱?实操考试心里没底怕挂科

电力电缆证在哪复审多少钱?实操考试心里没底怕挂科 实操考试心里没底怕挂科,你不是一个人。很多人第一次报考电力电缆证时,都担心自己操作不熟练,一不小心就挂科。尤其是在河南,像商丘这样的城市,电力电缆作业是市政工程里最常见、最基础的岗位之一,但…

2026/11/7 0:28:09

隆回电工证培训机构排名曝光:真实经历告诉你怎么避坑

隆回电工证培训机构排名曝光:真实经历告诉你怎么避坑 怕考不过白交培训费?我身边就有人因为选错培训机构,花了几千块最后连考试都没通过。别急,这篇讲的是隆回电工证培训机构排名的干货,全是真实经历,帮你少走弯路。…

2026/11/7 0:28:09

无操作证从事特种作业多少钱?工地太忙根本没时间复习考试

无操作证从事特种作业多少钱?工地太忙根本没时间复习考试 工地太忙根本没时间复习考试,你是不是也经常在工地上头昏脑涨,连手机都顾不上看?更别提抽时间去复习特种作业操作证的考试内容了。很多人觉得, 无操作证从事特种作业…

2026/11/7 0:28:09

大专如何报考电工证多久拿证 证书过期了不知道怎么复审延期

大专如何报考电工证多久拿证 证书过期了不知道怎么复审延期 证书过期了不知道怎么复审延期,这个问题在洛阳涧西区不少转岗从业者身上都出现过。尤其是持有电工证的朋友,很多人在换工作、换行业后,忽视了证书的有效期和复审时间,导致证书失效,影响了后续…

2026/11/7 0:23:09

自贡电工证报考多久拿证?学历不高怕报不上名怎么解决

自贡电工证报考多久拿证?学历不高怕报不上名怎么解决 你是不是也这样想:“我学历不高,连初中都没读完,还能不能报考自贡电工证?”这个问题,我在安阳的一个劳务班组里遇到过,他们班组长老张,就是典型的“半文盲”,但照样考到了低压电工证,现在成了项…

2026/11/5 15:39:06

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/6 10:49:01

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/7 0:03:08

郑州报考避坑指南:电工证和钳工证怎么选?实操考试心里没底怕挂科

郑州报考避坑指南:电工证和钳工证怎么选?实操考试心里没底怕挂科 实操考试心里没底怕挂科?你不是一个人。特别是在郑州这样的城市,很多施工企业负责人和一线作业人员在报考电工证和钳工证时都面临着同样的困惑。到底该考哪个证?哪个更适合自己?哪个证书…

2026/11/7 0:03:08

广西电工证办理流程全解析:外省证怎么转?在哪考最靠谱?

广西电工证办理流程全解析:外省证怎么转?在哪考最靠谱? 之前考的证在外省能不能转过来?这个问题我遇到太多了,今天就拿广西电工证办理流程来具体说说,别再走弯路了。广西电工证的报考、复审、继续教育这些环节,如果你不了解,真的会吃大亏,尤其对于从…

2026/11/7 0:03:08

电气电工证都有哪些保姆级教程

电气电工证都有哪些保姆级教程 你是不是正愁不知道去哪报名,怕被中介坑?别急,这篇保姆级教程专为河南初次报考人员准备,帮你搞清楚 电气电工证都有哪些 ,以及如何避开那些坑。 电气电工证都有哪些?别被五花八门的证书搞懵了…

2026/11/5 15:39:06

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/6 10:49:01

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑