沙师弟,师父的充电器掉了

Day 14: Elasticsearch 5 入坑指南

Advent | 作者 kennywu76 | 发布于2016年12月15日 | | 阅读数:27243

尝鲜

10月26日,Elasticsearch5.0.0 GA终于放出,携程ES Ops团队也在第一时间在DEV和UAT环境分别进行了2.4.0 至5.0.0的升级和测试。升级完成后,除了部分Query不向前兼容(主要是Filtered Query),需要在应用端做一些修改以外,未发现其他问题。通过监控系统看对比升级前后的主要系统指标,在同等索引量的情况下,CPU使用率有明显下降 ( 30% - 50%左右) ,相信性能方面5.0应该是有较大提升的。 

在测试环境稳定运行了2周以后,我们决定选定一个生产集群进行升级,考验新版本在更为复杂的用户环境下的表现。 出于对业务影响最小化的考虑,用于日志分析的集群被圈定为升级目标。该集群也是携程十几个集群中规模最大的一个,共有120个数据结点运行于70台物理机上,总数据量接近1PB。

升级前需要做一些准备工作,下载官方的Migration Helper插件,检查集群设置和索引的兼容性。对于不兼容的配置项,MH会详尽列出,其中标注为红色部分为为升级前必须修改项。1.x版本创建的索引,是无法直接升级到5的,需要先在2.x集群里做一次reindex 。 MH提供了不兼容索引扫描功能,对于找到的不兼容索引,可以直接在UI上发起reindex操作,等待结束即可。 如果是用于业务搜索集群,数据可能比较重要,建议升级前做一个Snapshot,万一升级过程出现意外,可以回退版本从备份里快速恢复数据。我们的日志集群数据量极大,也没有对数据100%不丢的要求,因此升级前没有做Snapshot。 做完所有的准备工作后,预先通知所有用户集群升级的时间以及可能产生的影响,选定了周五深夜用户低峰期,开始正式升级工作。 

首先通过Ansible将新版本批量部署到所有结点并统一配置,紧接着对原有集群做了Full Stop,校验所有的ES已经停下后,开始Full Start。整个过程比较顺利,所有结点正常启动,数据恢复完成后,集群重新回到正常服务状态。

周末两天运行,未发现有任何的异样,CPU利用率也降了不少,看起来很靠谱……直到周一


踏坑

周一早上,随着用户访问量高峰来临,马上浮现出一个诡异的现象: 索引速率遇到了瓶颈,数据开始在前置的消息队列(Kafka)里堆积。 从监控数据看,尽管所有的数据结点CPU消耗都比上周同期低,磁盘IO也很低,但索引速率却低了很多。反复对比查看升级前后各类监控指标后,终于发现一个可疑点,所有结点的网络流量比升级前高了好几倍!  在集群架构上,我们是单独架设了几台client node做为数据写入和分发的入口,现在这几个node的网络流量已经饱和,成为数据写入的瓶颈。一开始,怀疑是否2.4启用了tcp压缩,而5.0取消了,但翻查官方文档后发现transport.tcp.compress在2.4和5.0里默认都是关闭的! 这时候只有两个解决办法了,要么启用tcp压缩,要么扩容client node。 先考虑了一下tcp压缩的方案,快速扒了一下ES源码,在transport.TcpTransport这个类里,sendRequest和sendResponse两个方法会根据transport.tcp.compress设置来决定发送的消息是否要经过压缩,而在messageReceived方法则会读取消息头部的状态信息,探测消息是否经过压缩以及压缩的方法,而后决定是否需要解压,以及采用的解压方式。 这样看起来,ES是允许tcp压缩和不压缩的结点之间通讯的,那么只对client node启用压缩应该就可以了。测试环境测试过后,验证了想法的可行性。于是对生产的client node开启tcp压缩,同时在数据发送端(hangout的ES output)也启用tcp压缩,重启client node后入口网络流量降到和之前2.4差不多的程度,问题得到规避。 针对这个问题在Github上提交了issue https://github.com/elastic/ela ... 21612, 但未得到官方合理的解释。

解决好这个问题,另外一个问题来了,很多执行大量历史数据搜索的用户反映出不了结果。 从监控数据看,这类查询的搜索耗时非常久,直到网关300秒超时(查询api前置的nginx代理)。我们之前对集群设置过Global Search timeout为60s,用来保护集群资源过多被超高代价的查询消耗,在2.4版本是有效果的,现在看来不起作用了。手动测试了一下,这个参数果然失效! 于是向官方报告了第2个问题:https://github.com/elastic/ela ... 21595 。 这个问题很快被官方确认为Bug,修复也很快加入到了5.0.2。 为了规避这个问题,我们只好临时修改了一下Kibana以及第三方API访问要经过的nginx proxy,默认为所有的search request加入一个超时选项。此后,问题有一些缓解,但仍然发现用户查询大范围历史数据时,部分用于存储历史数据的结点响应很慢。

我们的集群是做了冷热分离的结构的,热节点主要承担写入和存放过去24小时数据,冷结点没有写入,查询频率也低,所以为了最大化利用硬件资源,一台物理机上跑了3个实例,这样一台128GB内存的机器可以存放下近30TB的索引。查看冷结点的监控数据,看到用户查询期间磁盘的read IO非常高,直接将磁盘IO Util%撑到100%,并且可持续数小时,同时search thread pool有大量的active thread处于无法完成状态,search queue不断攀升直至饱和、开始reject。 表象上看search thread似乎一直在尝试从磁盘大量读取数据,一次search甚至可以持续几十分钟至一个小时,耗尽了所有的搜索线程,导致拒绝后续的搜索服务。 于是Github上报了第3个issue: https://github.com/elastic/ela ... 21611  这个问题找到解决办法之前,我们只能通过反复重启有问题的冷结点来缓解。 和官方讨论过程中,得知5.0在Lucene文件访问方式上有一个比较大的改动,2.4使用mmapfs读取索引文件的部分,而5.0以后改为用mmapfs读取索引文件的全部。怀疑问题和这个变动有关,尝试将所有索引文件的设置改为NIOFS后,问题迎刃而解。 搜索性能一下回到了2.4时代,再也没出现搜索线程超长时间执行的问题。之后找时间复现了这个问题,并抓取了线程栈,看到长时间执行的搜索线程一直在做Global Ordinal的构造工作。 至于为何会这样,还不清楚。 从官方给出的信息看,底层索引文件的访问模式是没有变化的,仅仅是将文件读取方式全部改成了mmapfs,理论上应该性能更好,但是看起来在我们这种一台机器跑多个ES实例,所有分配的heap为系统缓存3倍的极端用例下,大范围的数据搜索可能造成过高的磁盘读IO,集群性能指数级下降。

以上问题前后耗了4天才完全规避掉,支持团队连续熬夜后集群总算回复到平稳状态。然而好景不长,运行一段时间以后,数据结点出现疑似内存泄漏现象。结点总数据没怎么增加、甚至还有减少的情况下,heap使用率一只呈攀升趋势,Old GC无法回收内存。这个问题对用户影响较小,通过监控我们可以及时发现内存即将用尽的结点,做一次重启很快就恢复了。 为排查根源,我们对一个有问题的结点做了dump,通过MAT工具分析,看到meta data相关的一个alias对象被实例化了有6600万次之多! 在Github上提交了第四个issue: https://github.com/elastic/ela ... 22013,不多久被确认为已知问题https://github.com/elastic/ela ... 21284 ,在5.0.1已经修复。

最后还存在一个master node内存泄漏的问题,这个问题在2.4.0时代就存在了,升级到5.0.0以后依然没有修复。由于我们的master node和data node是分离的,所以这个问题比较容易通过监控发现,解决方式也很简单和迅速,重启master node即可,对用户完全无影响。之后不久,5.0.2版本正式发布,release notes里提到了对这个问题的修复 https://github.com/elastic/ela ... 21578

上周周末我们将集群rolling upgrade到了5.0.2,global search timeout失效和两个内存泄漏的问题从根源上解决掉了。 网络流量增大的问题依然存在,仍然需要通过启用client结点的transport.tcp.compress规避。 冷结点搜索性能的问题没看到有提及,估计没解决,安全起见,还是保持索引的文件系统为NIOFS。升级完成运行一段时间后,可以肯定,5.0.2已经比较稳定。


心得

升到5.0.2后,对于其中一组数据结点这两天特意加了点索引负载,通过监控数据将v5.0.2与2.4.0做实际运行环境的索引吞吐量对比。

2.4_.png


5.0_.png

 
在近似的CPU使用率和load情况下,5.0.2能够支撑更大的吞吐量。另外5.0带来的Instant aggregation功能,对于跨多个索引的时序类型数据的聚合也可以有效Cache了,在使用Kibana的时候提速感觉非常明显。

升级过程虽然遇到很多波折,但由于集群架构上做了角色分离(client,master,data)和冷热分离,因而Bug引起的故障比较容易被限定在一个较小的范围而不至于影响所有的功能和所有的用户。 故障点定位更加容易,规避措施也更容易实施。 部分规避措施实施过程中甚至对用户是完全无影响的,比如: 重启内存泄漏的master node)。详尽的监控为问题的发现和诊断提供了有力的支持。

Elasticsearch是非常复杂的系统,官方的测试无法覆盖所有的用例场景和数据规模,一些极端的应用场景可能触发某个深藏的Bug或者缺陷而陷入困境。 因此对于稳定性要求极高的应用,最好还是采用经过长时间考验的版本,比如v2.4.2。

[尊重社区原创,转载请保留或注明出处]
本文地址:http://elasticsearch.cn/article/120


33 个评论

请问这是什么监控插件??
自家公司开发的监控系统,前端图表集成的grafana
升级不是需要重建数据么?请问下你们这种规模的集群,怎么做升级的,大概需要停机多久
目前只有在1.x里创建的索引升5.x才需要重建数据。如果是2.x -> 5.x无需重建数据,可以比较平滑的升级。 如果不幸就是用的1.x,那么分场景。 数据规模大的场景通常是日志型应用,一般按天创建索引,那么可以先升级到2.x,然后等一段时间,直到1.x里创建的索引退化到没有用可以删除以后,再升级到5.x。 其他用作垂直搜索的场景,只能重新索引数据了,但是这种场景里数据规模一般不是太大,重新索引耗时不会太多。

升级本身做好准备的话很快,停机做集群full restart,1小时不到集群就可以恢复到yellow状态,重新投入使用,恢复到green状态则可能需要数小时。
@kennywu76 ,http://elasticsearch.cn/question/917,@medcl 说升级接口兼容,但是数据需要重建,还有请问一个问题,v2的索引里面有not_analyzed字段,如果升级这个索引还可以直接写数据进去么,会自动识别成keyword?
我很确定2.x 升级5.x无需重建数据,官方的升级文档也有说明 https://www.elastic.co/guide/en/elasticsearch/reference/current/setup-upgrade.html

官方有提供一个升级兼容性检测工具: https://github.com/elastic/elasticsearch-migration/。 这个工具可以发现不兼容的集群配置项,这些配置项需要在部署5.x的时候按照建议做相应的修改。另外如果集群里有1.x创建的索引,这个工具也会指出来,并且可以直接在界面上点点按钮做reindex。

not_analyzed字段升级后依然是string / not_analyzed,并不会自动改成keyword,但是5.x可以兼容这个字段类型,数据写入没问题。
“2.4使用mmapfs读取索引文件的部分,而5.0以后改为用mmapfs读取索引文件的全部。怀疑问题和这个变动有关,尝试将所有索引文件的设置改为NIOFS后,问题迎刃而解。 搜索性能一下回到了2.4时代”

这个有后续么?我的架构基本参照您的,也准备升级了
前一段我们的集群升级到了5.3.2,专门针对这个问题测试了一下,结论是问题依然存在。 在跑多个实例的结点上,如果将索引的设置为mmapfs,对大索引做terms aggregation的时候,磁盘读IO非常高,并且持续很长时间,用jstack看到es在build global ordinals。 直观感受,当系统剩余内存比较低的情况下,对大索引构造global ordinals可能引起大量不必要的磁盘IO。 改用NIOFS后,同样的操作快的多。 底层原因依然不清楚。
了解了,感谢答复
你好,有个业务前期数据量小,分片数和节点配置的较小,后期业务快速增长,需扩容,怎么平滑满足业务方使用?
只能重建索引? 调整分片数,扩大节点会使之前检索失效
首先,还是需要估算一下中期,长期的业务量和数据量,这样才好规划。
要做到对业务平滑的扩容,大致有下面几个方法:
1. 前期多shard做一些over-allocation,即shard数量稍微多一点,比如是node数量的2-3倍,数据量增加shard比较大的时候,通过加结点让shard均衡到新加结点。
2. 给索引加alias,业务通过alias间接访问索引。 当数据量增大,需要切分更多shard时,新建一个更多shard的索引,重新索引数据,之后做一次alias指向的切换,即可做到对业务无缝。
3. 如果新增的数据从特性上来说,是按照某个键值来增加的,比如时间、产品id、城市id等等,那么可以考虑用这个这个键值作为索引名的一部分,达到对索引分区的目的。 这样后面增加一个业务种类的时候,就是新增一个索引。 应用方面,可以根据分区的键值访问对应的索引,或者通过一个指向所有索引的alias,访问所有索引。
你好,想向你咨询一下es5.5如何修改thread_pool参数,命令行不能支持动态,写到yml中也报错,搞糊涂了
大神我也在做ES升级,遇到下面的问题,有空帮我分析分析,小弟感激不尽
https://elasticsearch.cn/question/2019
大神,现在贵公司用的啥版本?之前我们用的1.4。现在准备上5.6。数据迁移,本来想用snapshot的方式,但是官方文档显示需要借助2.x进行reindex,感觉有点麻烦,另外就是elasticdump那个插件。还有其他方式吗?求帮忙
我们线上跑的5.3.2,稳定性还不错。 1.x -> 5.x的迁移我没有做过,最佳实践还是论坛里找一下吧。
你好,请问现有的索引有办法修改mmapfs为niofs吗?需要reindex吗?
不需要,这个只是索引级别的一个设置。 但是这个设置是静态的,不能对open状态的索引直接做update。 需要先将索引close,然后用update settings api更改,再重新打开索引即刻生效。
谢谢!额外请教一个问题,es搜索和统计只会在主分片进行吗?(es重启后都是副本分片,主副分片看起来不会自动平衡)那么是否有接口可以提升副本分片为主分片?
搜索和统计是在主副分片之间轮流进行的。
学习了,有一个问题请教一下,我们这边的版本是2.X的,由于一个索引数据量大(4个亿多数据),过一段时间就会出现[FIELDDATA]Data too large的问题,这个应该是内存FIELDDATA缓存过多引起,这个有没有办法规避?也尝试配置indices.fielddata.cache.size,让他把缓存适时淘汰老的,但一配置发现查询会很慢,引起性能问题。这个有没有什么经验指导一下。谢谢
另外你们的单索引没有配到数据很大的情况吗?这种情况频繁查询,内存的缓存怎么满足。不断查询会使缓存占用越来越大,这个问题怎么处理,等到一定值后自动清理释放吗?
ES2.x对于支持doc values特性的字段默认都启用了,对这种类型的聚合排序都不会用到fileddata。 除非你的应用场景有对analyzed的字段做聚合排序,这时候可能会需要构造fielddata cache,这时候需要看一下字段类型设置是否合理,因为对这类字段做聚合排序通常结果没有什么意义。 可以用cat api查看一下feelddata里是哪些字段在吃内存,对这些字段做了哪些类型的查询。
这边是做了term条件查询,然后最后做时间字段以时间进行了排序,展现。这种会有问题吗?
term查询和时间字段排序都不会用到fielddata。你最好先用cat api查看一下fielddata的内容,看是哪些字段消耗内存。
好的,非常感谢。我按你的方法再确认下。
好的,非常感谢。我按你的方法再确认下。
使用reindex进去1.x到5.x的升级时,发现源集群的资源消耗比较严重,requests_per_second做限制之后会发现比较慢,100T数据量下的迁移有没有比较好的建议呢,并没有找到特别好的办法呢
如果1.x的索引规模很大,没有什么好办法,只能是等待reindex完成。
请问贵司最大的日志集群准备入es6的吭么
已经在ES6上了, 300多个结点, 日索引数据量1600亿, 80TB,集群总数据量2.5万亿。
太牛逼了。请问下贵司hot节点的大概什么配置,单物理机部署几个实例。
我是单台机器部署4个节点,每小时压缩前数据大概4T左右,20个物理节点,在查询量大的时候,io已经很吃力,影响到写入了。请问这种情况只能加机器么。
我是按小时建索引。查询量大的时候机器io ops彪高,我已经控制到单节点单shard了,doc value等也都关掉了。
有32vcore,128GB RAM和48vcore , 192GB RAM两种物理机。 机器做了冷热分离,热数据写入节点只部署1个实例,保存近2天数据。 冷结点部署3个实例,主要用于保存2天前的历史数据。 你这个数据量级也只能加机器了。
你好,我想咨询一下,配置了Global Search timeout之后;
当到达设定的时间后,会总之查询吗?在服务器端查询的请求还在执行吗?

要回复文章请先登录注册