
最近需要把一台服务器上的Elasticsearch数据迁移到另一台服务器。我心想这有什么难的?不就是把数据拷贝过去,重新启动就完事了。
结果这个"简单"的迁移任务,差点把我搞疯。

上图就是我的迁移思路:服务器A的ES数据迁移到服务器B。看起来很直接,做起来各种坑。
我原来部署ES的时候图省事,没有做数据挂载。现在要迁移数据,得先把容器里的数据拷贝出来。
ES的数据默认存在容器的/usr/share/elasticsearch/data目录下,需要先拷贝到宿主机:
# 从ES容器拷贝数据到宿主机
docker cp es_container:/usr/share/elasticsearch/data /backup/es_data然后把这些数据传输到目标服务器。我用的scp:
scp -r /backup/es_data user@target_server:/data/elasticsearch/在目标服务器上,用相同的版本启动ES容器,并挂载数据目录:
docker run -d \
--name elasticsearch \
-p 9200:9200 \
-v /data/elasticsearch:/usr/share/elasticsearch/data \
elasticsearch:7.16.2重要提醒:版本一定要保持一致!我就是在这里踩了坑,版本不一致导致数据格式不兼容。
容器启动后,ES立马报错退出:
java.lang.IllegalStateException: failed to obtain node locks, tried [[/usr/share/elasticsearch/data]] with lock id [0]; maybe these locations are not writable or multiple nodes were started without increasing [node.max_local_storage_nodes] (was [1])?看这个错误,明显是权限问题。ES容器里的用户无法访问挂载的数据目录。
# 修改数据目录的所有者和权限
sudo chown -R 1000:1000 /data/elasticsearch
sudo chmod -R 775 /data/elasticsearch这里的1000:1000是ES容器内部用户的UID和GID。修改完权限后,重新启动容器,这个问题就解决了。
权限问题解决后,ES容器能正常启动了,但是查询数据的时候又出问题了:
ElasticsearchStatusException[Elasticsearch exception [type=search_phase_execution_exception, reason=all shards failed]]all shards failed?这是什么鬼?
curl -X GET "http://127.0.0.1:9200/_cluster/health?pretty"结果显示:
{
"cluster_name" : "docker-cluster",
"status" : "red",
"unassigned_shards" : 2,
"active_shards_percent_as_number" : 89.47
}status是red,还有2个未分配的分片。这就是导致查询失败的原因。
curl -X GET "http://127.0.0.1:9200/_cat/shards?v&pretty"
从图片可以看到,确实有几个分片的状态是UNASSIGNED,没有分配到节点上。
curl -X GET "http://127.0.0.1:9200/_cluster/allocation/explain?pretty" -H 'Content-Type: application/json' -d '{
"index": "acowbo_new",
"shard": 0,
"primary": true
}'这个命令能告诉你分片为什么没有分配。执行后发现了关键信息:
"details" : "failed shard on node: failed to create index, failure IllegalArgumentException[Custom Analyzer [ik_analyzer] failed to find tokenizer under name [ik_smart]]"找到问题了:自定义分析器ik_analyzer找不到ik_smart分词器!
原来的ES安装了IK分词器插件,但是新的ES容器没有安装,导致索引无法正常创建。
# 进入ES容器
docker exec -it elasticsearch /bin/bash
# 安装IK分词器插件(版本要和ES版本匹配)
bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.16.2/elasticsearch-analysis-ik-7.16.2.zip安装完插件后,重启ES容器:
docker restart elasticsearch重启后再次检查集群状态:
curl -X GET "http://127.0.0.1:9200/_cluster/health?pretty"现在status应该变成green了,unassigned_shards也变成0。
查询功能也恢复正常了。
这次ES迁移让我学到了不少东西:
不只是拷贝数据文件,还要考虑:
Docker容器的用户权限和宿主机不同,数据目录的权限要特别注意:
如果原ES用了自定义插件,新环境必须安装相同版本的插件。缺少插件会导致:
遇到分片问题,排查顺序应该是:
我原来部署ES图省事,没做数据挂载,这次迁移就吃亏了。要先docker cp把数据拷出来,麻烦得要死。
以后部署ES第一件事就是做数据挂载,省得迁移的时候折腾。
从一台服务器拷贝到另一台服务器,文件的所有者和权限都可能变化。ES容器启动的时候,如果没有权限访问数据目录,就会直接报错退出。
记住要用chown -R 1000:1000和chmod -R 775修改权限。
这个是我完全没想到的。原来的ES用了IK分词器,新环境没装,直接导致分片分配失败。
而且插件版本还得和ES版本严格匹配,差一个小版本都可能不兼容。
经过这次折腾,我总结了几个经验:
迁移前先看看原环境用了什么插件,记录下来,新环境也要装相同版本的。
版本一定要保持一致,别想着顺便升级个版本什么的,数据迁移的时候风险太大。
迁移完不要急着庆祝,先检查集群状态,确保所有分片都正常,再测试查询功能。
说实话,这次ES迁移比我想象的复杂多了。以前以为就是拷贝数据文件的事,现在才知道涉及这么多细节。
记录下来,希望其他人别像我一样踩这些坑。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。