有奖捉虫:行业应用 & 管理与支持文档专题 HOT
文档中心 > Elasticsearch Service > 最佳实践 > 自建集群融合迁移 > 自建 ES 集群在线融合迁移原理解析及操作指南
随着腾讯云 ES 集群稳定性越来越高、产品体验越来越好。有越来越多的外部客户希望将自建的 ES 集群迁移到腾讯云上来。本文将介绍一种腾讯云 ES 在业界独有的业务不停服无感知的迁移方案:在线融合迁移方案。本方案目前已经迁移了上百套客户自建 ES 集群上云。下面将结合我们在给客户迁移过程中总结出的宝贵经验,来详细介绍在线融合迁移技术方案的基本原理、核心优势、迁移步骤和注意事项。

为什么需要在线融合迁移

要回答这个问题,我们首先来看下当前业界常用的迁移方案,分别是 Logstash、Reindex、快照备份与恢复和跨集群复制 CCR,如下图所示。

从图中我们可以看出以上四种迁移方案都有一个共同的特点,那就是都需要业务停服,即都属于离线迁移。离线迁移最大的痛点就是迁移期间业务需要停止写入,且迁移流程非常繁琐,工作量巨大。对于一些核心的业务集群,客户几乎不可能接受任何时刻的停服操作。因此对于负责迁移的同学来说就急需一种平滑的、业务无感知的、高可用的迁移技术方案。这便是腾讯云 ES 在线融合迁移技术方案要解决的问题。

在线融合迁移方案原理

在线融合迁移方案,最体现优势的两个字就是在线,相比于离线迁移,能够真正实现业务不停服、无感知;而最体现原理的两个字就是融合,通过将自建集群和云上集群这两个本身独立的集群融合为一个大集群,并结合ES集群自带的 分片分配、迁移特性 来完成数据的迁移工作。融合迁移示意图如下图所示。

从上图的迁移流程示意图中可以看出,整个迁移主要分为三步,即融合、迁移和下线。
融合:首先我们需要在腾讯云ES控制台上申请一套和自建ES集群同等规模的空集群,即上图2中的目标集群,然后将云上的集群全量重启后加入到自建的ES集群中,使得两个集群融合成一个大集群。
迁移:融合完成后,通过对ES集群cluster/settings设置exclude属性来进行分片的迁移,当执行了如下API后,ES集群就会自动将自建集群节点上的分片逐步驱逐到云上的节点上来。从而完成分片的搬迁和集群数据的迁移工作。
PUT _cluster/settings
{
"persistent": {
"cluster.routing.allocation.exclude_name": "{source_node_names}"
}
}
下线:当自建集群节点上的分片都已经全部迁移完成后,再将自建集群节点全部停机下线,这样便完成了整个集群的迁移上云过程。我们可以通过如下API来查看自建节点上的分片数是否为0。
GET /_cat/allocation?v=true


在线融合迁移方案优势

平滑迁移,业务无感知,不停服

相比于 Logstash、快照备份和跨集群复制等离线迁移方案,在线融合迁移真正做到了在线平滑迁移和业务不停服。

集群无需重启,无需做数据一致性校验

在线融合迁移由于是通过全量重启云上ES集群来加入自建集群,因此不会对客户自建集群做任何有侵入性的操作,不同于快照迁移,需要提前安装 COS 插件并重启集群;也不需要像 Logstash 迁移,在迁移前后需要对索引 doc 数量做一致性校验。

对版本要求较低,只需云上集群版本不低于自建集群即可

在线融合迁移对集群版本的要求是只需要云上集群版本不低于自建集群版本即可。而云上目前提供了从5.6.4、6.4.3、6.8.2、7.101和7.14.2多个版本,相信总有一版本能够满足客户需求。

极大节约人力成本和运维成本

之所以说能够极大节约人力成本和运维成本,主要原因是离线迁移方案涉及到的方方面面实在太多,例如需要提前跟业务同学沟通可接受停服时间和停服时长,大部分业务低峰期都是在凌晨,因此离线迁移对迁移时间要求比较苛刻;同时离线迁移还需要做数据一致性校验,这些都是非常耗时耗力的工作。而在线融合迁移方案由于能够做到平滑透明、业务不停服,因此整个迁移过程都不需要任何业务方同学参与,也对迁移时间没有严格要求,更不需要做数据一致性校验。这些都能够极大节约人力和运维成本。

在线融合迁移的限制

虽然在线融合迁移能够彻底解决业务停服的痛点,也能够极大提升迁移效率。但是也并不是所有的自建集群都符合融合迁移的条件的,经过我们大量的测试和实际迁移经验,总结了如下几点限制和需要满足的条件。

自建 ES 集群版本不能大于云上集群版本

如云上 ES 当前提供的最高版本号是7.14.2,因此如果自建集群版本号大于7.14.2,则无法通过在线融合方案迁移;主要原因是云上低版本的集群节点无法加入高版本的自建集群中。另外对于版本号,最好是两个集群大版本号一致,例如自建版本是6.4.6,则云上优先选择6.8.2,自建版本是7.5.2,云上优先选择7.10.1。

自建 ES 集群上不能安装有云上集群不存在的插件

在迁移之前需要先在自建集群节点上执行如下 API 来查看自建集群上都安装了哪些插件。
curl http://127.0.0.1:9200/_cat/plugins
如果有发现安装了云上不存在的插件则会使得云上 ES 集群节点融合后,分片分配失败导致集群状态异常问题。下图4是云上 ES 集群支持安装的插件列表。



需确保自建 ES 集群和云上集群网络互联互通

这里说的网络互联互通是要求云上的节点可以直接访问到自建集群的节点,同样自建集群节点也可以直接访问到云上集群节点,中间不可以有任何代理 Proxy。中间有 Proxy 的访问都属于单向网络通信,而不是双向网络通信。下面介绍自建集群两种常见的网络环境和网络通信方案:
1. 腾讯云 CVM 自建 ES 集群迁移到腾讯云 ES: 由于腾讯云 ES 集群采用了跨租户弹性网卡直接打通了 ES 集群 VPC 和客户 VPC 网络环境,因此对于腾讯云 CVM 自建的 ES 集群,只需要使用自建集群所在的 VPC在云 ES 控制台购买集群即可实现网络双向互通。如果自建集群和腾讯云 ES 集群不在同一个地域,则可以采用云上云联网或者对等连接方案进行打通网络。
2. IDC 自建 ES 集群迁移到腾讯云 ES: 如果客户的自建 ES 集群是在自己的 IDC 机房或者是其他云厂商云服务器中,则可以通过专线方式打通两边的网络。两个集群网络打通后可以通过在云上集群节点上至下 telnet 自建 ip 9300方式进行验证。

需确保自建 ES 集群没有开启 security

通常情况下,客户的自建集群都是开源版本的,如果是基础版且开启了 security 的话,则需要先将 security 关闭后才能发起融合。并且白金版集群也不支持融合。如果期望上云后集群使用白金版,则可以在迁移结束后再升级到白金版即可。

云上集群名称需和自建集群名称一致

默认情况下,腾讯云 ES 集群会随机生成一个固定格式固定长度的字符串作为集群的名称,即 elasticsearch.yml 配置文件中的 cluster.name,如 cluster.name: "es-cohesszwr"(此集群 ID 配置名为虚构)。 而如果需要和自建集群进行融合,则必须要保证两个集群的 cluster.name 相同才可以。由于是让云上集群去加入自建集群,因此需要保证云上集群的集群名称与自建集群相同。自定义云上集群配置名需要开通白名单支持,开白后会看到如下图所示的填写项。如果集群创建出来后没有设置自定义的集群名称,可以找腾讯云 ES 迁移同学后台处理。



在线融合迁移基本步骤

在线融合迁移的过程需要客户的运维同学和腾讯云ES团队的迁移同学密切配合才能完成,由于 ES 在7.0版本优化了 Master 选主逻辑,因此7.0以下的版本和7.0以上的版本需要分别采用不同融合策略。下面介绍下不同版本迁移的基本步骤和差异。

7.0以下版本迁移

7.0以下版本的迁移是指客户自建 ES 集群版本和腾讯云 ES 集群版本都是7.0以下的版本,如客户版本是6.4.5,云上版本为6.8.2。
1. 分片锁定(客户侧操作) 迁移之前,需先在自建集群上执行如下 API,将分片优先锁定在自建集群节点上,这么做的原因是防止两个集群融合后分片自动漂移到云上节点,造成未知风险。
curl -H "Content-Type: application/json" -XPUT _cluster/settings -d '{
"cluster.routing.allocation.include._name" : "自建集群节点名称列表"
}'
2. 集群融合(腾讯云侧操作) 在这一步腾讯云 ES 迁移人员会调用后台接口,将自建 ES 集群节点追加到云上节点中,然后全量重启云上集群。这样在云上集群节点起来后会自动加入到自建集群中。这样就顺利融合成了一个大集群。
curl localhost:5100/cluster/update -d '{
"cluster_name": "es-cohesszwr",
"operator": "wr",
"es_config": {
"discovery.zen.ping.unicast.hosts": "
[\\"10.0.0.xx:9300\\",\\"10.0.0.xx:9300\\",\\"10.0.0.xx:9300\\",
\\"10.0.0.xx:9300\\", \\"10.0.0.xx:9300\\",, \\"10.0.0.xx:9300\\"]"
},
"restart_type": "full_cluster_restart"
}'
3. 数据迁移(腾讯云侧操作) 集群融合成功后,如果未发现什么异常问题,即可发起正式迁移了,通过执行如下 API。
curl -H "Content-Type: application/json" -XPUT _cluster/settings -d '{
"cluster.routing.allocation.include._name" : "云上集群节点名称列表",
"cluster.routing.allocation.exclude._name" : "自建集群节点名称列表"
}'
该 API 的作用就是将自建集群节点上的分片驱逐到云上节点。在融合的中间状态由于分片迁移会消耗一定的性能。因此为了稳定性考虑,可以通过如下 API 将迁移的并发度和迁移速度调小一点。
PUT _cluster/settings
{ "persistent": {
"cluster.routing.allocation.node_concurrent_recoveries": 2,
"indices.recovery.max_bytes_per_sec": "40mb/s" }
}
在迁移的中间状态,业务侧这时候可以将客户端连接ES集群的配置改成腾讯云 ES 的访问 VIP。
4. 集群分离(客户侧操作) 检查数据都迁移到云上节点后,客户需要将自建集群节点进行停机下线,将两个融合的集群进行分离。下线自建节点前需要修改自建集群配置名称 cluster.name 为其他值,如在原集群配置名称后加上-local,以及检查是否有自动拉起 ES 进程的脚本,如果有也一并删除。另外下线自建节点时,需要逐台下线,且把当选 master 节点安排在最后一个下线。这么做的好处是可以最大程度减少 Master 选主的次数。
5. 配置恢复(腾讯云侧操作) 腾讯云 ES 迁移同学确认自建集群和云上集群完全分离后,再次和客户侧业务进行确认是否有异常,如果没有异常,则通过调用如下 API 将云上配置进行恢复到融合前。
curl localhost:5100/cluster/update -d '{
"cluster_name": "es-cohesszwr",
"operator": "wr",
"es_config": { "discovery.zen.ping.unicast.hosts": "null"},
"restart_type": "no_restart"
}'
注意
这里的 discovery.seed_hosts 设置为 null,是因为后台接口会自动下发初始节点 IP 到配置中,另外 restart_type 务必设置为 no_restart,不重启方式更新。否则会影响业务稳定性。

7.0以上版本迁移

7.0以上版本的迁移是指客户自建 ES 集群版本和腾讯云 ES 集群版本都是7.0以上的版本或者云上集群是7.0以上版本,如客户版本是6.8.3,云上版本为7.5.1或者自建版本为7.5.2,云上版本为7.10.1。
1. 分片锁定(客户侧操作) 这一步和7.0以下版本操作是一样的,具体操作详情可参考上面步骤。
2. 集群融合(腾讯云侧操作) 这一步和7.0以下版本最大的区别就是将自建集群节点列表追加到云上并全量重启云上集群后,云上集群并不能直接加入自建集群,这主要是和7.0以上版本选主算法有关。因此为了让云上集群全量重启后能够正常融合,需要在全量重启后逐步对云上集群节点执行如下命令用于抹除云上集群的元数据。详细原理可参考 官方文档 提供的 elasticsearch-node 命令。 首先先执行追加自建节点 IP 配置 API:
curl localhost:5100/cluster/update -d '{
"cluster_name": "es-cohesszwr",
"operator": "wr",
"es_config": {
"discovery.seed_hosts": "
[\\"10.0.0.xx:9300\\",\\"10.0.0.xx:9300\\",\\"10.0.0.xx:9300\\",
\\"10.0.0.xx:9300\\", \\"10.0.0.xx:9300\\",, \\"10.0.0.xx:9300\\"]"
},
"restart_type": "full_cluster_restart"
}'
注意
上面的 API 中 es_config 字段的 key 是 discovery.seed_hosts,而不再是 discovery.zen.ping.unicast.hosts。
随后再通过脚本批量对云上集群每个节点执行如下命令来抹除集群元数据,随后便可以看到云上集群节点就可以成功加入自建集群中了。
ps -ef | grep java | grep c_log | awk '{print $2}' |xargs kill -9
cd /data1/containers/*/es/
./bin/elasticsearch-node detach-cluster (选择y)
3. 数据迁移(腾讯云侧操作) 这一步和7.0以下版本操作是一样的,主要目的是让分片从自建集群节点上逐步平滑迁移到云上节点上来,具体操作详情可参考上面步骤。
4. 集群分离(客户侧操作) 这一步和7.0以下版本操作是一样的,具体操作详情可参考上面步骤。
5. 配置恢复(腾讯云侧操作) 配置恢复的操作也基本和7.0以下版本一样,唯一的区别同样在于 es_config 参数中的 key,这里应该是 discovery.seed_hosts。同样采用 no_restart 不重启方式进行更新。
curl localhost:5100/cluster/update -d '{
"cluster_name": "es-cohesszwr",
"operator": "wr",
"es_config": { "discovery.seed_hosts": "null"},
"restart_type": "no_restart"
}'

在线融合迁移常见问题

自建集群节点切勿同时下线,需逐台停机下线

这里我们对7.0以上版本做过一系列测试,当集群处于融合状态后,然后一次性同时下线所有的自建集群节点后,云上集群会立即处于失主状态,导致集群不可用,业务出现大量报错。这主要是由于集群检测到一半节点(具有 node.master 角色)同时脱离集群后,已经不满足选出 Master 节点的基本条件,从而导致集群长期处于失主状态。
因此为了避免在集群分离时集群不可用风险,切勿同时下线自建节点, 而是需要逐台进行下线,并且把自建节点上当选的 Master 节点放在最后一个下线。否则会导致多次切主,且有可能多切到自建节点上。

禁止同一集群二次融合,否则会有索引丢失风险

在线融合迁移方案需要在集群融合后将所有的自建集群索引迁移到云上,强烈不建议只迁移部分索引,或者分批次迁移,如第一次融合后迁移部分业务索引,然后分离集群,过段时间再进行二次融合,再把剩余索引迁移过来。
结合我们的测试情况来看,当数据迁移完成两个集群分离后,自建的 ES 集群会出现 Red 情况,主要是由于索引都迁移到了云上,而自建集群上只有索引的元信息,因此会出现索引无法分配的情况,这也是集群分离后自建集群 Red 的原因。
通常这种情况下客户会选择删除这些索引以让集群恢复 Green。如果这时候再次将两个集群融合来迁移剩余索引的话,由于是通过全量重启云上集群节点来加入自建集群,因此融合后会以自建集群上当选 Master 上的集群元数据为准。因此一旦融合成功,就会把自建集群的元数据同步给云上集群节点,这时候就会直接删除云上第一次融合迁移过去的索引,从而导致之前迁移的索引数据全部丢失。这个风险的根本原因就是我们第一次分离后将自建集群上 Red 的索引删除了,而这些删除的索引都会记录在自建集群的元数据里,在一个叫索引坟墓的地方。融合后会同步这些元数据给云上集群。详情可参考官方文档 Index tombstones
虽然我们强烈不建议甚至禁止同一个集群二次融合,但是如果实在需要二次融合来解决业务不同阶段迁移的问题,可以通过如下解决方案来避免二次融合的数据丢失问题。
二次融合避免数据丢失解决方案:迁移索引 Reopen 方案:
1. 第一步:第一次融合,在集群分离后,对于自建集群上 Red 的索引,不要进行删除,而是对这些索引执行 close 操作,即 关闭索引
POST {index_name}/_close
2. 第二步 第二次融合,融合成功后,再将之前关闭的索引执行 open 操作,即 打开索引
POST {index_name}/_open
经过我们多次测试,迁移索引 Reopen 方案能够解决二次融合场景下数据丢失的问题。

客户端在融合前需确保已关闭嗅探功能

客户端开启嗅探 Sniff 功能是为了能够让 Client 端自动发现集群侧 ES 节点的动态变更。云上 ES 是通过 PrivateLink 打通的客户侧 VPC 和云上集群 VPC 网络,如果融合后客户端将访问配置切换到云上后,同时保持开启了嗅探功能,就会出现嗅探到的节点 IP 访问不同的情况,从而导致 Client 端大量的超时请求,影响业务使用。客户端报错信息可能如下:
NoNodeAvailableException[None of the configured nodes are available: [{#transport#-1}{VTss4h8SRsCpP6EW5PoLxxxrQ}{192.168.106.xxx}{192.168.106.xxx:9300}] ]at org.elasticsearch.client.transport.TransportClientNodesService.ensureNodesAreAvailable(TransportClientNodesService.java:347) at org.elasticsearch.client.transport.TransportClientNodesService.execute(TransportClientNodesService.java:245) at org.elasticsearch.client.transport.TransportProxyClient.execute(TransportProxyClient.java:59) ......
因此为了保障融合迁移方案对业务的透明和平滑,需要在融合前检查客户端是否开启了 Sniff 嗅探,如果开启需关闭此功能。不同语言客户端接入云上 ES 集群方式可以参考腾讯云 ES 官方文档 通过客户端访问集群