本章导读:在生产环境中,ElasticSearch集群的高可用性直接关系到业务的连续性。本章将从分片冗余机制出发,深入探讨多副本容灾、故障恢复、数据备份、跨机房容灾等核心技术,并结合真实生产案例,为你构建一套完整的企业级容灾体系。
一、分片冗余、多副本容灾原理与配置
1.1 分片机制核心原理
ElasticSearch 的数据分布和冗余机制是其高可用性的基石。
分片(Shard)的本质:
- 主分片(Primary Shard):承载数据的原始分片,负责处理所有写操作
- 副本分片(Replica Shard):主分片的完整拷贝,提供冗余和高可用读能力
┌─────────────────────────────────────────────┐
│ Index: logs │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Shard 0 │ │ Shard 1 │ │ Shard 2 │ │
│ │ (P0+R1) │ │ (P1+R2) │ │ (P2+R0) │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ │
│ P=Primary R=Replica │
│ 每个主分片有一个副本分片 │
└─────────────────────────────────────────────┘
1.2 多副本容灾配置实战
索引创建时指定副本数:
// 创建包含多副本的索引
PUT /orders
{
"settings": {
"number_of_shards": 3,
"number_of_replicas": 2 // 每个主分片有2个副本
}
}
// 动态修改副本数(不影响服务)
PUT /orders/_settings
{
"number_of_replicas": 3
}
副本分配策略优化:
// 强制副本不分配在同一节点
PUT /_cluster/settings
{
"persistent": {
"cluster.routing.allocation.awareness.attributes": "rack_id",
"cluster.routing.allocation.awareness.force.rack_id.values": "rack1,rack2,rack3"
}
}
// 节点启动时配置机架信息
// elasticsearch.yml
node.attr.rack_id: rack1
1.3 容灾原理深度解析
写入容灾流程:
Client → Primary Shard → 并行写入副本 → 返回成功
↓ (主分片故障)
Replica 提升为 Primary
读取容灾流程:
- 请求可路由到主分片或任意副本分片
- 副本故障不影响读取
- 主分片故障自动选举副本
关键配置参数:
| 参数 | 默认值 | 说明 |
|---|---|---|
wait_for_active_shards | 1 | 写入前需激活的分片数 |
index.write.wait_for_active_shards | 1 | 索引级写入确认机制 |
cluster.routing.allocation.total_shards_per_node | unbounded | 单节点最大分片数 |
二、集群故障自动恢复、手动兜底方案
2.1 自动恢复机制详解
Master 选举机制:
# 防止脑裂的关键配置
discovery.zen.minimum_master_nodes: (master_eligible_nodes / 2) + 1
# 7.x+ 版本(推荐)
discovery.type: zen
cluster.initial_master_nodes: ["node-1", "node-2", "node-3"]
分片自动恢复流程:
- Master 检测到节点离线
- 标记该节点上的主分片为不可用
- 将对应副本分片提升为主分片
- 重新分配缺失的副本分片
- 集群状态恢复 Green
恢复速度控制:
PUT /_cluster/settings
{
"persistent": {
"cluster.routing.allocation.node_initial_primaries_recoveries": 4, // 初始主分片恢复并发
"cluster.routing.allocation.node_concurrent_recoveries": 2, // 总并发恢复数
"indices.recovery.max_bytes_per_sec": "100mb" // 恢复限速
}
}
2.2 手动兜底方案
场景1:master 节点全部宕机
# 1. 查看集群状态
curl -X GET "localhost:9200/_cluster/health?pretty"
# 2. 强制从剩余节点中选举(紧急恢复)
# 在剩余节点上执行
curl -X POST "localhost:9200/_cluster/voting_config_exclusions?pretty" \
-H 'Content-Type: application/json' \
-d '{"node_names": ["dead_master_1", "dead_master_2"]}'
# 3. 重新配置 minimum_master_nodes
curl -X PUT "localhost:9200/_cluster/settings?pretty" \
-H 'Content-Type: application/json' \
-d '{"persistent": {"discovery.zen.minimum_master_nodes": 2}}'
场景2:集群状态为 Red(主分片丢失)
# 方案A:尝试恢复丢失的主分片(数据可能不完整)
curl -X POST "localhost:9200/_cluster/reroute?pretty" \
-H 'Content-Type: application/json' \
-d '{
"commands": [
{
"allocate_empty_primary": {
"index": "orders",
"shard": 0,
"node": "node-3",
"accept_data_loss": true
}
}
]
}'
# 方案B:从副本强制恢复(丢弃主分片可能有的新数据)
curl -X POST "localhost:9200/_cluster/reroute?pretty" \
-H 'Content-Type: application/json' \
-d '{
"commands": [
{
"allocate_stale_primary": {
"index": "orders",
"shard": 0,
"node": "node-2",
"accept_data_loss": true
}
}
]
}'
手动恢复决策树:
集群Red?
├─ 是 → 有副本?
│ ├─ 是 → 等待自动恢复(<5min)
│ │ ├─ 恢复成功 → 结束
│ │ └─ 超时 → 手动allocate_stale_primary
│ └─ 否 → 业务是否可接受数据丢失?
│ ├─ 是 → allocate_empty_primary
│ └─ 否 → 从备份恢复
└─ 否 → 观察Yellow状态,等待副本分配
三、数据备份与恢复:快照备份、定时备份策略
3.1 快照仓库配置
创建远程快照仓库(以HDFS为例):
# 1. 安装HDFS插件
bin/elasticsearch-plugin install repository-hdfs
# 2. 创建快照仓库
curl -X PUT "localhost:9200/_snapshot/hdfs_backup?pretty" \
-H 'Content-Type: application/json' \
-d '{
"type": "hdfs",
"settings": {
"uri": "hdfs://namenode:9000",
"path": "/es_backups",
"conf_location": "hdfs-site.xml",
"compress": true,
"chunk_size": "64mb"
}
}'
S3 快照仓库配置(推荐云环境):
PUT /_snapshot/s3_backup
{
"type": "s3",
"settings": {
"bucket": "es-backup-bucket",
"region": "ap-east-1",
"compress": true,
"base_path": "daily_backups",
"server_side_encryption": true
}
}
3.2 定时备份策略
使用 Curator 实现定时快照:
# curator_config.yml
client:
hosts:
- 10.0.0.1
- 10.0.0.2
port: 9200
actions:
1:
action: snapshot
description: "创建每日快照"
options:
repository: s3_backup
name: "es_snapshot_{{ ts() }}"
ignore_unavailable: false
include_global_state: true
partial: false
wait_for_completion: true
max_wait: 3600
filters:
- filtertype: pattern
kind: regex
value: '^(orders|users|products).*$'
Linux Crontab 定时执行:
# 每天凌晨2点执行快照
0 2 * * * /usr/bin/curator /opt/curator/curator_config.yml
# 快照清理策略:保留最近30天
0 3 * * * curl -X DELETE "localhost:9200/_snapshot/s3_backup/es_snapshot_*" \
-H 'Content-Type: application/json' \
-d '{"filter": {"age": {"direction": "older", "unit": "days", "count": 30}}}'
3.3 数据恢复实战
恢复整个集群:
# 1. 查看可用快照
curl -X GET "localhost:9200/_snapshot/s3_backup/_all?pretty"
# 2. 恢复指定快照(所有索引)
curl -X POST "localhost:9200/_snapshot/s3_backup/snapshot_2024_01_15/_restore?pretty"
# 3. 部分恢复(只恢复特定索引)
curl -X POST "localhost:9200/_snapshot/s3_backup/snapshot_2024_01_15/_restore?pretty" \
-H 'Content-Type: application/json' \
-d '{
"indices": "orders,users",
"ignore_unavailable": true,
"include_global_state": false,
"rename_pattern": "(.+)",
"rename_replacement": "restored_$1"
}'
恢复验证脚本:
#!/bin/bash
# 验证恢复数据完整性
SNAPSHOT_NAME="snapshot_2024_01_15"
INDEX_NAME="orders"
# 1. 检查索引状态
curl -s "localhost:9200/_cat/indices/$INDEX_NAME?v"
# 2. 对比文档数量
DOC_COUNT_SNAPSHOT=$(curl -s "localhost:9200/_snapshot/s3_backup/$SNAPSHOT_NAME/_status" | jq '.snapshots[0].stats.num_files')
DOC_COUNT_CURRENT=$(curl -s "localhost:9200/$INDEX_NAME/_count" | jq '.count')
if [ "$DOC_COUNT_SNAPSHOT" == "$DOC_COUNT_CURRENT" ]; then
echo "数据恢复完整"
else
echo "警告:数据可能不完整"
fi
四、跨机房数据同步、异地容灾架构落地
4.1 CCR(Cross-Cluster Replication)跨集群复制
CCR 架构原理:
┌─────────────────┐ ┌─────────────────┐
│ 主机房集群 │ │ 备机房集群 │
│ (Leader Index) │ ──────→ │ (Follower Index) │
│ │ CCR │ │
└─────────────────┘ └─────────────────┘
写入主集群 自动同步到备集群
读请求分流 主机房故障时接管
CCR 配置实战:
# 1. 在备集群配置远程集群
curl -X PUT "localhost:9200/_cluster/settings?pretty" \
-H 'Content-Type: application/json' \
-d '{
"persistent": {
"cluster.remote.leader_cluster.seeds": ["10.0.1.1:9300", "10.0.1.2:9300"]
}
}'
# 2. 创建跟随索引(自动同步)
curl -X PUT "localhost:9200/orders_copy/_ccr/follow?pretty" \
-H 'Content-Type: application/json' \
-d '{
"remote_cluster": "leader_cluster",
"leader_index": "orders"
}'
# 3. 监控同步状态
curl -X GET "localhost:9200/_ccr/stats?pretty"
4.2 异地双活架构设计
双活写入架构(推荐):
┌─────────────┐
│ 负载均衡 │
└──────┬──────┘
┌───────────┼───────────┐
▼ ▼
┌─────────────────┐ ┌─────────────────┐
│ 机房A Elasticsearch │ │ 机房B Elasticsearch │
│ (活跃,写入) │◄───│ (活跃,写入) │
│ 同步 │───►│ 同步 │
└─────────────────┘ └─────────────────┘
▲ ▲
│ │
└────────── 双向同步 ──────────┘
关键配置:
# 机房A配置
cluster.name: es-cluster-east
node.name: node-east-1
network.host: 0.0.0.0
http.port: 9200
transport.port: 9300
discovery.seed_hosts: ["10.0.1.1:9300", "10.0.1.2:9300"]
# CCR双向复制配置
PUT /_ccr/auto_follow/orders-pattern
{
"remote_cluster": "west_cluster",
"leader_index_patterns": ["orders_*"],
"follow_index_pattern": "{{leader_index}}_west"
}
4.3 容灾切换预案
主机房故障切换流程:
# Step 1: 确认主机房故障
curl -X GET "backup-es:9200/_cluster/health?pretty"
# 确认 status 不是 green
# Step 2: 停止CCR同步(防止数据冲突)
curl -X POST "backup-es:9200/_ccr/pause_follow/orders_copy?pretty"
# Step 3: 将跟随索引转换为普通索引
curl -X POST "backup-es:9200/orders_copy/_ccr/unfollow?pretty"
# Step 4: 更新应用配置,指向备集群
# 修改应用配置文件中的 ES 地址
# Step 5: 验证备集群可正常提供服务
curl -X GET "backup-es:9200/orders_copy/_count?pretty"
回切流程(主机房恢复后):
# 1. 重新建立CCR反向同步
curl -X PUT "primary-es:9200/orders_restored/_ccr/follow?pretty" \
-d '{"remote_cluster": "backup_cluster", "leader_index": "orders_copy"}'
# 2. 数据追平后切换流量
# 3. 恢复原有CCR配置
五、生产事故复盘:数据丢失、集群瘫痪应急预案
5.1 事故案例1:误删索引导致数据丢失
事故经过:
2023年某电商公司,运维人员执行清理脚本时,误将生产索引
orders_2023删除,导致订单查询服务中断2小时。
根本原因分析:
- 未开启索引删除保护
- 缺乏操作审批流程
- 没有近期的快照备份
改进方案:
// 1. 开启索引保护(防止误删)
PUT /orders_2023/_settings
{
"index.blocks.write": false,
"index.blocks.read_only": false,
"index.blocks.read": false,
"index.blocks.metadata": true // 阻止元数据操作(包括删除)
}
// 2. 使用索引别名,不直接暴露真实索引名
PUT /orders_2023/_alias/orders_current
// 应用使用别名访问,删除索引不会影响别名配置
// 3. 自动化备份验证
PUT /_snapshot/s3_backup/daily_verify
{
"type": "s3",
"settings": {
"bucket": "es-backup",
"verify": true // 创建快照时验证可用性
}
}
5.2 事故案例2:集群脑裂导致数据不一致
事故经过:
某金融公司ES集群,由于网络抖动导致机房A和机房B的master节点失联,各自选举出master,形成脑裂。网络恢复后,两个master尝试合并,导致部分数据冲突丢失。
根本原因分析:
minimum_master_nodes配置不当- 未配置
discovery.zen.ping.unicast.hosts正确隔离 - 跨机房网络不稳定
应急预案:
# 预防配置
discovery.zen.minimum_master_nodes: 2 # 3个master节点时设为2
discovery.zen.ping.timeout: 30s # 增加ping超时时间
discovery.zen.fd.ping_interval: 10s # 故障检测间隔
discovery.zen.fd.ping_timeout: 30s # 故障检测超时
discovery.zen.fd.ping_retries: 5 # 重试次数
# 脑裂恢复操作手册
# 1. 立即停止较小partition的节点
# 2. 更新较大partition的minimum_master_nodes
# 3. 逐一启动停止的节点
# 4. 验证数据一致性
5.3 完整应急预案模板
# ElasticSearch 生产环境应急预案
## 1. 事故分级
| 级别 | 描述 | 响应时间 | 参与人员 |
|------|------|----------|----------|
| P0 | 集群完全不可用 | 15分钟 | 架构师+DBA+运维 |
| P1 | 部分功能异常 | 1小时 | DBA+运维 |
| P2 | 性能下降 | 4小时 | 运维 |
## 2. 应急联系人
- 架构师:张三 138xxxx
- ES负责人:李四 139xxxx
- 运维值班:值班电话 xxxx
## 3. 常见故障处理流程
### 3.1 集群Red状态
1. 检查 `_cat/health` 确认红色原因
2. 检查 `_cat/shard` 定位未分配分片
3. 尝试自动恢复(等待5分钟)
4. 手动分配分片(参考第二章)
5. 如无法恢复,从快照恢复
### 3.2 数据丢失
1. 立即停止相关索引写入
2. 确认丢失数据时间范围
3. 从最近快照恢复
4. 使用logstash重新导入丢失时段数据
5. 数据校验
### 3.3 集群雪崩
1. 熔断机制触发(已有)
2. 限流读请求
3. 增加节点(横向扩展)
4. 临时关闭副本分配减轻压力
## 4. 恢复验证清单
- [ ] 集群状态恢复Green
- [ ] 所有索引状态正常
- [ ] 文档数量与备份一致
- [ ] 应用端可正常查询
- [ ] 写入延迟恢复正常
- [ ] 监控告警清除
## 5. 事后复盘模板
- 事故时间线
- 影响范围(QPS、用户数)
- 根因分析
- 改进措施(技术+流程)
- 跟进事项及负责人
本章小结
本章详细介绍了 ElasticSearch 企业级高可用与容灾的完整方案:
- 分片冗余是容灾的基础,合理配置副本数能在节点故障时自动恢复
- 自动恢复机制能处理大部分故障,但需要掌握手动兜底方案应对极端情况
- 快照备份是最后一道防线,必须建立定时备份和定期恢复验证机制
- 跨机房容灾通过CCR实现数据同步,双活架构能提供更高的可用性
- 应急预案需要结合真实案例不断迭代,定期演练才能确保关键时刻不掉链子
最佳实践建议:高可用不是配置出来的,是运维出来的。建立完善的监控体系、定期备份验证、常态化故障演练,才能真正做到"故障零感知"。
下一章预告:第21章将深入探讨 ElasticSearch 性能调优与容量规划,教你如何根据实际业务场景优化集群性能。
812

被折叠的 条评论
为什么被折叠?



