Elasticsearch 8.x 部署与运维手册

5 阅读10分钟

适用版本:Elasticsearch 8.6+ 适用范围:生产、预生产、灰度集群 文档定位:基础设施团队/SRE 实施集群部署、扩缩容、版本升级、日常运维的执行手册 配套文档:《Elasticsearch 生产开发规范》、《监控告警手册》、《故障应急 Runbook》


目录

  1. 总体原则
  2. 集群拓扑
  3. 节点规格基线
  4. 操作系统调优
  5. JVM 调优
  6. elasticsearch.yml 配置基线
  7. 安全初始化
  8. 启动顺序与初始化 checklist
  9. 日常运维操作
  10. 扩容与缩容
  11. 滚动重启与版本升级
  12. 快照与备份
  13. 集群迁移
  14. 日常巡检 checklist
  15. 附录 A:常用 _cat 命令速查
  16. 附录 B:变更操作授权矩阵

1. 总体原则

1.1 三个不变量

任何运维动作都不得破坏以下三个不变量,否则操作必须中止并升级:

不变量含义触发应急
多数派可用master 候选节点 ≥ (总数/2)+1 在线否则集群无法选主
每个分片至少一个副本可用primary 或 replica 至少一份 healthy否则索引部分写入失败
磁盘水位 < 85%任一 data 节点磁盘使用率不超过 flood_stage否则索引强制只读

1.2 操作分级

级别示例授权是否需变更窗口
L0 只读_cat/*、查询、查看配置任何运维
L1 低危修改 refresh_interval、扩 replica、新建索引SRE 值班
L2 中危节点上下线、reindex、滚动重启单节点SRE 值班 + 备班复核是(建议低峰)
L3 高危版本升级、master 节点重建、全集群重启SRE Lead + 架构组是(必须)
L4 致命删索引、_cluster/voting_config_exclusions、强制分片分配CTO 授权是(必须)

详细授权矩阵见附录 B。

1.3 操作纪律

  1. 任何 L2+ 操作必须先在预生产复演,禁止在生产首次执行陌生操作
  2. 禁止从笔记本直连生产 API,所有操作通过堡垒机审计
  3. 禁止使用 elastic 超管账号执行日常运维,按角色申请独立账号
  4. 变更前必须做集群快照(L3+ 必须,L2 建议)
  5. 变更过程必须有 runbook,无 runbook 不操作

2. 集群拓扑

2.1 推荐生产拓扑

┌─────────────────────────────────────────────────────────┐
│  应用层 (Order/Search/Recommend Services)               │
└────────────────────────┬────────────────────────────────┘
                         │ HTTPS, API Key
                         ▼
            ┌──────────────────────────┐
            │  Coordinating × 2 (可选)  │ ← 大查询/聚合代理
            └──────────────┬───────────┘
                           │
       ┌───────────────────┼───────────────────┐
       ▼                   ▼                   ▼
   master×3 (专用)    data_hot×N           data_warm×N
   2C 4G              SSD, 32G heap        SATA SSD, 32G heap
                                            │
                                            ▼
                                      data_cold×N
                                      HDD/对象存储, 16G heap

2.2 节点角色规则

角色数量职责是否承担数据
master必须 3 个,奇数集群状态管理、元数据
data_hot≥ 3,按容量扩接收写入,最近数据
data_warm按容量扩7~30 天数据
data_cold可选30 天以上是(只读)
data_frozen可选90 天以上,可搜索快照是(极少访问)
coordinating可选,2~4大查询/聚合代理
ingest可选,可与 hot 合并pipeline 预处理
ml可选机器学习作业

禁止

  • master 节点兼任 data 角色(脑裂风险)
  • master 节点数为偶数(投票打平)
  • master 节点跨可用区数 < 3(单 AZ 故障即失主)

2.3 可用区分布

最少 3 个 AZ

AZ-A: master-01, hot-01, hot-04, warm-01
AZ-B: master-02, hot-02, hot-05, warm-02
AZ-C: master-03, hot-03, hot-06, warm-03

启用 shard allocation awareness:

cluster.routing.allocation.awareness.attributes: zone
node.attr.zone: az-a   # 各节点不同

效果:副本必然分布到不同 AZ,单 AZ 故障不会导致数据不可用。


3. 节点规格基线

3.1 硬件规格

角色CPU内存磁盘网络
master2 vCPU4~8 GB50 GB SSD1 Gbps
data_hot16~32 vCPU64 GB1~2 TB NVMe SSD10 Gbps
data_warm8~16 vCPU32~64 GB4~8 TB SATA SSD10 Gbps
data_cold4~8 vCPU16~32 GB8~16 TB HDD1 Gbps
coordinating8~16 vCPU32 GB50 GB SSD10 Gbps

3.2 内存与磁盘的硬约束

约束数值理由
物理内存最小值16 GB低于此值 Lucene 缓存不足,性能不可控
JVM Heap 上限31 GB超过失去指针压缩
Heap : 物理内存≤ 1:2另一半留给 Lucene FileCache
磁盘:Heap≥ 1:32(搜索)/ 1:96(日志)超出后单分片体积失控
磁盘容量单盘 ≤ 4 TB(搜索)/ ≤ 16 TB(日志冷)恢复时间约束
磁盘 IOPShot ≥ 30k,warm ≥ 5k否则 segment merge 跟不上

3.3 文件系统

推荐
文件系统XFS(首选)或 ext4
挂载选项noatime,nodiratime
数据盘独立挂载,禁止与系统盘共用
RAIDRAID 0(追求性能,靠副本保护)或 不做 RAID(推荐)
LVM仅在需要快照场景使用,性能损失约 5%

禁止

  • NFS / 网络文件系统作为 data 目录
  • 在 data 节点开启 swap

3.4 容器化部署的特别要求

容器(Docker/K8s)部署时:

# 必要的 ulimits
ulimits:
  memlock: -1
  nofile: 65535

# 禁止 OOM killer 杀掉 ES 进程
oom_kill_disable: true   # 或在 K8s 中设置 priorityClass

# K8s 专属
resources:
  requests: { memory: "64Gi", cpu: "16" }
  limits:   { memory: "64Gi", cpu: "16" }   # requests = limits,避免被驱逐

禁止

  • 同一物理机跑多个 ES 容器(争抢 page cache)
  • 使用 emptyDir 存数据
  • 没有反亲和(podAntiAffinity)的 master/data 部署

4. 操作系统调优

4.1 内核参数

/etc/sysctl.d/99-elasticsearch.conf

# 虚拟内存映射区数量 — Lucene mmap 大量文件
vm.max_map_count = 262144

# 关闭 swap,仅在极端内存压力下使用
vm.swappiness = 1

# 网络 backlog
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535

# TIME_WAIT 复用,应对高并发短连接
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 15

# 文件句柄
fs.file-max = 1048576

应用:sysctl -p /etc/sysctl.d/99-elasticsearch.conf

4.2 用户限制

/etc/security/limits.d/elasticsearch.conf

elasticsearch  soft  nofile  65535
elasticsearch  hard  nofile  65535
elasticsearch  soft  nproc   4096
elasticsearch  hard  nproc   4096
elasticsearch  soft  memlock unlimited
elasticsearch  hard  memlock unlimited

4.3 Transparent Huge Pages

必须关闭 THP,否则会引发 GC 长停顿:

echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo never > /sys/kernel/mm/transparent_hugepage/defrag

加入 /etc/rc.local 持久化。

4.4 时间同步

所有节点必须接入同一 NTP 源,时间偏差 < 100ms。否则:

  • master 选举可能异常
  • 监控时间序列错位
  • 审计日志无法关联
# 验证
chronyc tracking
chronyc sources -v

4.5 验证 OS 调优

启动 ES 前执行(脚本化,落盘 pre-start-check.sh):

检查项命令预期
max_map_countsysctl vm.max_map_count≥ 262144
swappinesssysctl vm.swappiness≤ 1
nofileulimit -n(es 用户下)65535
memlockulimit -l(es 用户下)unlimited
THPcat /sys/kernel/mm/transparent_hugepage/enabled[never]
时间同步chronyc trackingoffset < 100ms
磁盘挂载mount | grep <data_dir>noatime
磁盘空间df -h <data_dir>使用率 < 50%(首次部署)

任何一项不满足,禁止启动


5. JVM 调优

5.1 Heap 设置

config/jvm.options.d/heap.options

-Xms31g
-Xmx31g

铁律-Xms 必须等于 -Xmx,避免运行时扩容引发的 GC 抖动。

物理内存推荐 Heap
16 GB8 GB
32 GB16 GB
64 GB30 GB
128 GB31 GB(不再增加)
256 GB31 GB(剩余全给 FileCache,或拆成 2 个节点)

5.2 GC 选择

ES 8.x 默认 G1GC(JDK 17+)。不要改回 CMS。

config/jvm.options.d/gc.options

# G1 调优 — 仅在默认配置出现长停顿时调整
-XX:MaxGCPauseMillis=200
-XX:InitiatingHeapOccupancyPercent=30

# GC 日志(生产必开)
-Xlog:gc*,gc+age=trace,safepoint:file=/var/log/elasticsearch/gc.log:utctime,pid,tags:filecount=32,filesize=64m

5.3 OOM 处理

config/jvm.options.d/oom.options

-XX:+ExitOnOutOfMemoryError
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/var/log/elasticsearch/heapdump
-XX:ErrorFile=/var/log/elasticsearch/hs_err_pid%p.log

OOM 后立刻退出,让进程管理器(systemd)拉起新实例,避免 stuck-in-OOM 状态。

5.4 JVM 验证

# 进程启动后检查
jps -lvm | grep Elasticsearch
jcmd <pid> VM.flags | grep -E "MaxHeapSize|UseG1GC|HeapDump"

预期:

  • MaxHeapSize ≈ Xmx
  • +UseG1GC
  • +HeapDumpOnOutOfMemoryError

6. elasticsearch.yml 配置基线

6.1 集群标识

cluster.name: prod-search-cluster
node.name: ${HOSTNAME}            # 必须全集群唯一

6.2 角色配置(按节点类型分别填写)

# master 节点
node.roles: [ master ]

# 热数据节点
node.roles: [ data_hot, data_content, ingest ]
node.attr.box_type: hot
node.attr.zone: az-a

# 温数据节点
node.roles: [ data_warm ]
node.attr.box_type: warm
node.attr.zone: az-b

# 协调节点
node.roles: [ ]                   # 空数组 = coordinating only

6.3 网络

network.host: 0.0.0.0
http.port: 9200
transport.port: 9300

# HTTP 限制
http.max_content_length: 100mb    # bulk 单批最大
http.compression: true
http.cors.enabled: false          # 生产禁用 CORS

6.4 集群发现与选主

discovery.seed_hosts:
  - master-01.internal:9300
  - master-02.internal:9300
  - master-03.internal:9300

# 首次启动必须明确,启动后可以保留也可以注释
cluster.initial_master_nodes:
  - master-01
  - master-02
  - master-03

严重警告

  • cluster.initial_master_nodes 仅在首次集群启动时使用
  • 集群形成后,新增 master 节点不要修改这一项,否则会引发分裂集群(split-brain)
  • 单节点测试用 discovery.type: single-node生产严禁

6.5 路径

path.data: /data/es
path.logs: /var/log/elasticsearch
path.repo: /mnt/snapshot          # 共享快照目录(NFS/S3)

6.6 内存与并发

bootstrap.memory_lock: true       # 必须;配合 ulimit memlock unlimited
indices.memory.index_buffer_size: 10%

# 线程池(一般无需调整,仅在压测后明确瓶颈再改)
thread_pool.write.queue_size: 1000
thread_pool.search.queue_size: 1000

6.7 分片相关

# 单节点分片上限保护
cluster.max_shards_per_node: 1500

# 分片均衡敏感度(默认即可)
cluster.routing.allocation.balance.shard: 0.45
cluster.routing.allocation.balance.index: 0.55

# 磁盘水位
cluster.routing.allocation.disk.threshold_enabled: true
cluster.routing.allocation.disk.watermark.low: 85%
cluster.routing.allocation.disk.watermark.high: 90%
cluster.routing.allocation.disk.watermark.flood_stage: 95%

# Awareness(多 AZ)
cluster.routing.allocation.awareness.attributes: zone
cluster.routing.allocation.awareness.force.zone.values: az-a,az-b,az-c

6.8 安全

xpack.security.enabled: true
xpack.security.transport.ssl.enabled: true
xpack.security.transport.ssl.verification_mode: full
xpack.security.transport.ssl.keystore.path: certs/transport.p12
xpack.security.transport.ssl.truststore.path: certs/transport.p12

xpack.security.http.ssl.enabled: true
xpack.security.http.ssl.keystore.path: certs/http.p12

xpack.security.audit.enabled: true
xpack.security.audit.logfile.events.include:
  - access_denied
  - authentication_failed
  - connection_denied
  - tampered_request
  - run_as_denied
  - security_config_change

6.9 完整模板下发流程

  1. 模板存放在配置仓库:infra/elasticsearch/{cluster_name}/elasticsearch.yml.j2
  2. 通过 Ansible/Salt 下发,禁止手工编辑
  3. 变更走 PR + 审批
  4. 部署前 diff 比对当前节点配置与目标
  5. 灰度 1 节点 → 观察 30 分钟 → 全量

7. 安全初始化

7.1 证书生成

集群首次部署使用 elasticsearch-certutil

# 1. 生成 CA
bin/elasticsearch-certutil ca \
  --out config/certs/elastic-stack-ca.p12 \
  --pass <ca-password>

# 2. 为每个节点生成节点证书
bin/elasticsearch-certutil cert \
  --ca config/certs/elastic-stack-ca.p12 \
  --ca-pass <ca-password> \
  --name node-01 \
  --dns node-01.internal \
  --ip 10.0.0.11 \
  --out config/certs/node-01.p12 \
  --pass <node-password>

# 3. 设置文件权限
chown elasticsearch:elasticsearch config/certs/*
chmod 660 config/certs/*

证书有效期建议 2 年,到期前 60 天必须轮转。

7.2 内置账号密码

首次启动后立即重置:

bin/elasticsearch-reset-password -u elastic -i
bin/elasticsearch-reset-password -u kibana_system -i

密码存入团队密钥管理(Vault / KMS),禁止写在配置文件、Git、Wiki。

7.3 角色与账号规划

最小角色集:

角色用途权限范围
app_writer_<service>业务服务写入特定索引 write + create_index
app_reader_<service>业务服务读取特定索引 read
ops_viewerSRE 只读monitor + 全索引 view_index_metadata
ops_adminSRE 操作manage + 数据节点限定
kibana_adminKibana 管理员Kibana 所有空间
kibana_user_<team>业务用户特定 Kibana space

严禁业务应用使用 superuser / elastic

7.4 API Key 管理

服务接入推荐 API Key(可独立轮转、可吊销、不影响其他服务):

POST /_security/api_key
{
  "name": "order-service-prod",
  "expiration": "365d",
  "role_descriptors": {
    "order_writer": {
      "indices": [{ "names": ["search-order-*"], "privileges": ["read","write","create_index"] }]
    }
  },
  "metadata": { "owner_team": "order", "env": "prod" }
}

API Key 必须:

  • 设置过期时间(≤ 1 年)
  • 走 Vault/KMS 注入应用,禁止明文落盘
  • 季度审计未使用的 key 并吊销

8. 启动顺序与初始化 checklist

8.1 首次集群启动顺序

1. 全部节点完成 OS 调优 + 配置下发 + 证书分发
2. 启动 3 个 master 节点(同时启动)
3. 等待 cluster status = green(仅 master 节点)
4. 启动 data_hot 节点(可并行)
5. 启动 data_warm / data_cold 节点
6. 启动 coordinating 节点
7. 重置内置账号密码
8. 创建运维账号、应用账号、API Key
9. 注释 cluster.initial_master_nodes(可选,建议保留)
10. 配置快照仓库
11. 配置 ILM 策略与 Index Template
12. 接入监控
13. 接入 Kibana
14. 灰度业务流量

8.2 节点启动 checklist

每个节点首次启动前确认(脚本化):

  • OS 调优全部通过(见 §4.5)
  • elasticsearch 用户与组已创建
  • data 目录所有者为 elasticsearch,权限 750
  • 证书文件就位且权限 660
  • elasticsearch.yml 与目标一致(diff 干净)
  • JVM heap = 物理内存的 1/2 且 ≤ 31GB
  • systemd unit 已配置,LimitMEMLOCK=infinity
  • 监控 agent(metricbeat / node_exporter)已部署
  • 日志收集(filebeat / vector)已部署
  • 防火墙开放 9200(HTTP)/ 9300(transport)
  • DNS / hosts 解析正确
  • NTP 同步偏差 < 100ms

任何一项 NO,禁止启动

8.3 集群健康验证

启动完成后逐项验证:

# 1. 集群状态 = green
curl -k -u admin "https://master-01:9200/_cluster/health?pretty"

# 2. 所有节点已加入
curl -k -u admin "https://master-01:9200/_cat/nodes?v"

# 3. master 选举正常
curl -k -u admin "https://master-01:9200/_cat/master?v"

# 4. 节点角色与预期一致
curl -k -u admin "https://master-01:9200/_cat/nodes?v&h=name,node.role,heap.percent,ram.percent,disk.used_percent"

# 5. 测试写入
curl -k -u admin -X POST "https://master-01:9200/test-init/_doc" \
  -H 'Content-Type: application/json' -d '{"hello":"world"}'

# 6. 测试查询
curl -k -u admin "https://master-01:9200/test-init/_search"

# 7. 清理测试索引
curl -k -u admin -X DELETE "https://master-01:9200/test-init"

9. 日常运维操作

9.1 索引基础操作

操作命令备注
列出索引GET /_cat/indices?v&s=store.size:desc按大小排序
查看 mappingGET /<idx>/_mapping
查看 settingsGET /<idx>/_settings
修改动态 settingsPUT /<idx>/_settings { ... }仅部分字段动态
关闭索引POST /<idx>/_close释放内存,仍占磁盘
打开索引POST /<idx>/_open
删除索引DELETE /<idx>L4 操作,必须授权

9.2 别名操作

POST /_aliases
{
  "actions": [
    { "add":    { "index": "search-product-v3", "alias": "search-product" } },
    { "remove": { "index": "search-product-v2", "alias": "search-product" } }
  ]
}

别名切换是原子操作,是 reindex 平滑切换的关键。

9.3 强制段合并

冷数据归档前合并段以节省空间:

POST /<idx>/_forcemerge?max_num_segments=1&wait_for_completion=false

禁止

  • 在写入活跃的索引上执行 force merge(会拖垮 IO)
  • 在主索引上设 max_num_segments=1 而不切只读

9.4 集群配置变更

PUT /_cluster/settings
{
  "persistent": {                  # 重启保留
    "indices.recovery.max_bytes_per_sec": "200mb"
  },
  "transient": {                   # 重启丢失,临时变更用
    "logger.org.elasticsearch.xpack.security": "DEBUG"
  }
}

禁止

  • 使用 transient 修改长期配置(会被 persistent 覆盖且重启丢失)
  • 不记录变更原因(必须在变更工单留底)

9.5 任务管理

# 查看正在执行的任务
GET /_tasks?actions=*search*&detailed

# 查看 reindex / update_by_query 任务
GET /_tasks?actions=*reindex*&detailed

# 取消任务
POST /_tasks/<task_id>/_cancel

9.6 慢查询日志

按索引启用:

PUT /<idx>/_settings
{
  "index.search.slowlog.threshold.query.warn": "1s",
  "index.search.slowlog.threshold.query.info": "200ms",
  "index.search.slowlog.threshold.fetch.warn": "500ms",
  "index.indexing.slowlog.threshold.index.warn": "1s"
}

日志路径:logs/<cluster>_index_search_slowlog.json


10. 扩容与缩容

10.1 扩容(加节点)

前置条件

  • 新节点 OS 调优、证书、配置已就绪
  • 集群当前状态 = green
  • 预留扩容窗口(建议低峰)

步骤

  1. 启动新节点
  2. 等待节点加入:GET /_cat/nodes?v
  3. 观察分片再均衡:GET /_cat/shards?v | head
  4. 默认 ES 会自动迁移分片到新节点,控制迁移速度:
PUT /_cluster/settings
{
  "transient": {
    "cluster.routing.allocation.cluster_concurrent_rebalance": 4,
    "indices.recovery.max_bytes_per_sec": "100mb"
  }
}
  1. 等待 unassigned_shards = 0relocating_shards = 0
  2. 完成后恢复默认值

10.2 缩容(下节点)

禁止:直接 kill 节点。必须先排空。

# 步骤 1: 排空目标节点(按 IP 或节点名)
PUT /_cluster/settings
{
  "transient": {
    "cluster.routing.allocation.exclude._name": "node-05"
  }
}

# 步骤 2: 等待节点上的分片数 = 0
GET /_cat/shards?v | grep node-05
GET /_cat/allocation?v

# 步骤 3: 下线节点
systemctl stop elasticsearch

# 步骤 4: 取消排空规则
PUT /_cluster/settings
{
  "transient": {
    "cluster.routing.allocation.exclude._name": null
  }
}

10.3 master 节点变更

最高危操作,必须严格按序:

  1. 必须保持 master 候选数 ≥ 3 全程满足
  2. 一次只能变更一个 master 节点
  3. 旧 master 下线前先 voting 排除:
POST /_cluster/voting_config_exclusions?node_names=master-01&timeout=2m
  1. 等待新 master 选出
  2. 下线旧节点
  3. 新增 master 节点上线后,清除排除列表
DELETE /_cluster/voting_config_exclusions

禁止

  • 同时下线多个 master
  • 不清理 voting_config_exclusions(会导致后续 master 变更异常)

11. 滚动重启与版本升级

11.1 滚动重启 SOP

适用场景:变更 elasticsearch.yml、JVM 参数、OS 补丁。

1. 集群 status = green,无 unassigned shard
2. 通知业务方进入"低写入"状态(如 bulk 客户端降速)
3. 禁用分片自动均衡:

   PUT /_cluster/settings
   {
     "persistent": {
       "cluster.routing.allocation.enable": "primaries"
     }
   }

4. 同步刷新 translog(加速重启):

   POST /_flush

5. 停止目标节点:
   systemctl stop elasticsearch

6. 应用变更(配置 / 二进制 / 内核)

7. 启动节点:
   systemctl start elasticsearch

8. 等待节点加入并 status >= yellow

9. 启用分片均衡:
   PUT /_cluster/settings
   { "persistent": { "cluster.routing.allocation.enable": null } }

10. 等待集群恢复 green(关键 — 不可跳过)

11. 重复 5~10 处理下一个节点

严格遵守

  • 一次一个节点,禁止并行
  • 每个节点完成 green 后再进行下一个
  • 总时长无上限,宁慢勿乱

11.2 版本升级

11.2.1 升级路径

当前版本目标版本路径
8.x8.x+1滚动升级
8.x8.y(y > x+1)必须先升到 8.x+1
7.178.x必须先 7.17 → 7.17 latest → 8.x
7.0~7.168.x不支持,必须先升到 7.17

跨版本升级前,必须

11.2.2 升级前检查

# 1. 升级助手 API(8.x 仍可用)
GET /_migration/deprecations

# 2. 客户端兼容性
# 检查所有应用客户端版本是否支持目标 ES 版本

# 3. 插件兼容性
GET /_cat/plugins?v
# 确认目标版本有匹配的插件包

11.2.3 升级顺序

1. 备份(快照)
2. 升级 master 节点(按 §11.1 滚动)
3. 升级 data_warm / data_cold(按 §11.1 滚动)
4. 升级 data_hot(按 §11.1 滚动)
5. 升级 coordinating
6. 升级 Kibana
7. 升级客户端 SDK(按业务节奏)

11.2.4 回滚

ES 不支持降级。一旦升级到 8.x+1 节点写入数据,无法回到 8.x。

唯一回滚方式:从快照恢复到旧版本集群。

因此:升级前快照是强制的。


12. 快照与备份

12.1 快照仓库类型

类型适用场景
s3AWS S3 / 兼容协议(推荐云上)
gcsGoogle Cloud Storage
azureAzure Blob
fs(共享文件系统)自建机房 NFS/CephFS
hdfsHadoop 集群

禁止

  • 仓库放在 ES 节点本地磁盘(节点故障即丢备份)
  • 多个集群共用同一仓库路径(互相覆盖)

12.2 注册仓库

PUT /_snapshot/s3-repo
{
  "type": "s3",
  "settings": {
    "bucket": "es-snapshot-prod",
    "base_path": "search-cluster",
    "server_side_encryption": true,
    "max_snapshot_bytes_per_sec": "100mb",
    "max_restore_bytes_per_sec": "200mb"
  }
}

12.3 SLM 自动快照策略

PUT /_slm/policy/daily-full
{
  "schedule": "0 30 1 * * ?",        # 每天 01:30
  "name": "<full-{now/d}>",
  "repository": "s3-repo",
  "config": {
    "indices": ["*"],
    "include_global_state": true,
    "ignore_unavailable": true,
    "partial": false
  },
  "retention": {
    "expire_after": "30d",
    "min_count": 7,
    "max_count": 60
  }
}
PUT /_slm/policy/hourly-incremental
{
  "schedule": "0 5 * * * ?",         # 每小时 5 分(避开整点)
  "name": "<inc-{now/d}-{now/h{HH}}>",
  "repository": "s3-repo",
  "config": { "indices": ["search-*","logs-*"] },
  "retention": { "expire_after": "7d", "min_count": 24 }
}

12.4 快照验证

至少每月一次从快照恢复到测试集群验证:

POST /_snapshot/s3-repo/<snapshot_name>/_restore
{
  "indices": "search-product-v3",
  "rename_pattern":     "(.+)",
  "rename_replacement": "$1-restored",
  "include_global_state": false
}

没有恢复演练 = 没有备份

12.5 RTO / RPO 目标

指标目标
RPO(最大数据丢失)1 小时(增量快照间隔)
RTO(恢复时间)4 小时(单索引)/ 24 小时(全集群)
演练频率单索引恢复每月 1 次,全集群每季度 1 次

13. 集群迁移

13.1 迁移方案选型

方案适用中断复杂度
Snapshot/Restore离线/小数据量有写入截断
Reindex from Remote在线/大数据量
Cross-Cluster Replication (CCR)跨地域容灾无(异步复制)高,需 Platinum License
Logstash 双写跨大版本/异构

13.2 Reindex from Remote

# 在目标集群执行
POST /_reindex?wait_for_completion=false&slices=auto&requests_per_second=2000
{
  "source": {
    "remote": {
      "host": "https://old-cluster:9200",
      "username": "migrator",
      "password": "..."
    },
    "index": "search-product-*",
    "size": 1000
  },
  "dest": {
    "index": "search-product-v3"
  },
  "conflicts": "proceed"
}

前置

  • 目标集群 elasticsearch.yml 配置 reindex.remote.whitelist: old-cluster:9200
  • 目标集群提前创建 mapping
  • 限速控制源集群压力

13.3 切流方案

T0: 双写新旧集群(应用层)
T1: 迁移历史数据(reindex)
T2: 数据校验(count + 抽样 diff)
T3: 读流量灰度切换:1% → 10% → 50% → 100%
T4: 观察 1~3 天
T5: 停止旧集群写入
T6: 旧集群保留 1 个月
T7: 下线旧集群

回滚点:T3 任意时刻可切回旧集群。


14. 日常巡检 checklist

14.1 每日(自动化巡检脚本)

  • 集群 status = green
  • 各节点 heap usage < 75%
  • 各节点 disk usage < 70%
  • 无 unassigned shard
  • 无 pending tasks
  • 无 thread_pool rejected
  • 慢查询数量较前日无突增
  • SLM 快照成功执行
  • ILM 策略未卡住

14.2 每周

  • 单节点分片数 ≤ heap GB × 20
  • 单分片大小在合理区间(搜索 1030GB / 日志 3050GB)
  • mapping 字段总数无异常增长
  • 索引数量符合预期(无遗留测试索引)
  • 证书剩余有效期 > 90 天
  • API Key 是否有过期或长期未使用的需要清理
  • 备份大小趋势正常

14.3 每月

  • 单索引快照恢复演练
  • 慢查询 Top 20 治理
  • 容量趋势预测(30 天后是否需扩容)
  • 角色与权限审计(删除离职人员账号)

14.4 每季度

  • 全集群快照恢复演练
  • 滚动重启演练(预生产)
  • 故障演练(kill master、kill data 节点、断网)
  • 文档更新(本手册 + 关联 runbook)

附录 A:常用 _cat 命令速查

GET /_cat/health?v                                    # 集群健康
GET /_cat/nodes?v&h=name,node.role,heap.percent,ram.percent,cpu,load_1m,disk.used_percent
GET /_cat/master?v                                    # 当前 master
GET /_cat/indices?v&s=store.size:desc                 # 索引按大小排序
GET /_cat/shards?v&s=store:desc                       # 分片按大小排序
GET /_cat/shards/<idx>?v                              # 单索引分片分布
GET /_cat/allocation?v                                # 各节点分片占用
GET /_cat/recovery?v&active_only=true                 # 恢复中的分片
GET /_cat/thread_pool?v&h=node_name,name,active,queue,rejected
GET /_cat/pending_tasks?v                             # master 待处理任务(应该≈0)
GET /_cat/tasks?v&detailed                            # 正在执行的任务
GET /_cat/repositories?v                              # 快照仓库
GET /_cat/snapshots/<repo>?v                          # 快照列表
GET /_cat/segments/<idx>?v&h=index,shard,segment,size,size.memory  # 段信息
GET /_cat/aliases?v                                   # 别名
GET /_cat/templates?v                                 # 模板
GET /_cat/plugins?v                                   # 已安装插件

附录 B:变更操作授权矩阵

操作级别SRE 值班SRE Lead架构组CTO
查看任意 APIL0
修改动态 settings(非容量类)L1
创建新索引(按规范)L1
调整副本数L1
关闭/打开索引L2复核
Reindex(单索引)L2复核
滚动重启单节点L2复核
节点上下线L2复核
修改集群 persistent settingsL2复核
滚动重启全集群L3复核
版本升级L3复核
Master 节点变更L3复核
扩缩容 ≥ 30% 节点L3复核
删除生产索引L4复核
voting_config_exclusions 操作L4复核
强制分配/重路由分片L4复核
跨集群迁移L4复核

授权方式:

  • L1:值班 SRE 自主,工单留痕
  • L2:值班执行,备班复核(双人在场)
  • L3:变更评审会通过,变更窗口执行
  • L4:CTO 邮件/IM 显式授权,变更窗口执行

文档版本

版本日期变更作者
v1.02026-05-11初版-