背景
近日得知一个使用到es 的功能,该功能写入了21亿条文档,可能导致接下来写入失败导致影响业务。紧急学习es 相关知识,进行处理。
救赎
简单的知识背景
es 的一些基础设定,可以跟mysql 进行一定的映像,如索引=库,type = 表,doc = 每一行数据。大概可以这么理解,但并不完美。为了快速理解问题稍微铺垫一下。
业务中有多方会像es 集群中的一个索引写入数据,之后通过kibana 提供搜索功能。但由于开始设计索引时,没有设计分片,只用了单分片单副本,导致es 资源使用的不合理,写入数据有了上限,也就是2,147,483,519个。如今我们的业务还有3千万的写入空间。
简单解法
既然是空间不够了,那我就清理空间呗,想到了通过post /index_name/
_query_delete 语法,因为并不需要太久远的数据,想着直接清除掉之前的数据就能得救,就喜出望外。事实并不是如此,尝试过后,发现无法删除数据。
因为数据量过大,而且基于es 的特性,长处是搜索的便捷,而删除索引内部的数据就成了短板。
进阶法
基于这样的考虑,在不动现有业务逻辑的情况下,有了一个新的解决方法就是,将现有索引设置为只读:
#开启索引只读 PUT index_name/_settings {"index.blocks.read_only_allow_delete":true} #开启索引块只读 PUT index_name/_settings {"index.blocks.read_only":true}
重新构建新索引,将索引进行分片,按现有数据300个G计算,每个分片承载30-60个G的数据,需要设置9个分片。
然后通过reindexAPI进行数据迁移
POST _reindex?slices=auto&wait_for_completion=false {"source":{"index":"source_index","dest":{"index":"dest_index"}}
现有300个G 的数据在reindex的过程中至少需要6个小时的数据迁移,无法记录新生成的数据,由于对新数据的依赖性,这种个做法是对业务有伤害性的,评估下来暂不可取。
适合法
结合上述进阶法,新建一个索引,设置6个分片,与旧索引相同的mapping。
put /new_index_name {"setting":{ "number_of_shards" : 6, "number_of_replicas" : 1}}
然后给新索引设置别名:
POST /_aliases {"actions":[{"add":{"index":"new_index","alias":"new_index_alias"}}]}
给新索引创建好别名后,以后一旦索引数量上去之后可以直接再次新建索引,并给新索引取之前的别名,即可滚动持续的将业务维持下去。唯一美中不足的是需要业务方进行修改,好在绝大多数数据的写入是自己部门进行维护,少了被人掣肘的点,还是可喜可贺的。
现在只是将新索引及使用别名写入查询跑通了,为了保证思绪的完整,静待明日解救这个即将瘫痪的业务吧。
总结
在选择好技术后,一定要对其有一个预期的走势判断,否则前期没有做好基础性的建设,很快业务到达瓶颈,后人不清楚当时的业务逻辑,很难有快速应对的办法。良好的前瞻性设计,多考虑系统的可扩展性,才能体现一个工程师的价值!
大家加油!!!