【ElasticSearch 从入门到架构师】第20章-企业级高可用与容灾方案

本章导读:在生产环境中,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_shards1写入前需激活的分片数
index.write.wait_for_active_shards1索引级写入确认机制
cluster.routing.allocation.total_shards_per_nodeunbounded单节点最大分片数

二、集群故障自动恢复、手动兜底方案

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"]

分片自动恢复流程

  1. Master 检测到节点离线
  2. 标记该节点上的主分片为不可用
  3. 将对应副本分片提升为主分片
  4. 重新分配缺失的副本分片
  5. 集群状态恢复 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 企业级高可用与容灾的完整方案:

  1. 分片冗余是容灾的基础,合理配置副本数能在节点故障时自动恢复
  2. 自动恢复机制能处理大部分故障,但需要掌握手动兜底方案应对极端情况
  3. 快照备份是最后一道防线,必须建立定时备份和定期恢复验证机制
  4. 跨机房容灾通过CCR实现数据同步,双活架构能提供更高的可用性
  5. 应急预案需要结合真实案例不断迭代,定期演练才能确保关键时刻不掉链子

最佳实践建议:高可用不是配置出来的,是运维出来的。建立完善的监控体系、定期备份验证、常态化故障演练,才能真正做到"故障零感知"。


下一章预告:第21章将深入探讨 ElasticSearch 性能调优与容量规划,教你如何根据实际业务场景优化集群性能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值