窝窝团的ES经验教训总结

本文节选自研发解决方案介绍#基于ES的搜索+筛选+排序解决方案 

ES 的几次事故和教训

1>误删数据

  ES 的 Web 控制台权限很大,可以删数据。

  有一天,一个开发者需要查询索引 mapping,他用 firefox 的插件访问,结果 Method 默认居然为 DELETE,如下图所示:

http://images.cnitblog.com.sixxs.org/blog/7438/201412/121918225874156.png

  没有注意,于是悲剧发生了。

教训:

1)后来耀华咨询了长期运维ES的一些人,大部分都建议前置一个 ngnix,通过 ngnix 禁用 delete 和 put 的 HTTP 请求,借此来限制开放的ES接口服务。

2)这次的误操作,实际上是在没有给定索引的情况下,误执行了DELETE 操作,结果删除了全部索引。其实配一下 ES 是可以避免的,加入这个配置:

    action.disable_delete_all_indices=true

   这样会禁止删除所有索引的命令,删除索引的话,必须要给定一个索引 ,稍微安全一些。

 

2>mvel 脚本引发的ES事故

ES集群表象:

  一天,ES 各个节点负载升高,JVM Full GC 频繁。

  查看其内存使用状况发现,ES 各个节点的 JVM perm 区均处于满或者将要满的状态

问题原因:

  头一天上线了商品搜索的一个动态排序功能,它采用 ES 的 mvel 脚本 来动态计算商品的排序分值。而 mvel 的原理是基于 JIT,动态字节码生成的,于是很有可能造成 perm 区持续升高,原因是它不断地加载和生成动态 class。

  由于 ES 各个节点的 perm 区接近饱和状态,所以造成了服务器负载升高,GC 频繁,并进一步造成 ES 集群出现了类似于“脑裂”的状态。

 

经验教训:

 引入新技术,还是要谨慎,毕竟如果真是 mevl 脚本引起的问题,其实线下做压力测试就能提前发现。

加强ES的监控。

虽然现在回过头来看,如果在第一时间重启所有 nodes,损失应该是最小的——但是王超认为当时采用的保守策略依然是有意义的,因为在弄清楚问题原因之前,直接重启 nodes 有可能反而造成更大的数据破坏。

 

3>mark shard as failed  ES事故

问题现象:

  一天,打算对 JVM 参数和 ES 配置做了小幅度的谨慎调整。

  凌晨 00:10 左右,维护者开始按照计划对 ES 集群的各个 node 依次进行重启操作,以便使新配置的参数生效(这类操作之前进行过很多次,比较熟练)。

1, 使用 http 正常的关闭接口,通知 174_0 节点进行关闭,成功。

2, 观察其余 node 的状态,几十秒后,ES 剩余的9个节点恢复了 green 状态。

3, 启动 174_0 节点。

         ——至此仅仅完成了 174_0 节点的重启工作,但紧接着就发现了问题:174_0 节点无法加入集群!

 

  此时的状态是:174_0 报告自己找不到 master,剩余9个节点的集群依然运行良好。

  于是用 jstat 查看了 174_0 的内存占用情况,发现其 ParNew 区在正常增长,所以他认为这次重启只是比往常稍慢而已,决定等待。

  但是在 00:16 左右,主节点 174_4 被踢出集群,174_3 被选举为主节点。

  之后,日志出现了 shard 损坏的情况:

  [WARN ][cluster.action.shard ] [174_node_2] sending failed shard for [goods_city_188][0], node[eVxRF1mzRc-ekLi_4GvoeA], [R], s[STARTED], reason [master [174_node_4][6s7o-Yr-QXayxeXRROnFPg][inet[/174:9354]]{rack_id=rack_e_14} marked shard as started, but shard has not been created, mark shard as failed]

  更糟的是,不但损坏的 shard 无法自动回复,而且损坏的 shard 数量越来越多,最终在将近 01:00 的时候,集群由 yellow 状态转为 red 状态,数据不再完整(此时损坏的主 shard 不到 20%,大部分城市还是可以访问的)。

 

临时解决办法:

  首先对主站做业务降级,关闭了来自前端工程的流量。

  维护者开始采用第一套方案:依次关闭所有 node,然后再依次启动所有 node。此时上面新增的 gateway 系列参数开始起作用,集群在达到 6 个 node 以上才开始自动恢复,并且在几分钟后自动恢复了所有的 shard,集群状态恢复 green。

  随后打开了前端流量,主站恢复正常。

  接着补刷了过去2小时的数据到 ES 中。

  至此,故障完全恢复。

 

经验教训:

1, 此次事故发生时,出问题的 nodes 都是老配置;而事故修复之后的所有 nodes 都是采用的新配置,所以可以确定此次问题并不是新配置导致的

2, ES 自身的集群状态管理(至少在 0.90.2 这个版本上)是有问题的——先是从正常状态逐渐变为“越来越多的 shard 损坏”,重启之后数据又完全恢复,所有shard 都没有损坏。

3, 由于是深夜且很短时间就恢复了服务,所幸影响范围较小。

4, 故障原因不明,所以随后安排 ES 从 0.90 版本升级到 1.3 版本。

 

ES 存在的问题以及改进

  Elastic Search 在窝窝运行几年来基本稳定,可靠性和可用性也比较高,但是也暴露了一些问题:

1.    ES 的更新效率,作为基于 lucene 的分布式中间件,受限于底层数据结构,所以其更新索引的效率较低,lucene 一直在优化;

2.    ES 的可靠性的前提是保证其集群的整体稳定性,但我们遇到的情况,往往是当某个节点性能不佳的情况下,可能会拖累与其同服务器上的所有节点,从而造成整个集群的不稳定。

其实解决这个问题不难,两种方法:

    增加服务器,让节点尽可能地散开;

    当某个节点出现问题的时候,需要我们及早发现处理,不至于拖累整个集群。其实监控一个节点是否正常的方法不难,ES 是基于 JVM 的服务,它出现问题,往往和 GC、和内存有关,所以只要监控其内存达到某个上限就报警即可;

3.    没有一个好的客户端可视化集群管理工具,官方或者主流的可视化管理工具,基本都是基于 ES 插件的,不符合我们的要求,所以需要一款可用的客户端可视化集群管理工具;

4.    ES 的升级问题,由于 ES 是一个快速发展的中间件系统,每一次新版本的更新,更改较大,甚至导致我们无法兼容老版本,所以 ES 升级问题是个不小的问题,再加上我们数据量较大,迁移也比较困难。

posted @ 2015-02-05 09:45  lambertzhao  阅读(245)  评论(0)    收藏  举报