首页 > 其他分享 >ES索引数据迁移、分片数优化(reindex)

ES索引数据迁移、分片数优化(reindex)

时间:2024-05-08 17:48:04浏览次数:20  
标签:index reindex URL 索引 USER 分片 ES

目录

ES索引数据迁移、分片数优化(reindex)

​ Elasticsearch是⼀个实时的分布式搜索引擎,为⽤户提供搜索服务。当我们创建好一个索引时,内部的mapping是无法更改的,当业务发生变化,或是当初规划错误导致每个分片数据量过大(网上建议单个分片最大50G)就会影响数据的查询效率,这时候就要重新创建索引,进行数据的迁移了。

业务背景

​ 当初公司人员对ES还不太了解,创建索引时随意设置,导致有些索引分片设置的极其不合理,旱的旱死,涝的涝死,如下两图:

总共35个分片,平均一个分片存储1.3gb大小数据

总共30个分片,平均一个分片存储66gb大小数据

ES的分片数量可以理解为与HDFS的小文件数,如果ES分片数过多会增大整个ES集群的压力,如果单个分片存储的数据过大,又会影响查询效率

步骤

假设原索引名为my_index,更新为reindex_my_index新索引

  1. 新增一个索引redinex_my_index,Mapping看需求选择是否更原来my_index一样(这里一样)
  2. 通过官方_reindex方法将my_index同步至redinex_my_index
  3. 校验同步结果,确保两个索引的分片数一致
  4. 删除my_index索引
  5. redinex_my_index索引起一个别名,就叫my_index
  6. redinex_my_index索引创建对应my_index索引的metric

新建索引

​ 这边只是想缓解一下集群的压力,进行分片数合并,因此Mapping将保持原来的一样。

  • 获取原索引的body
curl  -u$USER_NAME:$PASSWORD -H 'Content-Type:application/json' -X GET $ES_URL/$index | jq '."'$index'"' | jq 'del(.settings.index.creation_date,.settings.index.uuid,.settings.index.version,.settings.index.provided_name,.aliases)' | jq '.settings.index.number_of_shards='$shardNum''

通过GET请求获取原索引的结构,再通过jq(一种json数据处理工具,可以查一下具体的语法)筛选出对应索引名 '."'$index'"' 下的json数据,由于后面要创建相同的索引,有些结构数据用不到,索引后面通过jqdel()删除了一些索引结构数据,最后通过jq对里面的分片数进行更改,进而创建出了新的索引

  • 创建索引
curl  -u$USER_NAME:$PASSWORD  -H 'Content-Type:application/json' -X PUT "$ES_URL/$newIndexName -d '$newIndexBody'"

将原索引数据复制到新索引中

在同步时,先开启索引只读权限,防止数据在同步的过程中,原索引进行写入、删除操作,导致同步异常的事情发生

  • 原索引开启只读
curl -u $USER_NAME:$PASSWORD -H 'Content-Type:application/json' -X PUT $ES_URL/$index/_setting -d'{"index.blocks.read_only_allow_delete":true}'

关于ES内的数据同步,官方是给出了_reindex方法的。

参数:

​ source:原信息,index为原索引名

​ dest:目标信息,index为新索引名

  • 同步等待
curl -u $USER_NAME:$PASSWORD -H 'Content-Type:application/json' -X POST $ES_URL/_reindex -d'{"source": {"size": '$SIZE', "index": "'$index'"}, "dest": {"index": "'$newIndexName'"} }'

size参数是每秒批处理多少条数据,官方默认是1000条。

上面的是同步等待,意思是只能等待上面的执行完,才能继续同步其他的索引,如果想实现异步同步,需关闭wait_for_completion参数。

  • 异步同步
curl -u $USER_NAME:$PASSWORD -H 'Content-Type:application/json' -X POST $ES_URL/_reindex?wait_for_completion=false -d'{"source": {"size": '$SIZE', "index": "'$index'"}, "dest": {"index": "'$newIndexName'"} }'

请求成功后,会返回相应的TaskID,通过这个ID就可以随时查看运行进度

{"task":"AzDO4-XThyZ_fe8VdpAgw:364135143"}
  • 查看异步同步结果
curl -u $USER_NAME:$PASSWORD -H 'Content-Type:application/json' -X GET $ES_URL/_tasks/$TaskID

通过completed为true判断reindex任务已结束

通过response.time.out为false判断reindex任务已完成

通过对比response.totalresponse.created判断数据是否全部复制到新索引中

校验结果

查看原索引数量:

curl -u $USER_NAME:$PASSWORD -X GET $ES_URL/_cat/count/$index?v

查看新索引数量:

curl -u $USER_NAME:$PASSWORD -X GET $ES_URL/_cat/count/$newIndexName?v

对比两个量级是否一致

删除原索引

当文档数量一致后,就可以删除原索引了

curl  -u$USER_NAME:$PASSWORD  -H 'Content-Type:application/json' -X DELETE $ES_URL/$index

给新索引起别名

curl  -u$USER_NAME:$PASSWORD  -H 'Content-Type:application/json' -X POST $ES_URL/_aliases -d'{"actions" : [{ "add" : { "index" : "'$newIndexName'", "alias" : "'$index'" } } ] }'

创建新索引的metric

该步骤用于触发新索引的数据清理功能,同名的Metric无需重复创建

先获取原索引的metric

oldMetricName=$(echo $index | cut -d "@" -f 1)

newMetricBody=$(curl -u$USER_NAME:$PASSWORD  -H 'Content-Type:application/json' -X GET $ES_URL/_metric/$oldMetricName |jq '.result' | jq '."'$oldMetricName'"')

创建新的meteric

curl -u$USER_NAME:$PASSWORD -H 'Content-Type:application/json' -X PUT $ES_URL/_metric/$newMetricName -d "'$newMetricBody'"

至此,整个ES索引数据迁移、分片优化(reindex)完成了

脚本整合

#!/bin/bash

#新index的名称前缀
REINDEX_PREFIX='reindex_'

#实例ip和端口
ES_URL='your_ip:your_post'

#实例用户名称
USER_NAME='your_username'

#实例用户名称对应的密码
PASSWORD='your_password'

#批处理大小,reindex较慢时可适当调大
SIZE=5000

INDEX_1=$1

# 如果输入的索引名的长度为0
if [ -z "$INDEX_1" ]; then
	##查询出分片数大于指定值的索引-------------------------------------------------------------------获取分片数大于30的索引名----
	curl  -u$USER_NAME:$PASSWORD  -H 'Content-Type:application/json' -X GET $ES_URL/_cat/indices | awk '$5 > 30 {print $3}' | awk '!seen[$1]++' | cut -d ' ' -f 1 >./waitForMergeIndex.txt

	echo "***********Start to Execute Reindex Task...************"
	while IFS= read -r index; do
		## 使用 </dev/tty 对read的输入源进行重定向,限定只能通过当前的终端输入,其下面还有tty0、tty1...tty...,代表着第一个终端虚拟机、第二个终端虚拟机、...、第n个终端虚拟机
		read -p "请确认是否要修改索引:$index 的分片数?请输入y或n:" -r confirmReindex </dev/tty
		if [ "$confirmReindex" = "n" ]; then
			continue
		fi
		echo "开始更新索引分片等配置信息,当前索引名称:$index"
		read -p "请输入新分片数:" -r shardNum </dev/tty
		#read -p "请输入新refresh_interval:" -r refreshInterval  < /dev/tty
		#read -p "请输入新副本数:" -r replicas  < /dev/tty

		##查询表结构
		##newIndexBody=`curl -H 'Content-Type:application/json' -X GET  $ES_URL/$index  | jq '."'$index'"' |jq  'del(.settings.index.creation_date,.settings.index.uuid,.settings.index.version,.settings.index.provided_name,.aliases)' |jq '.settings.index.number_of_shards='$shardNum'' |jq '.settings.index.number_of_replicas='$replicas'' |jq '.settings.index.refresh_interval='"$refreshInterval"''`

		## 通过get索引获取原索引的结构,再通过jq(一种json数据处理工具,可以查一下具体的语法)筛选出对应索引名 `'."'$index'"'` 下的json数据,由于后面要创建相同的索引,有些结构数据用不到,索引后面通过jq del()删除了一些索引结构数据,最后通过jq对里面的分片数进行更改,进而创建出了新的索引
		newIndexBody=$(curl  -u$USER_NAME:$PASSWORD -H 'Content-Type:application/json' -X GET $ES_URL/$index | jq '."'$index'"' | jq 'del(.settings.index.creation_date,.settings.index.uuid,.settings.index.version,.settings.index.provided_name,.aliases)' | jq '.settings.index.number_of_shards='$shardNum'')
		#echo $newIndexBody
		echo "开始执行reindex..."
		##创建新表 -- 表名
		newIndexName+=$REINDEX_PREFIX$index

		echo "创建新表:$newIndexName"
		## 建表语句,将建表语句赋值给req变量
		req+="curl  -u$USER_NAME:$PASSWORD  -H 'Content-Type:application/json' -X PUT $ES_URL/$newIndexName -d '$newIndexBody'"
		#echo $req
		## 将字符串转换成可执行的语句
		reqEval=$(echo -e $req)
		#echo $reqEval
		## eval动态执行,有点像scala、python中的惰性函数
		eval $reqEval
		echo -e "\n"

		##执行reindex迁移
		echo "开始执行reindex,对于较大的索引耗时可能较长,可通过命令监控或者取消reindex任务,监控reindex:curl -u root:le201909 -H 'Content-Type:application/json' -X GET 172.xx.xx.4:9201/_tasks/AnNKL9xwR_iXHvGViMwELw:9476639         取消reindex:curl -u root:le201909 -H 'Content-Type:application/json' -X POST 172.xx.xx.4:9201/_tasks/AnNKL9xwR_iXHvGViMwELw:9476639/_cancel"
		reindexBody+='{"source": {"size": '$SIZE', "index": "'$index'"}, "dest": {"index": "'$newIndexName'"} }'
		# 如果 reindex 时间过长,建议加上 wait_for_completion=false 的参数条件,这样 reindex 将直接返回 taskId,任务在后台运行。
		reindexReq="curl -u $USER_NAME:$PASSWORD -H 'Content-Type:application/json' -X POST $ES_URL/_reindex?wait_for_completion=false -d'$reindexBody' | jq '.task' | tr -d '\"'"

		#echo -e "\nreindex命令执行返回为:"
		#echo $reindexReq
		reindexReqEval=$(echo -e $reindexReq)
		#echo $reindexReqEval
		echo -e "\nreindex命令执行返回为:"
		taskId=$(eval $reindexReqEval)
		echo "reindex任务ID:$taskId"
                echo -e "\n"

		##循环查询任务执行结果,执行结束后继续其他流程
		taskComplete=0
		while [ $taskComplete -eq 0 ]; do
			taskResult=$(curl  -u$USER_NAME:$PASSWORD  -H 'Content-Type:application/json' -X GET $ES_URL/_tasks/$taskId | jq '.completed')
			echo "任务是否已完成:$taskResult"
			if [ "$taskResult" == "true" ]; then
				taskComplete=1
			fi
			sleep 1s
		done

		echo "Reindex任务已执行完毕,请继续确认以下步骤。"

		##删除旧索引
		read -p "请再次确认是否要删除该索引:$index ,输入y确认删除,n为不删除,若不执行删除,需要手动创建别名和删除索引才能完成分片调整流程: " -r confirmDel </dev/tty

		if [ "$confirmDel" = "y" ]; then
			echo "正在删除旧索引:$index"
                	curl  -u$USER_NAME:$PASSWORD  -H 'Content-Type:application/json' -X DELETE $ES_URL/$index
                	echo -e "\n"
		fi

		##创建别名
		echo "为新表创建别名..."
		aliases+='{"actions" : [{ "add" : { "index" : "'$newIndexName'", "alias" : "'$index'" } } ] }'
		aliasesReq+="curl  -u$USER_NAME:$PASSWORD  -H 'Content-Type:application/json' -X POST $ES_URL/_aliases -d'$aliases'"
		aliasesReqEval=$(echo -e $aliasesReq)
		echo $aliasesReqEval
		eval $aliasesReqEval
		echo -e "\n"

		##创建reindex后的metric
		echo "为reindex生成的子表创建对应的metric..."
		oldMetricName=$(echo $index | cut -d "@" -f 1)
		newMetricName=$REINDEX_PREFIX$oldMetricName
		newMetricBody=$(curl -u$USER_NAME:$PASSWORD  -H 'Content-Type:application/json' -X GET $ES_URL/_metric/$oldMetricName |jq '.result' | jq '."'$oldMetricName'"')
        	metricReq+="curl -u$USER_NAME:$PASSWORD -H 'Content-Type:application/json' -X PUT $ES_URL/_metric/$newMetricName -d '$newMetricBody'"
        	metricReqEval=$(echo -e $metricReq)
        	eval $metricReqEval
        	echo -e "\n"

		echo "索引:$index 分片调整结束。"
		req=''
		reindexBody=''
		reindexReq=''
		newIndexName=''
		aliases=''
		aliasesReq=''
		newMetricName=''
		newMetricBody=''
		metricReq=''
		metricReqEval=''
		oldMetricName=''
		echo -e "\n"
		echo -e "\n"
	done <"./waitForMergeIndex.txt"

else
	read -p "请确认是否要修改索引:$INDEX_1 的分片数?请输入y或n:" -r confirmReindex </dev/tty
	if [ "$confirmReindex" = "n" ]; then
		exit 0
	fi
	echo "开始更新索引分片等配置信息,当前索引名称:$INDEX_1"
	read -p "请输入新分片数:" -r shardNum </dev/tty
	#read -p "请输入新refresh_interval:" -r refreshInterval  < /dev/tty
	#read -p "请输入新副本数:" -r replicas  < /dev/tty

	##查询表结构
	##newIndexBody=`curl  -u$USER_NAME:$PASSWORD  -H 'Content-Type:application/json' -X GET  $ES_URL/$INDEX_1  | jq '."'$INDEX_1'"' |jq  'del(.settings.index.creation_date,.settings.index.uuid,.settings.index.version,.settings.index.provided_name,.aliases)' |jq '.settings.index.number_of_shards='$shardNum'' |jq '.settings.index.number_of_replicas='$replicas'' |jq '.settings.index.refresh_interval='"$refreshInterval"''`

	newIndexBody=$(curl  -u$USER_NAME:$PASSWORD  -H 'Content-Type:application/json' -X GET $ES_URL/$INDEX_1 | jq '."'$INDEX_1'"' | jq 'del(.settings.index.creation_date,.settings.index.uuid,.settings.index.version,.settings.index.provided_name,.aliases)' | jq '.settings.index.number_of_shards='$shardNum'')
	#echo $newIndexBody
	echo "开始执行reindex..."
	##创建新表-即新的索引名,$REINDEX_PREFIX为事先设置好的索引前缀名
	newIndexName+=$REINDEX_PREFIX$INDEX_1

	echo "创建新表:$newIndexName"
	# 该语句类似:create table newIndexName as select * from newIndexBody
	req+="curl  -u$USER_NAME:$PASSWORD   -H 'Content-Type:application/json' -X PUT $ES_URL/$newIndexName -d '$newIndexBody'"
	reqEval=$(echo -e $req)
	#echo $reqEval
	
	# 执行语句
	eval $reqEval
	echo -e "\n"

	##执行reindex迁移
	echo "开始执行reindex,对于较大的索引耗时可能较长,可通过命令监控或者取消reindex任务,监控reindex:curl -u root:le201909 -H 'Content-Type:application/json' -X GET 172.xx.xx.4:9201/_tasks/AnNKL9xwR_iXHvGViMwELw:9476639         取消reindex:curl -u root:le201909 -H 'Content-Type:application/json' -X POST 172.xx.xx.4:9201/_tasks/AnNKL9xwR_iXHvGViMwELw:9476639/_cancel"
	reindexBody+='{"source": {"size": '$SIZE', "index": "'$INDEX_1'"}, "dest": {"index": "'$newIndexName'"} }'
	reindexReq="curl -u $USER_NAME:$PASSWORD -H 'Content-Type:application/json' -X POST $ES_URL/_reindex?wait_for_completion=false -d'$reindexBody' | jq '.task' | tr -d '\"'"

	#echo -e "\nreindex命令执行返回为:"
	echo $reindexReq
	reindexReqEval=$(echo -e $reindexReq)
	echo $reindexReqEval
	echo -e "\nreindex命令执行返回为:"
	taskId=$(eval $reindexReqEval)
	echo "reindex任务ID:$taskId"
	echo -e "\n"

	##循环查询任务执行结果,执行结束后继续其他流程
	taskComplete=0
	while [ $taskComplete -eq 0 ]; do
		taskResult=$(curl  -u$USER_NAME:$PASSWORD  -H 'Content-Type:application/json' -X GET $ES_URL/_tasks/$taskId | jq '.completed')
		echo "任务是否已完成:$taskResult"
		if [ "$taskResult" == "true" ]; then
			taskComplete=1
		fi
		sleep 1s
	done

	echo "Reindex任务已执行完毕,请继续确认以下步骤。"

	##删除旧索引
	read -p "请再次确认是否要删除该索引:$INDEX_1 ,输入y确认删除,n为不删除,若不执行删除,需要手动创建别名和删除索引才能完成分片调整流程: " -r confirmDel </dev/tty

	if [ "$confirmDel" = "y" ]; then
		echo "正在删除旧索引:$INDEX_1"
        	curl  -u$USER_NAME:$PASSWORD  -H 'Content-Type:application/json' -X DELETE $ES_URL/$INDEX_1
        	echo -e "\n"
	fi

	##创建别名
	echo "为新表创建别名..."
	aliases+='{"actions" : [{ "add" : { "index" : "'$newIndexName'", "alias" : "'$INDEX_1'" } } ] }'
	aliasesReq+="curl  -u$USER_NAME:$PASSWORD  -H 'Content-Type:application/json' -X POST $ES_URL/_aliases -d'$aliases'"
	aliasesReqEval=$(echo -e $aliasesReq)
	echo $aliasesReqEval
	eval $aliasesReqEval
	echo -e "\n"
	
	##创建reindex后的metric
	echo "为reindex生成的子表创建对应的metric..."
	oldMetricName=$(echo $INDEX_1 | cut -d "@" -f 1)
	newMetricName=$REINDEX_PREFIX$oldMetricName
	newMetricBody=$(curl -u$USER_NAME:$PASSWORD  -H 'Content-Type:application/json' -X GET $ES_URL/_metric/$oldMetricName |jq '.result' | jq '."'$oldMetricName'"')

	metricReq+="curl -u$USER_NAME:$PASSWORD -H 'Content-Type:application/json' -X PUT $ES_URL/_metric/$newMetricName -d '$newMetricBody'"
	metricReqEval=$(echo -e $metricReq)
	eval $metricReqEval
	echo -e "\n"

	echo "索引:$INDEX_1 分片调整结束。"
	req=''
	reindexBody=''
	reindexReq=''
	newIndexName=''
	aliases=''
	aliasesReq=''
	echo -e "\n"
	echo -e "\n"
fi

echo "***********Reindex Task End...************"

使用感受

​ 这种方法效率极其低下,当数据量大于40g时(大概4亿多条数据),要等上1天的时间,期间如果遇上网络波动、集群压力过大都会造成同步的失败。单批次数据量过大的时,还会增大集群的压力。

​ 求大神推荐新方法!!!(由于效率极其地下,这边对一些数据不常用,随时间变化影响大的数据设置了TTL,缩减了数据过期时间以及增大了滚动周期,以此来缓解分片数的增长)

标签:index,reindex,URL,索引,USER,分片,ES
From: https://www.cnblogs.com/Mr-Sponge/p/18180344

相关文章

  • Debian 系统 IP 和 DNS 配置, 解决 resolv.conf 文件导致的问题
    IP配置/etc/network/interfacesautoeth0ifaceeth0inetstaticaddressx.x.x.xnetmask255.255.255.0gatewayx.x.x.x#dns-nameservers没有用DNS配置修改文件/etc/systemd/resolved.confDNS=8.8.8.88.8.4.4重启systemd-resolvedsystemctlrestartsystemd-res......
  • Server-side vulnerabilities :path traversal
    来自bp的学院,提供了靶机,是个学习好地方服务器漏洞之路径遍历 就是说网站提供的图片,如果直接通过src="/loadImage?filename=xxx.jpg“读取的话,可以通过构造”filename=../../../etc/passwd"参数,拿到服务器的passwd文件,这样能读取服务器的用户放一个靶机地址:https://portswigg......
  • sql server时间戳timestamp
    原文链接:https://www.cnblogs.com/hanke123/p/4741561.html在SQLServer中联机丛书是这样说的:SQLServertimestamp数据类型与时间和日期无关。SQLServertimestamp是二进制数字,它表明数据库中数据修改发生的相对顺序。实现timestamp数据类型最初是为了支持SQLServer恢......
  • lesson1
    单词court法庭settlesthoutofcourt私了accumulate/amassv积累amasspossessions积累财富pileup/collect/gather/hoard越积越多Meanwhile,thetraficpiledupbehind.Shenzhenrealestatedevelopershoardlagrgeamountsofland.obligev使...感到必须be......
  • 新手必看!2024年入行Salesforce终极指南!
     Salesforce这个千亿美金巨兽,在全球范围内有42,000多名员工。作为一家发展迅速的科技公司,一直在招聘各种角色,包括销售、营销、工程师和管理人员等。 IDC报告显示,2022年至2028年间,Salesforce经济净收益预计达2万亿美元,并在全球创造1200万个就业岗位。 什么是Salesforce......
  • Testing Egineer note:2024_5_8-day07-part02
    设计测试用例编写技巧设计测试用例编写技巧查看用例的模板案例模板1:案例模板2:案例模板3:用例的要素讲解编写用例的要素?用例编号,用例标题,前置条件,测试步骤,预期结果,优先级(必写)系统名称、模块名称、用例创建时间,实际结果,用例类型,执行时间,执行状态等(非必填项)详......
  • Testing Egineer note:2024_5_8-day07-part01
    设计测试用例方法之白盒测试法(了解)白盒测试技术白盒测试(结构测试或者逻辑驱动测试)定义:白盒测试也叫透明盒测试,检查程序内部结构及路径一是否符合规格说明,二是否符合其代码规范。白盒测试常见方法:语句覆盖;判断覆盖(也称“分支覆盖”);条件覆盖;判断、条件覆盖;条件组合覆盖;路......
  • Cannot resolve method 'and(java.util.function.Predicate<java.lang.String>)
    springboot整合knife4j报错,提示找不到该方法,用的knife4j依赖是最新版本解决方法:将knife4j版本进行降级处理,这里采用2.0.4......
  • Ant Design
    AntDesignofReact(antd)中的表单form如何设置两个formItem之间的间距?margin-bottom:24px;用antdesign的form时候,设置行垂直间距没啥用magin是透明的,没有颜色,padding是有颜色的model注意设置z-index固定侧边栏:style="{overflow:'auto',height:'100vh',positio......
  • iOS pod删除某一个框架记录一下 eg: JMessage
    pod删除JMessage 提示没有找到 “jcore-ios” 在otherlinkerFlags 中删除 “jcore-ios” 删除后说没有找到“JMessage”继续删除  删除后问题出现了   提示没有找到coreimage 很奇怪 根本没有动这个文件 继续删除问题更多,回去排查发现 -fram......