搜索引擎 升级 Elasticsearch 集群数量实战记录

pathbox · 2017年07月31日 · 7253 次阅读

现在线上有一个 elasticsearch 集群搜索服务有三台 elasticsearch 实例(es1、es2、es3),打算将其升级为 5 台(增加 es4、es5)。这篇文章主要是对整个操作的过程记录,以及出现的问题总结,包括移动数据量所需要的时间。因为,一开始由于不知道线上数据量全部分配完需要多少时间,如果从凌晨开始操作,到早上 8 点都还没有同步完,这样会影响到白天线上业务的正常使用。

准备阶段

线上 es 集群使用的是阿里云服务器,copy 其中一个镜像。然后更改其 elasticsearch.yml 配置文件,检查 IK 插件是否安装成功。按照这个流程,准备两台新的服务器放入阿里云的隔离组,并安装好 elasticsearch,测试 elasticsearch 实例可以正确启动。也做了将这两台服务器构建一个集群的测试。开始升级操作前 30 分钟,再次检查 elasticsearch.yml 配置。主要的修改是:

discovery.zen.minimum_master_nodes:3
discovery.zen.ping.unicast.hosts: ["es1_ip", "es2_ip","es3_ip","es4_ip","es5_ip"]

升级操作

关闭 es 集群 shard 分配功能。对 es1 执行:

curl -XPUT es1_ip:9200/_cluster/settings -d '{
  "transient": {
   "cluster.routing.allocation.enable": "none"
   }
}'

然后检查:

curl es1_ip:9200/_cluster/settings
curl es2_ip:9200/_cluster/settings
curl es3_ip:9200/_cluster/settings

得到的结果是:

{"transient":{"cluster":{"routing":{"allocation":{"enable":"none"}}}}}

说明 es 集群已经关闭 shard 分配功能

关闭 es1、es2、es3 上的 monit

sudo service monit stop

手动控制 elasticsearch 进程的启动,避免 monit 自动拉起 elasticsearch 进程导致意外问题

这时,新的两台服务器 es4、es5 还在隔离组。把隔离取消,然后启动这两台服务器的 elasticsearch 实例

使用目录下面写好的启动脚本,这个脚本可以在启动时,为 elasticsearch 获取所设定的内存 (控制分配给 es 进程的最大内存、最小内存),JVM 的设置等

./elasticsearch.sh start

执行

curl es1_ip:9200/_cat/nodes
curl es1_ip:9200/_cat/shards
curl es1_ip:9200/_cat/health
curl es1_ip:9200/_cat/indices

验证 nodes 节点信息是否变为五个,以及 shard 现在的分布情况,应该只分布在 es1、es2、es3 上。es4 和 es5 还没有 shard

然后记录下当前的 indices 信息

例子:

health status index    pri rep docs.count docs.deleted store.size pri.store.size
green  open   users     5   1   15036978      4262221     13.2gb          6.6gb
green  open   posts     5   1   15036978      4262221     13.2gb          6.6gb

我们可以看到索引的健康度、状态、文档数量、数据大小和主分片数量、副分片的倍数设置。记录下这些信息,在最后升级完的时候 进行比对,看是否有偏差。如果一切正常,这些信息是不会变的。

启动 es 集群 shard 分配功能

这是集群操作,所以只要对其中一台 es 实例操作即可

curl -XPUT es1_ip:9200/_cluster/settings -d '{
  "transient": {
   "cluster.routing.allocation.enable": "all"
   }
}'

shard 分配开始

执行:

curl es1_ip:9200/_cat/shards

curl es1_ip:9200/_cat/health

curl es1_ip:9200/_cat/indices

curl es1_ip:9200/_cat/recovery
  • 观察 shards 分布情况,是否向 es4 和 es5 分配 shards。以及分配的百分比进度
  • 监控 es4 和 es5 服务器的 elasticsearch 的 log
  • 登入 es4 和 es5, 查看挂载的 SSD 数据盘数据量是否在增长
  • 测试进行 es 搜索的测试,快速搜索,工单筛选,客户筛选,观察对线上业务的影响

这段时间,主要使用:

curl es1_ip:9200/_cat/shards

curl es1_ip:9200/_cat/health

curl es1_ip:9200/_cat/recovery

观测 shard 分配进度和情况,以及线上系统健康度。

curl es1_ip:9200/_cat/shards 可以看见具体哪个索引的,哪个 es 服务器在移动 shard 到另一台 es 服务器

正在shard移动时的状态
posts r RELOCATING  3628884   5.4gb es_ip1   elasticsearch1 -> es_ip5 elasticsearch5

可以看到哪个索引,哪个 shard 分片,从哪台服务器上移到另一台服务器上

这个过程发现,elasticsearch 会选择将 reproduction shard(副本分片) 移到新的 elasticsearch 服务器上,而避免移到主分片。

这样可以避免移到主分片时候发生数据丢失的情况,而移动副本分配不用担心这个问题,并且线上的 health 一直是 green。尽可能不影响线上正常搜索业务。

移动 shard 默认是两个并发操作。一开始误解了,以为每个 es 实例会进行两个并发的 shard 移动,会有 6 个 shard 在并发移动,实际情况是,整个集群只有 2 个 shard 在并发移动。下次可以将这个值调大一些,加快 shard 的移动速度,幸好 shard 数据移动的速度比想象的要快。

通过 htop 观察服务器的负载,在进行 shard 分配的服务器,CPU 使用率一般在 20%-40% 之间。服务器是 16 核,也就是一个 elasticsearch 进程 shard 的移动,一个核心都没有跑满,服务器负载在 0.2。可见 elasticsearch 的分片移动还是很保守的,对服务器几乎没有很大的压力。并且观察发现,elasticsearch 不会一次把某个索引该分配的 shard 都分配完再选择下一个索引,而是轮询的分配索引的 shard。A 索引分配了一个 shard,就分配 B 索引的 shard,一圈之后,又回到 A 索引继续分配 shard。直到最后所有索引 shard 数量在集群中平衡。

收尾操作

大约一个小时时间,shard 分配结束。一共将 88G 左右的数据分配到了两台新的服务器上。这是在默认 shard 并发分配数 2 的情况下的时间记录。大家以后可以根据这个记录,预估自己的 elasticsearch shard 分配会需要多少时间。

动态修改 master 选举数量。根据 elasticsearch 文档推荐的公式: (N(master)+1)/2

curl -XPUT es1_ip:9200/_cluster/settings -d '{
      "persistent" : {
          "discovery.zen.minimum_master_nodes" : 3
      }
    }'

检查配置:

{"persistent":{"discovery":{"zen":{"minimum_master_nodes":"3"}}},"transient":{"cluster":{"routing":{"allocation":{"enable":"all"}}}}}

再检测 API 命令

curl es1_ip:9200/_cat/health

curl es1_ip:9200/_cat/indices

curl es1_ip:9200/_cat/shards

这时候,观察到 shard 分配的结果是,每个索引有 10 个 shard,每个 es 服务器拥有一个索引的两个 shard。新加入的 es4、es5 上都是副本 shard,原有集群中的 es1、es2、es3 拥有主 shard 和副本 shard。

例子:

index              shard   prirep   state     docs     store  ip    node
posts               2       r       STARTED   993718   3.5gb es1_ip es1
posts               2       p       STARTED   993718   3.5gb es1_ip es1
posts               0       p       STARTED   993428   3.7gb es2_ip es2
posts               0       p       STARTED   993428   3.7gb es2_ip es2
posts               3       p       STARTED   993653   3.6gb es3_ip es3
posts               3       p       STARTED   993653   3.6gb es3_ip es3
posts               1       r       STARTED   994063   3.5gb es4_ip es4
posts               1       r       STARTED   994063   3.5gb es4_ip es4
posts               4       r       STARTED   993938   3.5gb es5_ip es5
posts               4       r       STARTED   993938   3.5gb es5_ip es5

posts 索引的十个 shard 分片在每台 elasticsearch 服务器上有两个分片。perfect!(实际结果是乱序的)

后悔的操作选择

我们修改了 es1 的配置文件,想要重启 es1 elasticsearch 实例。重启后,发生了意想不到的事情,索引的 shard 又开始分配移动,等了快 40 分钟分配移动结束,但是,这时候不是每个 es 服务器平均拥有一个索引的两个 shard,而是有的 es 服务器有该索引的三个 shard。

posts               2 r STARTED   993718   3.5gb es4_ip es4
posts               2 p STARTED   993718   3.5gb es2_ip es2
posts               0 p STARTED   993428   3.7gb es4_ip es4
posts               0 r STARTED   993428   3.7gb es1_ip es1
posts               3 r STARTED   993653   3.6gb es1_ip es1
posts               3 p STARTED   993653   3.6gb es2_ip es2
posts               1 r STARTED   994063   3.5gb es5_ip es5
posts               1 p STARTED   994063   3.5gb es1_ip es1
posts               4 r STARTED   993938   3.5gb es5_ip es5
posts               4 p STARTED   993938   3.5gb es3_ip es3

posts 在 elasticsearch1 上出现了三个 shard

实际上,原本集群中的三台服务器是不用重启的,你可以修改他们 elasticsearch.yml 配置中的单拨数组设置:discovery.zen.ping.unicast.hosts。加上新加的两台服务器的 ip,和 discovery.zen.minimum_master_nodes:3。下次重启的时候,就会读取这个新的配置,而不需要马上重新。因为,k 可以通过调用 API 的方式,动态配置 discovery.zen.minimum_master_nodes,而 discovery.zen.ping.unicast.hosts 的配置,在新的 elasticsearch 服务器上配置五台服务器的 ip 地址就可以了。

打开所有 es 服务器的 monit,测试线上 elasticsearch 搜索功能

修改项目代码,加上新加的两台 elasticsearch 服务器 IP

暂无回复。
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册