Elasticsearch运维进阶

高可用架构

一、节点类型

1.1 主节点

协调集群内管理任务,比如索引创建、删除、集群状态更新等

1.2 数据节点

存储实际数据,并执行相关的CRUD操作和搜索请求

1.3 协调节点

接收客户端请求,将请求分发到数据节点并汇总结果,不存储数据

1.4 负载节点

在数据被索引之前,对数据进行预处理,比如解析、变换等

二、高可用

  1. ElasticSearch通过分片(Shard)机制来实现数据的水平扩展。每个索引可以被分成多个分片,每个分片是一个完整的搜索引擎,可以被分布在集群的多个节点上。为了提高数据的可用性和容错性,每个分片可以有零个或多个副本分片, 分片大于1即可满足基础高可用
  2. ElasticSearch集群的高可用性是通过多个节点和分片副本来实现的。当一个节点发生故障时,集群能够自动将请求重定向到其他节点,并且可以自动将故障节点上的分片重新分配到其他节点上。
  3. ElasticSearch使用Zen Discovery模块来进行节点发现和主节点选举。当集群启动或者主节点故障时,会进行一个新的主节点选举过程。这个过程确保了集群始终有一个主节点来管理集群状态。

三、故障转移

当数据节点发生故障时,副本分片会接管请求,并且集群会自动将新的分片分配到其他健康的节点上。这个过程是自动的,无需人工干预。

四、数据一致性

在分布式系统中,数据一致性是一个挑战。ElasticSearch通过以下机制来确保数据的一致性:

4.1 乐观并发控制

ElasticSearch使用乐观并发控制(Optimistic Concurrency Control, OCC)来处理文档版本的冲突。每个文档都有一个版本号,当文档被更新时,版本号会增加。如果两个并发的更新尝试发生冲突,ElasticSearch会拒绝旧版本的更新。

4.2 刷新与提交

ElasticSearch的索引数据不是立即写入磁盘的,而是先存储在内存中,通过定期的刷新(Refresh)操作写入磁盘。这确保了数据的快速响应,但也意味着在刷新间隔内的数据可能会在故障时丢失。为了减少这种风险,可以调整刷新间隔或使用副本分片来提供数据冗余。

五、分片

一个index创建出来, 根据不同es版本有默认(主)分片数量, 7.0之前默认为5 , 7.x及之后默认为1
而且还会默认创建副本分片数量为1

比如一个index在7.6版本创建, 那么它默认一共会产生1个主分配 + 1个副本分片

常见运维场景问题

一、分片与集群设计

如何计算主分片数?副本数设置依据是什么?

  1. 主分片数

    • 计算公式:max( min(节点数 × 1.5, 数据总量/50GB ), 3 )
    • 示例:3节点+300GB数据 → min(4.5, 6) ≈ 5分片
    • 硬规则:创建后不可修改,需预留20%增长空间
  2. 副本数

    • 基础容灾:≥1(允许宕机1节点)
    • 读性能提升:每增加1副本,读吞吐提升30-50%
    • 特殊场景:
      • 单节点集群:必须设为0(副本无法分配)
      • 跨AZ部署:副本数≥AZ数量-1

二、写入性能优化

如何提升Elasticsearch的写入吞吐量?

2.1 Bulk 调优

  • 单批次大小:10-15MB(过大引发GC,过小降低吞吐)
  • 并发线程数:CPU核数×2(观察 bulk_rejected 调整)

2.2 Refresh 策略

PUT /logs/_settings
{"refresh_interval": "30s"}  // 写入期关闭刷新,完成后恢复1s

2.3 Translog 优化

    "index.translog.durability": "async"  // 异步写入,风险:宕机丢失5s数据
    "index.translog.sync_interval": "5s"

2.4 硬件级加速

  • 使用 SSD + 分离 data 和 logs 磁盘路径
  • 关闭交换分区:sudo swapoff -a

三、常见排障

3.1 yellow

# 1. 检查未分配分片原因:
GET _cluster/allocation/explain?pretty

# 2. 查看磁盘水位(>85%将停止分配):
GET _cat/allocation?v&h=node,disk.percent,shards

# 3. 检查节点负载:
GET _nodes/stats/os,process?filter_path=**.load_5m,**.cpu.percent

# 4. 分析分片锁冲突:
GET _cluster/state?filter_path=metadata.indices.*.state,*.blocks

常见根因:

  • 磁盘不足 → 清理或扩容
  • 节点配置不一致 → cluster.routing.allocation.enable: all
  • 分片损坏 → 使用 reroute 强制分配

3.2 JVM调优

Old GC持续超过5秒,如何优化?

  • 堆内存设置

    • 不超过物理内存50%
    • 不超过32GB(压缩指针失效阈值)
    • 示例:64GB内存 → -Xms31g -Xmx31g
  • GC策略

-XX:+UseG1GC
-XX:G1ReservePercent=25    # 预留内存防Evacuation Failure
-XX:InitiatingHeapOccupancyPercent=35  # 提前触发GC
  • 堆外内存泄漏排查
# 关注 count 和 used_in_bytes 持续增长
GET _nodes/stats/jvm?filter_path=**.buffer_pools.direct.*

3.3 如何防止未授权访问?

  • 网络层 通过配置文件network.host绑定内网ip
  • 传输加密 通过开启xpack + 自签证书 bin目录下的keysotre二进制创建带密码的公私钥
  • 认证 开启basic认证, es的bin目录下有个elasticsearch-reset-password二进制

四、高可用设计

单机房高可用模式

3master 3client + 多data
日志分等级, 通过template设置主/副分片数量, 通过ilm控制生命周期,
日志通过logstash配置Datastream类型写入提前配置好template的数据流

data通过node.role分冷热节点
用到的节点角色:
master
ingest 数据预处理节点
data_hot
data_warm
data_cold

client设置为空即可作为业务入口

五、版本升级(生产环境)

5.1 如何零停机升级ES 7.x到8.x

  1. 前置检查

    • 使用 ES 8 Upgrade Assistant 插件扫描
    • 解决:type冲突、废弃API、证书兼容
  2. 滚动升级步骤

# 1. 停用分片分配(防恢复风暴)
PUT _cluster/settings
{"persistent": {"cluster.routing.allocation.enable": "none"}}

# 2. 逐节点升级:停机 → 装新版本 → 启动 → 重新加入集群

# 3. 开启分片分配并等待绿色

六、描述您解决过的重大ES故障

集群Red
收到集群Red告警,Kibana大量报错,部分日志索引不可用

6.1 初步诊断

# 确认集群状态
GET _cluster/health?pretty → status:red # 40个分片未分配

# 定位异常节点
GET _cat/nodes?v → node-5磁盘使用率98.7%(超过85%默认水位线)

6.2 止血操作

  • 扩容磁盘:临时挂载云盘并迁移部分分片
  • 通过reroute强制分片分配
  • 降级写入:临时关闭非关键日志写入

6.3 根因分析

直接原因:某业务团队误触发全量历史数据重导
深层问题:
* 未设置索引分片上限 → 单节点分片数达120(超最佳实践2倍)
* 缺乏自动处理机制 → 水位超85%未自动清理旧索引

6.4 长期改进

// 通过low和high的合理区间, 加长yellow时间段, 留出足够的时间操作
PUT _cluster/settings
{
  "persistent": {
    "cluster.routing.allocation.disk.watermark.low": "80%",
    "cluster.routing.allocation.disk.watermark.high": "90%",
    "cluster.max_shards_per_node": 500  // 限制全局分片总数
  }
}

配置示例

ELK日志节点

cluster.name: ohmy-log
network.host: 0.0.0.0
http.port: 9200

node.name: es-hotdata-132
node.roles: [ data, ingest ]
node.attr.box_type: hot

path.data: /app/data/elasticsearch
path.logs: /var/log/elasticsearch

bootstrap.memory_lock: true

# 所有master ip
discovery.seed_hosts: ["192.168.11.100","192.168.11.101","192.168.11.102"]

xpack.monitoring.templates.enabled: true
xpack.security.enabled: true
xpack.license.self_generated.type: basic
xpack.security.transport.ssl.enabled: true

xpack.security.http.ssl:
  enabled: false

# 需要预先生成证书
xpack.security.transport.ssl:
  enabled: true
  verification_mode: certificate
  keystore.path: elastic-certificates.p12
  truststore.path: elastic-certificates.p12

业务节点

cluster.name: ohmy-es8
node.name: "bookinfo-1"
node.attr.box_type: bookinfo
node.attr.node_type: VM
node.attr.zone: ohmy-home
path.data: "/app/data/elasticsearch"
path.logs: "/var/log/elasticsearch"
network.host: 0.0.0.0
discovery.seed_hosts: ["192.168.33.1","192.168.33.2","192.168.33.3"]

转载请注明来源, 欢迎对文章中的引用来源进行考证, 欢迎指出任何有错误或不够清晰的表达, 可以邮件至 chinaops666@gmail.com
相册