一、当Elasticsearch集群开始"长胖"时

想象你的Elasticsearch集群就像个正在发育的青少年,突然某天业务量暴增,原本的3个节点撑不住了。你赶紧加了2台新服务器,但很快发现:新节点像个局外人一样站着发呆,数据全挤在老节点上,搜索性能反而更差了。

这就是典型的数据均衡问题——新增节点后,Elasticsearch不会自动把存量数据重新分配。就像搬家时把所有家具堆在新客厅门口,反而让整个房子更乱了。

// 技术栈:Elasticsearch 7.x
// 查看当前分片分布情况(会显示所有分片集中在老节点)
GET _cat/shards?v&h=index,shard,prirep,node&s=node
/* 输出示例:
index      shard prirep node  
logs-2023  0     p      node-old-1
logs-2023  1     p      node-old-2 
logs-2023  2     p      node-old-1
...(新节点node-new-1/node-new-2完全没出现)
*/

二、让数据流动起来的三种药方

方案1:开启自动平衡(适合小规模集群)

就像给房间装个自动扫地机器人,Elasticsearch自带平衡机制,但默认配置比较保守:

// 动态启用所有平衡策略(生产环境建议逐个开启)
PUT _cluster/settings
{
  "persistent": {
    "cluster.routing.rebalance.enable": "all",
    "cluster.routing.allocation.balance.shard": "0.7",  // 分片平衡因子(默认0.45)
    "cluster.routing.allocation.balance.index": "0.6"   // 索引平衡因子(默认0.55)
  }
}
/* 注意:
   1. 值越接近1表示越激进
   2. 白天业务高峰时慎用,可能引发性能波动
*/

方案2:手动迁移分片(精准控制但费劲)

好比亲自搬家具,可以精确控制每个分片的位置:

// 将特定索引的分片迁移到新节点
POST _cluster/reroute
{
  "commands": [
    {
      "move": {
        "index": "order_logs",
        "shard": 0,
        "from_node": "node-old-1",
        "to_node": "node-new-1"
      }
    }
  ]
}
// 配合过滤API先找出热点分片
GET _cat/shards?v&h=index,node,store&s=store:desc

方案3:滚动重启老节点(核武器方案)

这是最彻底的方法——通过临时"踢掉"老节点迫使数据迁移:

# 技术栈:Elasticsearch + Shell
# 1. 先禁用分配(防止自动恢复)
PUT _cluster/settings
{
  "persistent": {
    "cluster.routing.allocation.enable": "none"
  }
}

# 2. 逐台重启老节点(建议间隔10分钟)
ssh node-old-1 "systemctl restart elasticsearch"

# 3. 重新启用分配
PUT _cluster/settings
{
  "persistent": {
    "cluster.routing.allocation.enable": "all"
  }
}

三、那些年我们踩过的坑

去年给某电商平台扩容时就翻车了。当时直接调整了cluster.routing.allocation.node_concurrent_recoveries(默认2),想加快平衡速度:

PUT _cluster/settings
{
  "persistent": {
    "node_concurrent_recoveries": 8  // 暴力提高到8
  }
}

结果导致:

  1. 网络带宽打满,正常查询超时
  2. 大量文件描述符耗尽
  3. 最终触发了保护机制自动停止迁移

血泪建议

  • 每次调整参数后用GET _nodes/stats/thread_pool监控bulk/search线程池队列
  • 遵循"小步快跑"原则,每次参数调整幅度不超过50%
  • 优先迁移冷数据索引(通过_ilm/policy打标签)

四、预防胜于治疗的日常保健

其实最好的扩容是"无感扩容"。我们给某物流系统设计的方案就很有意思:

// 技术栈:Elasticsearch 8.x
// 在索引模板预配置自动均衡策略
PUT _index_template/logs_template
{
  "index_patterns": ["*_logs"],
  "template": {
    "settings": {
      "number_of_shards": 10,
      "number_of_replicas": 1,
      "routing.allocation.total_shards_per_node": 3  // 每个节点最多放3个主分片
    }
  }
}
/* 效果:
   1. 新索引自动均匀分布
   2. 配合ILM自动滚动创建新索引
   3. 历史数据通过CCR跨集群复制逐步迁移
*/

长期建议

  1. 使用_cat/allocation?v每周检查磁盘使用差异
  2. 为热节点配置更高规格的硬件(比如NVMe SSD)
  3. 重要索引单独配置routing.allocation.require属性

五、总结:扩容不是终点而是起点

经过多次实战我们发现,Elasticsearch的数据均衡本质是空间换时间的艺术。就像整理衣柜,与其等塞爆时手忙脚乱,不如:

  • 提前规划好分片数量(建议单个分片30-50GB)
  • index.routing_partition_size控制写入热点
  • 善用_cluster/allocation/explain诊断分配失败原因

记住,一个健康的集群应该像交响乐团——每个节点都有活干,但谁都不该过度劳累。下次扩容时,不妨先喝杯咖啡,把本文的步骤再过一遍。