Elasticsearch 中的Shard(分片)和 Replica(副本)
在 Elasticsearch (ES) 中,Shard(分片) 和 Replica(副本) 是其分布式架构的核心概念。理解它们对于设计高性能、高可用的搜索集群至关重要。
简单来说:
- Shard (分片):是为了水平扩展(能存更多数据,能并行处理)。
- Replica (副本):是为了高可用(数据不丢)和提升读取性能(并发查询)。
1. Shard(分片 / 主分片)
在 ES 中,一个 Index(索引) 可能包含海量的数据,这些数据可能超过了单个节点的硬件限制(如硬盘容量、处理能力)。为了解决这个问题,ES 将索引划分为多个部分,每一部分就叫做一个 Shard。
通常我们说的 Shard 指的是 Primary Shard(主分片)。
- 本质:每一个 Shard 本质上都是一个独立的、功能完整的 Lucene 索引。
- 作用:
- 水平扩展:允许将一个大索引的数据分布在集群的不同节点上。
- 并行处理:查询时,ES 可以同时在多个分片上并行搜索,从而提高性能。
- 关键特性:
- 数量固定:在创建索引时,主分片的数量一旦指定,通常不能修改(除非使用 Reindex 重建索引,或者使用 Split/Shrink API,但代价较高)。
- 数据路由:ES 根据公式
shard = hash(routing) % number_of_primary_shards来决定文档存储在哪个分片上。如果分片数量变了,这个公式就失效了,导致找不到数据。
2. Replica(副本 / 副本分片)
为了防止硬件故障导致数据丢失,以及提高搜索的吞吐量,ES 允许为每个主分片创建一份或多份拷贝,这些拷贝叫做 Replica Shard(副本分片)。
- 本质:它是主分片的精确复制。
- 作用:
- 高可用性 (High Availability):如果存放主分片的节点挂了,ES 会自动将对应的副本分片提升(Promote)为新的主分片,确保服务不中断。
- 提升读取性能 (Read Throughput):搜索请求可以在主分片或副本分片上执行。增加副本数量可以分担查询压力,提高并发读取能力。
- 关键特性:
- 动态调整:副本的数量可以随时动态修改(通过 Update Settings API)。
- 反亲和性:副本分片永远不会和它的主分片在同一个节点上。如果在同一个节点,一旦该节点挂了,主备全丢,副本就失去了意义。
3. 图解示例
假设我们有一个集群,包含 3个节点。
我们创建一个名为 users 的索引,配置为:3个主分片 (P),1个副本 (R)。
总共会有 6 个分片实例(3个主 + 3个副本)。ES 会自动将它们均匀分布,可能如下所示:
| Node 1 | Node 2 | Node 3 | |
|---|---|---|---|
| P0 | ✅ (主分片 0) | ||
| R0 | ✅ (副本 0) | ||
| P1 | ✅ (主分片 1) | ||
| R1 | ✅ (副本 1) | ||
| P2 | ✅ (主分片 2) | ||
| R2 | ✅ (副本 2) |
- 如果 Node 1 挂了:
- P0 丢失。
- ES 检测到 Node 2 上有 R0。
- ES 将 Node 2 上的 R0 提升为新的 P0。
- 集群状态变黄(Yellow),因为缺少了 R2 和 新的 R0(原本在Node 1上)。
- 如果 Node 1 恢复或有新节点加入,ES 会重新复制数据补齐副本,集群变绿(Green)。
4. 写入与读取流程的区别
写入 (Write):
- 请求发送到协调节点。
- 根据路由计算,请求被转发到对应的 主分片 (Primary Shard)。
- 主分片执行写入。
- 如果成功,主分片将请求并行转发给所有的 副本分片 (Replica Shards)。
- 一旦所有(或满足配置的)副本写入成功,主分片向客户端报告成功。
- 结论:写入性能主要受限于主分片,且副本越多,写入越慢(因为要同步)。
读取 (Read/Search):
- 请求发送到协调节点。
- 协调节点通过轮询算法(Round-robin),在主分片和副本分片中选择一个来处理请求(负载均衡)。
- 结论:副本越多,读取的并发能力越强。
5. 最佳实践与常见问题
Q: 我应该设置多少个分片?
这是一个经典的容量规划问题。没有标准答案,但有经验法则:
- 分片大小:建议单个分片的大小保持在 10GB 到 50GB 之间。
- 太小:会导致过多的元数据开销(Lucene segment 合并压力大,JVM 堆内存占用高)。
- 太大:数据恢复(Rebalance)极慢,且一旦该分片所在节点故障,恢复时间很长。
- 节点与分片比:通常建议每 1GB 堆内存对应 20-25 个分片。
Q: 我应该设置多少个副本?
- 开发环境:0 个副本(节省空间)。
- 生产环境:至少 1 个副本(保证高可用)。
- 读多写少场景:可以适当增加副本数量(如 2-3 个),以提升查询吞吐量。
Q: 为什么主分片数量不能随便改?
因为 ES 存储文档时是根据 hash(id) % 主分片数 来决定存哪里的。如果存的时候分片数是 5,取的时候分片数变成了 6,取模的结果就不一样了,ES 就不知道去哪个分片找这个数据了。
总结对比
| 特性 | Primary Shard (主分片) | Replica Shard (副本分片) |
|---|---|---|
| 主要目的 | 存储数据、水平扩展、写入入口 | 高可用(容灾)、提升读取吞吐量 |
| 写入能力 | 负责处理写操作 | 被动同步主分片的数据,不直接处理写 |
| 读取能力 | 可以处理读操作 | 可以处理读操作 |
| 数量设置 | 创建索引时指定,通常不可变 | 可以随时动态修改 |
| 位置限制 | 无 | 不能与对应的主分片在同一节点 |
| 性能影响 | 决定了索引的最大容量和写入并发 | 副本越多,读越快,但写越慢(同步开销) |
右滑查看面试常问