惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

V
Vulnerabilities – Threatpost
aimingoo的专栏
aimingoo的专栏
B
Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
GbyAI
GbyAI
阮一峰的网络日志
阮一峰的网络日志
Engineering at Meta
Engineering at Meta
IT之家
IT之家
V
Visual Studio Blog
The Cloudflare Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
A
About on SuperTechFans
博客园 - 聂微东
Blog — PlanetScale
Blog — PlanetScale
N
News and Events Feed by Topic
A
Arctic Wolf
WordPress大学
WordPress大学
小众软件
小众软件
C
CERT Recently Published Vulnerability Notes
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
D
Darknet – Hacking Tools, Hacker News & Cyber Security
F
Fortinet All Blogs
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Y
Y Combinator Blog
T
Threat Research - Cisco Blogs
Latest news
Latest news
Simon Willison's Weblog
Simon Willison's Weblog
Cyberwarzone
Cyberwarzone
S
Schneier on Security
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
L
Lohrmann on Cybersecurity
Stack Overflow Blog
Stack Overflow Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
P
Privacy International News Feed
J
Java Code Geeks
Spread Privacy
Spread Privacy
宝玉的分享
宝玉的分享
I
Intezer
L
LangChain Blog
Hacker News - Newest:
Hacker News - Newest: "LLM"
G
GRAHAM CLULEY
博客园 - 叶小钗
博客园 - 三生石上(FineUI控件)
The GitHub Blog
The GitHub Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
N
News and Events Feed by Topic
AWS News Blog
AWS News Blog
Attack and Defense Labs
Attack and Defense Labs
Security Archives - TechRepublic
Security Archives - TechRepublic
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO

博客园_首页

Linux实操--组管理、权限管理和定时任务 Java + EasyExcel 实现单个接口导出多个Excel Mem0 源码解析系列(二):提示词工程的深度剖析 Openclaw TaskFlow究竟是什么?和普通Skill技能有什么区别 博文阅读密码验证 - 博客园 嘉立创开源:应该是全网MicroPython教程最多的开发板 Hermes Agent 集成实践:从协议到生产 2026年AI编程工具横评:Cursor、Codex、Claude Code、Zed、Windsurf Java程序员必看的RAG入门教程 2026 AI效率神器:Superpowers + Claude Code 保姆级教程 本地大模型部署全攻略:从 0 到 1 玩转 Ollama 【从0到1构建一个ClaudeAgent】内存管理-上下文压缩 .NET 高级开发 | 设计、实现一个事件总线框架 电子小白入门之NE555 3. WorkBuddy:隐藏玩法,一键召唤专家,让 AI 以"专家身份"给你干活 和AI一起搞事情#3:Claude Teammate 游戏开发翻车实录 【OpenClaw】通过 Nanobot 源码学习架构---(7)Memory C# .NET 周刊|2026年3月3期 我在 Debian 11 上把 K8s 单机搭起来了,过程没你想的那么顺(/opt 目录版) 深度学习进阶(七)Data-efficient Image Transformer CLI+Skill搭建浏览器AI自动化框架,告别一切重复枯燥任务 告别Token账单无底洞:OpenClaw本地部署,重塑企业数据主权的唯一解 FastAPI+Vue:文件分片上传+秒传+断点续传,这坑我帮你踩平了! SBTI 爆火后,我做了个程序员版的 CBTI。。已开源 + 附开发过程 多模态检索开始进入工程期:用 Sentence Transformers 搭建可落地的 Multimodal RAG 100多行代码实现一个最简单的Agent(用ReAct) Claude Code 通关手册(八):推荐 5 个 Hooks,代码质量提升 3 倍 老板:“有人截图了!”。安全部门:“收到,马上查暗水印!” - why技术 技术之外,皆是人间 C#/.NET/.NET Core技术前沿周刊 | 第 69 期(2026年4.01-4.12) Snack JSONPath 项目架构分析 Claude Code Buddy 小析:一个非核心功能,如何体现产品的细节完成度 AI新时代下的图床管理方案-Cloudflare图床+MCP+Skills方案指南 化繁为简:顺丰速运App如何通过 HarmonyOS SDK实现专业级空间测量 从零实现富文本编辑器#13-React非编辑节点的内容渲染 AI开发-python-langchain框架(3-23-OpenAI Functions风格Tool Calling智能助手) .NET + AI 进阶实战:基于类的技能开发 - 打造可治理的 Agent 能力模块 【从0到1构建一个ClaudeAgent】规划与协调-技能 上周热点回顾(4.6-4.12) 电子小白的工具三件套:面包板、杜邦线、万能板 单表五亿数据的查询优化 | Mysql、StarRocks 2. WorkBuddy:从“我是谁”到“帮我干活” C# 如何减少代码运行时间:7 个实战技巧 基于HelixToolkit.SharpDX 渲染3D模型 - 笺上知微 从零开始的双臂具身VLA起源及现阶段发展综述 - SkyXZ 记对 xonsh shell 的使用, 脚本编写, 迁移及调优 - pluvium27 受够了Vibe Coding的失控?换个起点,让AI事半功倍 从开始配置漏洞环境到漏洞复现流程 - 難しい 关于10年工作经验的程序员对OpenClaw的实战经验分享以及看法 - 虚无境 Any metadata 的内存布局 C# .NET 周刊|2026年3月2期 - InCerry 我帮你测过了,测试圈排名第二的 Skill 依然很牛逼 Skill Discovery | 无监督技能发现的经典工作总结 - MoonOut PbootCMS 网站内容数量多导致访问慢?这些实用优化方案帮你提速! - 家兴网络技术工作室 上下文工程是什么?过时了么?一文讲明白! - 一枫说码 网站漏洞怎么发现并修复?一篇实用指南(附完整流程) - 家兴网络技术工作室 开了 TUN 模式还是直连?90% 的人都踩过这个坑 Github日报|2026年04月12日 - AI一族 AScript扩展多种脚本语言 - rockey627 AI 学习笔记:Agent 的记忆机制 你能被装进一个文件里吗?——7 万人把同事"蒸馏"成了 AI - 我没有三颗心脏 Claude Code 通关手册(七):给 AI 装上技能包——Skills 完全指南 - 暮色之狐 在浏览器中快速编辑代码:VSCode Web 集成实践 - Newbe36524 蒸馏自己 skill?基于 Deepseek 的蒸馏器,丐版蒸馏方式,简单便捷 - To_Carpe_Diem Spring AI Aliababa和AgentScope,哪个更好? - 苏三说技术 Etsy 把 1000 个 MySQL 分片迁进 Vitess:425TB 数据背后的真正问题不是性能,而是运维规模 MicroPython LVGL基础知识和概念:底层渲染与性能优化 - FreakStudio 数据库草图算法 Python 潮流周刊#146:CPython 引入 Rust 的进展 - 豌豆花下猫 最小生成树 - mofei1116 红日靶场七:从外网入口、容器逃逸到 AD 接管的完整利用链复盘 - YouDiscovered1t 分享四款开源且实用的 Kafka 管理工具 - 追逐时光者 vLLM 权重加载机制全解析:从挑战到理想架构 LCT 学习笔记 - ACehomoxue Avalonia UI 12.0.0 正式发布:架构演进和性能飞跃 - 张善友 当 AI Agent 把调用链拉长,延迟开始成为一门生意 conhost.exe 无法显示 U+2717 - 145a 太秀了,我把自己蒸馏成了 Skill!已开源 - 程序员鱼皮 ASP.NET Core 内存缓存实战:一篇搞懂该怎么配、怎么避坑 基于 Ghostty 带有分割标签页和为 Claude 编程设计的通知终端 - BugShare AI 焊死入口:教育的“操作系统级”重塑 - 郝hai 初级Java开发工程师使用sql脚本编写代码的过程是简单而且不糊涂 - CoderOilStation Claude Code通关手册(六):MCP协议完全指南 - 暮色之狐 边框灯光环绕动画特效实现指南 - Newbe36524 开源:子木蒸馏版的 SEO 审计工具 seo-audit-skill v1.0 我所理解的Python元模型 【从0到1构建一个ClaudeAgent】规划与协调-TodoWrite - 程序员Seven Claude 和 Codex 在审计 Skill 上性能差异探究 - ACai_sec AScript如何实现中文脚本引擎 - rockey627 【渗透测试】HTB Season10 Garfield 全过程wp - dynasty_chenzi Android 开发者为什么必须掌握 AI 能力?端侧视角下的技术变革 树状数组正确性证明 - AC-wyr 你的 AI 焦虑,可能比 AI 本身更危险——ATM 机没有消灭银行柜员,但恐慌消灭了你的判断力 - 我没有三颗心脏 一个拉胯的分库分表方案有多绝望?整个部门都在救火! - 冰河团队 动态规划入门必学之走方格问题 - Ofnoname PostgREST 与 PostgreSQL 角色权限配置全解析(生产级实践) - SheepDog1998 使用 UEFI 图形输出协议 GOP 在屏幕上显示图像的方法 - 阿源- Claude Code通关手册(五):组建你的AI专家团队,子代理系统 - 暮色之狐 一个程序员到架构师的催婚路之感悟(整整10年后的催婚相亲感悟) - MisterLip 用 Agent Skill 自动生成工作周报 - 赵康
ElasticSearch主分片和副本分片概念详解
huangSir-devops · 2026-04-17 · via 博客园_首页

主分片概述

ES 主分片的本质是独立的 Lucene 实例,主分片负责数据的写入、修改、删除等操作,可以理解成凡是写入操作一定会走主分片。
ES中有一个文档(doc)的概念,每一个文档只会属于一个主分片.

例如一个ES索引有三个主分片分别在A、B、C三个集群节点上,当一个user的doc需要写入时,那么这个user的doc只会在其中一个主分片上,而不是在每个集群节点上都有。

主分片数量在ES索引创建时指定,当索引创建完成之后,则不允许再修改主分片的数量,例如下面的案例:

# 创建一个索引,指定主分片数量为3
PUT /test01
{
  "settings": {
    "number_of_shards": 3
  }
}

# 然后再尝试修改其主分片数量
PUT /test01/_settings
{
  "settings": {
    "number_of_shards": 3
  }
}

# 报错如下:
{
  "error" : {
    "root_cause" : [
      {
        "type" : "illegal_argument_exception",
        "reason" : "Can't update non dynamic settings [[index.number_of_shards]] for open indices [[test01/FPlsR0XQQba41Fr_2_8m7g]]"
      }
    ],
    "type" : "illegal_argument_exception",
    "reason" : "Can't update non dynamic settings [[index.number_of_shards]] for open indices [[test01/FPlsR0XQQba41Fr_2_8m7g]]"
  },
  "status" : 400
}

当我们指定主分片数量时,主分片数量并不是越多越好,在不考虑机器性能的情况下,主分片数量一般是根据其ES集群节点数量及索引存储的数据量来决定,有几个参考值:

  • 单个主分片大小控制在 20GB ~ 50GB 范围内,性能最优。
  • 主分片数量一般是集群节点的1-3倍。例如3节点的集群,一个索引的主分片数量可以为3/6/9。

当然这些仅仅只是参考,例如一个索引的存储的数据量仅仅只有几个G,那么此时只需要给一个主分片即可。

为什么呢?
上文说过 ES 主分片的本质是独立的 Lucene 实例,每个分片都要占用独立的系统资源、元数据开销、调度开销,数据量小的时候多分片的弊端会被无限放大,收益为负,具体体现在5个维度:

1、堆内存资源严重浪费(最直观的影响),每个 Lucene 实例都要占用固定的堆内存来存储:索引元数据(段信息、倒排词典、字段缓存、过滤器缓存等),写入/查询线程上下文、连接资源,分片级别的监控、统计数据。在小分片场景下,这些固定开销的占比会极高。
例如:1GB 索引用 1 个分片,元数据开销约 10~30MB,占比 1%~3%,而1GB 索引用 10 个分片,元数据总开销约 100~300MB,占比 10%~30%

2、查询性能不升反降(最影响业务的问题)
ES 查询的标准流程是:协调节点接收请求 → 路由到所有相关分片 → 每个分片独立执行查询 → 协调节点聚合所有分片的结果 → 返回给用户。
当主分片越多,调度开销+聚合开销越大。
比如 1GB 索引用 1 个分片:只需要执行1次查询,无需聚合,延迟 10ms 以内
比如 1GB 索引用 10 个分片:需要执行10次查询,还要合并10份结果,延迟会变成 30~50ms,是单分片的 3~5 倍
高并发场景下还会放大问题:协调节点要同时处理大量分片级别的请求,很容易出现CPU占满、OOM等问题。

3、集群元数据管理压力指数级上升(影响集群稳定性)
ES Master 节点需要管理全集群所有分片的元数据,分片越多,会导致集群状态(Cluster State)体积越大,Master 同步元数据到所有节点的耗时越长,创建/删除索引、分片分配、节点上下线等集群操作的执行速度越慢,极端情况会导致 Master 卡顿、集群无响应,元数据写入持久化的频率越高,Master 磁盘IO压力越大。
生产经验:总分片数超过 1 万的集群,稳定性会明显下降,很多操作都会变慢。

4、写入性能不会提升反而下降
很多人误以为「分片越多写入越快」,但小数据量场景下完全相反,当写入时需要计算路由决定写到哪个分片,分片越多路由开销越大。每个分片都要独立执行段合并、刷新磁盘等操作,小分片会产生大量小的段文件,合并开销翻倍。单分片写入性能本身就可以达到 5000~20000 TPS,小数据量(日写入低于 100GB)完全不需要多分片来扛写入压力。

5、运维复杂度大幅提升
分片分配、迁移、恢复的成本更高:集群扩容、节点故障时,大量小分片需要在节点之间移动,总耗时比少分片更长。
问题排查更难:分片越多,出现未分配分片、分片损坏的概率越高,定位问题更麻烦。
快照备份/恢复速度变慢:快照需要遍历所有分片的元数据,分片越多备份耗时越长。

然后ES的读写并行能力是由主分片数量来进行控制的,当主分片数量越多,那么读写并发支持的越多,但是读写不一定更快。

这里简单说一下,当一台32C/64G 节点,NVMe SSD,单分片大小 20~30GB支持500-25000左右的QPS,这里根据写入的场景来划分、例如写入一个极为复杂的文档,且写入的数据量超过10KB,那么QPS可能只有500 ~ 3000,当写入一个简单的文档,例如日志等,那么QPS可能为8000-25000左右的QPS

主分片存储数据量大小控制

上文有说过,主分片存储数据量大小推荐为20-50GB,那么怎么控制主分片存储的数据量大小呢?

  • 方式一:预估主分片数量
    在创建索引之前,需要预估一下该索引可能会存储多少数据?例如该索引会存储100GB数据,那么有3个集群节点,则这个索引给3个主分片即可

  • 方式二:使用Rollover + ILM自动滚动(推荐)
    最适合日志/指标/订单等按时间生成的时序数据,ES自动监控分片大小/时间,超过阈值自动生成新索引,永远不会出现超大分片:

示例:

PUT _ilm/policy/log_ilm_policy
{
  "policy": {
    "phases": {
      "hot": {
        "actions": {
          "rollover": {
            "max_size": "30GB",  // 单分片到30G自动滚动
            "max_age": "7d",     // 或者满7天自动滚动,哪个条件先到就触发
            "max_docs": 10000000 // 或者满1000万条自动滚动
          }
        }
      },
      "delete": {
        "min_age": "30d", // 超过30天自动删除
        "actions": { "delete": {} }
      }
    }
  }
}

当索引的分片存储数据量太大怎么解决呢?

方案A:Split拆分(推荐,速度快,不需要全量reindex)

适用条件:分片数只能拆成原分片数的整数倍,比如原4分片可以拆成8/12/16个,不能拆成6个

# 1. 先把索引设为只读
PUT /超大索引名/_settings
{ "index.blocks.write": true }

# 2. 拆分,原4分片拆成8分片(必须是整数倍)
POST /超大索引名/_split/拆分后的新索引名
{
  "settings": {
    "index.number_of_shards": 8
  }
}

方案B:Reindex重建(通用,任何情况都适用)

适用条件:任意调整分片数,没有倍数限制,缺点是需要全量同步数据,数据量大的话耗时久

# 1. 创建新索引,设置合适的分片数
PUT /新索引名
{
  "settings": {
    "number_of_shards": 10, // 改成你需要的分片数
    "number_of_replicas": 1
  }
}
# 2. 全量同步数据
POST _reindex?wait_for_completion=true
{
  "source": { "index": "超大索引名" },
  "dest": { "index": "新索引名" }
}

当索引分片太小(碎片太多)时怎么解决呢?

方案A:Shrink合并(推荐,速度快,不需要全量reindex)

适用条件:分片数只能合并成原分片数的约数,比如原8分片可以合并成4/2/1个,不能合并成3个

限制:Shrink 时不能指定 mapping,只能沿用源索引 mapping
源索引必须所有分片 结构一致、正常 green、只读

# 1. 先把索引设为只读,并且所有分片移到同一个节点
PUT /小分片索引名/_settings
{
  "index.blocks.write": true,
  "index.routing.allocation.require._name": "你的节点名称"
}
# 2. 合并,原8分片合并成2分片(必须是约数)
POST /小分片索引名/_shrink/合并后的新索引名
{
  "settings": {
    "index.number_of_shards": 2
  }
}

方案B:多个小索引合并成一个大索引

适用条件:比如把7天的日索引(log-2026.04.10 ~ log-2026.04.16)合并成一个周索引,减少总分片数

_reindex 合并多个 mapping 不同的索引时,需要下面几点注意:
1、新索引必须提前创建好统一的 mapping
2、所有旧索引的数据都会往这个新 mapping 上靠
3、类型冲突时:旧数据类型 vs 新 mapping 类型不兼容 → 报错,兼容 → 自动转换
当旧索引有、新索引没有的字段 → 被丢弃(不写入)
旧索引没有、新索引有的字段 → 写入 null / 默认值

// 1. 创建新的周索引,设置合适的分片数
PUT /log-2026.04.week2
{ "settings": { "number_of_shards": 6 } }
// 2. 批量同步所有日索引数据
POST _reindex?wait_for_completion=true
{
  "source": { "index": ["log-2026.04.10","log-2026.04.11","log-2026.04.12","log-2026.04.13","log-2026.04.14","log-2026.04.15","log-2026.04.16"] },
  "dest": { "index": "log-2026.04.week2" }
}

文档的写入流程

ES中文档的写入和主分片有关系,我们可以来看下整个文档的写入流程

ES文档写入涉及到下面几个组件:

  • Client:客户端(REST/Java API)
  • Coordinating Node:协调节点(接收请求、路由、返回结果)
  • Primary Shard:主分片(写入核心,数据强一致)
  • Replica Shard:副本分片(异步 / 同步复制,高可用)
  • Memory Buffer(Index Buffer):内存缓冲(高速写入,不可搜索)
  • Translog:事务日志(断电恢复,数据不丢)
  • Segment(Lucene):段文件(倒排索引,可搜索)
  • Disk:持久化磁盘

其写入流程主要分为7个步骤:

  • 1、客户端发起请求->ES协调节点写入
    • 客户端发送:PUT /my_index/_doc/1
    • 请求到达任意节点,该节点成为 Coordinating Node(协调节点)
  • 2、路由计算 → 确定主分片
    • 默认按照_id哈希,当用户指定id时,会按照id字段哈希
    • 然后协调节点查询集群元数据,找到该主分片所在节点
      _id哈希公式:
shard_num = hash(_id) % number_of_primary_shards
  • 3、转发请求 → 主分片节点

    • 协调节点把请求转发给 主分片所在的数据节点
  • 4、主分片写入(核心!内存 + Translog)
    主分片所在节点执行:

    • 写入 Memory Buffer(Index Buffer)
      • 数据进内存,此时不可搜索
      • 写入速度极快(内存级)
    • 同步写入 Translog(事务日志)
      • 每条写入都追加到 Translog,并刷到磁盘(默认 request 模式,强一致)
      • 作用:宕机后从 Translog 恢复内存数据,防止丢失
  • 5、主分片 → 副本分片 同步

    • 主分片并行把请求发给其对应的所有副本分片
    • 副本分片执行和主分片一样的逻辑:写内存 + 写 Translog
    • 副本全部成功后,主分片才标记写入成功
  • 6、返回结果 → 客户端

    • 主分片向协调节点返回成功
    • 协调节点向客户端返回 201 Created
  • 7、后台异步(Refresh + Flush)
    7.1 Refresh(默认 1 秒,近实时搜索)

    • 触发:refresh_interval: 1s 或内存满
    • 动作:
      • Memory Buffer → 生成 新 Lucene Segment(倒排索引)
      • Segment 写入 OS Cache(文件系统缓存),不直接落盘
      • 此时文档可被搜索(NRT 近实时)
      • 清空 Memory Buffer
        7.2 Flush(默认 30 分钟,持久化)
    • 触发:30 分钟、Translog 达 512MB、手动 flush
    • 动作:
      • 所有内存 Segment → 强制刷到磁盘
      • 执行 Lucene Commit,生成 commit 点
      • 清空 Translog,释放空间

副本分片概述

ES中的副本分片是主分片的完全拷贝,数据上和主分片完全一致。

可以看上面文档的写入流程,当文档完全写入主分片和副本分片时才会标记文档写入成功

副本分片是实现ES高可用的基础,当主分片挂了之后,副本分片会自动升级为主分片。

此时有一个问题,当主分片挂了之后,副本分片升级为主分片之后,那么还会有主分片吗?
主分片挂了之后,可以理解成当前主分片的节点挂了,副本分片升级为主分片之后,此时是集群为yellow,是没有副本分片的。
主要当原主分片所在的节点恢复之后,此时整个集群变为green,副本分片才会恢复。

并且副本分片可以承载ES中读的请求,提高ES集群查询的吞吐量。

ES中同一份数据的主分片和副本分片永远不会分配在同一个节点上(ES内置反亲和规则,避免单节点故障同时丢主副)

例如当前集群有三个节点,主分片在A节点上,那么副本分片永远不会在A节点上,只会在B或者C节点中。

副本数可以动态调整,随时修改,不需要重建索引
示例:

# 创建一个索引,指定副本分片为1
PUT /test01
{
  "settings": {
    "number_of_shards": 3,
    "number_of_replicas": 1
  }
}
# 查看一下
GET /test01/_settings
# 返回结果
{
  "test01" : {
    "settings" : {
      "index" : {
        "routing" : {
          "allocation" : {
            "include" : {
              "_tier_preference" : "data_content"
            }
          }
        },
        "number_of_shards" : "3",
        "provided_name" : "test01",
        "creation_date" : "1776394680601",
        "number_of_replicas" : "1", # 副本分片数量
        "uuid" : "FSLjaib0Rv2JXvd_wlg2MQ",
        "version" : {
          "created" : "7172699"
        }
      }
    }
  }
}


# 修改副本分片数量
PUT /test01/_settings
{
  "settings": {
    "number_of_replicas": 2 #修改为2
  }
}

# 查看一下
GET /test01/_settings
{
  "test01" : {
    "settings" : {
      "index" : {
        "routing" : {
          "allocation" : {
            "include" : {
              "_tier_preference" : "data_content"
            }
          }
        },
        "number_of_shards" : "3",
        "provided_name" : "test01",
        "creation_date" : "1776394680601",
        "number_of_replicas" : "2", # 主分片为2
        "uuid" : "FSLjaib0Rv2JXvd_wlg2MQ",
        "version" : {
          "created" : "7172699"
        }
      }
    }
  }
}

副本分片设置注意事项

  • 不要把副本数设为0(临时导入数据除外):设0主分片挂了直接丢数据,导入完成后立刻改回1
  • 不要设超过2副本:3副本及以上性价比极低,写性能下降明显(写请求要同步到所有副本),存储成本过高,除非是金融级核心业务

可以给一个设置的参考

集群规模 业务等级 推荐副本数 说明
1节点测试集群 测试 0 单节点设副本也分配不了,浪费空间
2节点生产集群 普通业务 1 必须设1副本,任意节点挂了数据不丢
3节点及以上生产集群 普通业务 1 性价比最高,兼顾高可用和存储成本
3节点及以上生产集群 核心业务(不能停机) 2 允许同时挂2个节点还能正常提供服务,存储成本是1副本的1.5倍

文档的读取流程

文档的读取流程分为两种,一种是GET流程,一种是SEARCH流程。

文档的GET读取流程较于写入流程比较简单,其流程如下:

  • 客户端发起GET请求
GET /my_index/_doc/100
  • 请求到达协调节点
    任何一个节点都可以当协调节点,只负责路由 + 转发 + 聚合。

  • 协调节点 计算文档所在分片
    根据公式计算完成之后协调节点立刻知道:文档 100 只在 主分片 P2 及其副本 R2 上
    计算公式:

shard = hash(_id) % 主分片数
  • 协调节点 选择分片(负载均衡)
    它会在 主分片 + 所有副本分片中进行轮询(round-robin) 选一个:

    • 可能选 P2
    • 可能选 R2
  • 协调节点转发请求到选中的分片节点上
    该分片本地读取文档,直接返回。

  • 分片返回文档 → 协调节点 → 客户端

文档的SEARCH读取流程较于写入流程比较复杂

search分为 2 个阶段:

  • Query 阶段(分片本地查,只返回 id + 排序值)
  • Fetch 阶段(协调节点拉取真实文档)
第 1 阶段:Query 阶段(分散收集)
  • 客户端发起请求到协调节点
  • 协调节点把查询广播到 所有主分片 + 副本分片
  • 每个分片开始本地执行搜索
    • 匹配文档
    • 按相关性分数排序
  • 每个分片只返回:doc id + 分数 + 排序值
    • 注意:不返回完整文档! 轻量级
  • 查询结果全部返回给协调节点
Fetch 阶段(聚合拉取)
  • 协调节点把所有分片返回的 id进行:
    • 全局排序
    • 合并
  • 协调节点取最终 top N(如前 10 条)
  • 协调节点根据这 最终 topN 的 id,向对应分片发起获取真实文档请求
  • 对应分片返回完整文档内容
  • 协调节点封装结果 → 返回给客户端

search读取文档的关键点:

  • 搜索 = 查所有分片
    • 不管数据在哪,必须广播所有分片
  • 分片越多,搜索压力越大
  • 副本可以分担搜索压力
    • 协调节点会轮询主 / 副,实现搜索负载均衡
  • Query 只传 id,Fetch 才取文档
    • 减少网络传输,这是 ES 搜索快的原因之一
  • from + size 越深,性能越差,因为要合并的结果越多

超级汇总:主分片和副本分片的区别

对比项 主分片(Primary Shard) 副本分片(Replica Shard)
数据角色 原始数据、权威数据源 主分片的完整备份拷贝
是否接受写入 接受写入(唯一入口) 不接受写入,仅同步数据
数量是否可修改 创建后不可修改 可动态修改(随时增删)
故障影响 挂掉会导致分片不可用,需副本切换 挂掉不影响写入,仅降低可用性
高可用作用 提供完整数据,被副本依赖 主分片挂掉可升级为主分片
查询作用 提供查询服务 分担查询,提升并发能力
同节点分配 与自己的副本不能在同一节点 与对应主分片不能在同一节点