天天看点

Elasticsearch经验之-GitHub故障处理近期代码检索中断(2013-2-4)         

近期代码检索中断(2013-2-4)         

上周(1月24 周三到1月25周五),在我新建的代码检索服务上发生了一起严重的断电事故。像往常一样,我们努力提供这起事故详尽透明的事后剖析。我们将尽力解释事故发生的原因和怎么样减少这些问题以防止类似的事故再次发生。 首先,我代表GitHub为这起事故向大家道歉。尽管它没有影响到除了代码检索之外的其他服务,但这起事故的严重性和停机时间对我们来说是完全不能能接受的。对这起事故,我们感到非常的抱歉,尤其在我们为该新功能的推出工作了很长一段时间后,故障还是很快发生了。

背景

         我们之前检索采用的技术叫作Solr,为了推出新的更好的检索服务,我们最终完成将GitHub上所有的搜索结果迁移到构建在Elasticsearch上新的检索集群上。因为代码检索索引的非常的大,所以我们使用一个集群专门储存索引。当前的集群是由26个存储节点和8 client节点组成。存储节点负责存放进过压缩过的索引的数据,而client节点负责查询活动的协调工作。每一个存储节点有2TB的SSD存储。这次停机的时候,我们在集群大概存储了17TB的代码。数据被分片存放在集群中,每一个分片在其他节点上都有一个副本用于冗余备份,最终实际使用大概34T的存储空间。这样一来,集群存储空间的利用率在67%左右。代码检索集群使用java6和Elasticsearch 0.19.9的版本,在我们将所有的代码创建了索引之后已经运行了数月,中途没有出现过什么问题。 在1月17日周三,我准备推出我们全新的、统一检索实现的代码检索服务。在这执之前,我们注意到elasticsearch 0.20.2已发布包含的补丁的版本并有一些性能提升。  为了升级将我们的Elasticsearch版本从0.19.9升级到0.20.2,我们决定推迟代码检索服务的上线,并在推出之前为了确保顺利启动,我们将公开发布。   在1月17 周三我们完成了成功升级,集群中的所有节点都成功启动并恢复集群状态。

错在哪里

因为这次升级,代码检索集群经历两次停机。

像其他的检索服务使用单个巨大的索引存储数据,Elasticsearch使用分片模式将数据进行分割,所以数据很容易分散的存放在集群中可管理的块当中。每一个分片他本身就是一个Lucene索引,Elasticsearch将分散在分片上的索引查询进行聚集。

第一次停机发生在升级后的大概两小时内,恢复过程中,作为集群的一部分重新启动。我们从所以日志找到错误信息,错误信息指出一些分片不能分配或不能分配到特定的节点上。经过进一步检查,我们发现一些数据分片上的段的缓存文件被损坏,其他的也丢失了。Elasticsearch能使用损坏的段缓存文件恢复分片,而且只是副本中的一个分片丢失,但7个分片的主和备分片都丢失了。

         我们回顾了停机的情况,并断定故障的问题你源于集群恢复期间的高负载。我们对于给问题的调查不能说明其他Elasticsearch用户碰到此类问题。在周末集群运行正常,因此我们决定将遇到的情况公之于众。

         第二次停机发生在1月24日,我们首先注意到我们的异常跟踪和监控系统检测到有大量的异常问题。进一步检查出这些异常主要来源于代码检索的超时和后台代码检索索引的更新任务。

         当时,我们开始检查集群中所有成员的状态和Elasticsearch的日志。我们能识别看似随机的存储节点上超大的负载。虽然大多数节点cpu的使用百分比是个位数,但几个节点达到将近100%。我们能排系统负载和IO负载是可能的罪魁或者,唯一造成巨大负载的服务器是运行Elasticsearch的java进程。随着检索和索引超时任然发生,我在日志里面查看到有若干个节点很快地被选举并且随后在集群中移除主节点角色身份。为了减少集群中主节点的快速交换的问题,我们决定最好的方案是完全停止集群并且把它调成维护模式,那样讲禁止分配和分配的重新分配。

         这样我们能使集群恢复运行,但我们仍然在Elasticsearch日志中看到若干报错。

恢复

         在我们集群重启后,我们注意到一节点完全不能重新加入到集群中,并且一些数据分片正视图在相同节点上进行双重备份。这时,我们得到了开发和支持Elasticsearch的两位Shay和Drew的支持。

         我们与Shay和Drew能确信为分配的分片(23主+副本)数据全部已经丢失。除数据丢失外,集群花费了大量时间视图恢复剩下的分片。在恢复的过程中,我们不得不重启集群几次,源于我们要回滚之前的升级和配置的改变,这将导致再次验证和分片重新分配。最终,这也成为最好耗时的部分,因为加载多次17TB的磁盘的索引数据是一个漫长的过程。

         在Shay和Drew的帮助下,我们发现我们集群在一些地方进行了错误的配置或者要达到最优性能需要一些配置调优。他们也查出Elasticsearch本身的两个bug。最后,我们运行在2009年发布的java 6版本上。这包含多个严重的bug,大内存分配导致的问题对Elasticsearch和Lucene都有影响。

         根据他们的建议,我们立即推出升级java和Elasticsearch,并升级了他们推荐的配置。…

         虽然这些检查增加了几个小时的停机时间,但我们认为时间是花在Elasticsearch开发的专家的反馈上的。

         在升级了配置,使用bug修复版本的Elasticsearch和高性能的java7,到目前为止,我们没有再碰到前两次停机中的古怪负载和快速主节点交换的问题。

周一的停机

         代码检索集群遭受的另外一次停机发生在1月28日、周一。这次停机和之前的事故是无关的,源于人工的错误。

         一个工程师将包含在Java和Elasticsearch分支的特性合并升级到了产品环境。在这个过程中,工程师在部署合并代码之前将Puppet环境切换回产品环境。这导致Elasticsearch节点上的Elasticsearch重新启动,因为Puppet运行在他们上面。我们立即查出问题的根源并停止集群以防在同一个集群中运行多个版本的java和Elasticsearch引起其他问题。部署完合并的代码之后,我们在所有的代码检索节点运行Puppet,然后恢复集群。我们没有在集群处于降级状态提供代码检索和查询服务,而是选择集群全部恢复之后。

减少问题发生

我们没有在升级时充分测试Elasticsearch0.20.2发布版本,也没有提前测试其他集群。

一个原因是我们缺少合适用于代码检索集群测试的演示环境。…

         Elasticsearch0.20.3上bug的修复,让我相信,我们再也不会碰到他们引起的问题了。我们也运行了Elasticsearch团队测试过的java版本,这个版本将能更稳定更好性能的运行Elasticsearch。另外,我们的代码检索集群配置已经让Elasticsearch团队进行审查,未来的审查计划将确保我们的使用案例配置是最优的。

         至于周一的停机,我们正计划让Puppet自动的运行在特定的环境,这种情况下GitHub的主干不可能运行在Puppetmaster的环境之前。

         最后,我想去分享几个Elasticsearch团队关于我们配置的几个提的注意事项, 希望帮助运行大集群的其他人。

1、设置ES_HEAP_SIZE环境变量以致JVM使用相同的最大最小堆内存。配置JVM使用不同的最小堆和最大堆意味着每次JVM需要额外的内存(大于最小堆)将要阻塞Java进程去给他分配。加上旧的Java版本,这就解释了当公开搜索时引进的高负载和持续的内存分配造成暂停。Elasticsearch团队推荐配置为系统RAM的50%大小。
2、我们集群将recover_after_time配置30分钟,Elasticsearch团队建议改变,让恢复立即执行而不是等到一段时间后。
3、我们没有配置minimum_master_nodes ,所以当节点经历长时间的暂停,一部分节点将视图组成他们的集群时,集群变的不稳定。
4、在开始恢复期间,一些节点耗尽磁盘空间,发生这种情况的原因还不清楚,因为在初始化之前集群的磁盘使用率是67%,但能相信是和高负载和就的java版本有关。elasticsearch团队也继续调查了解具体的情形。
           

总结

         我们非常抱歉在新版代码检索功能推出时发生不可用问题。那还没有达到我们的标准,我们将接受每一次停机的经验教训,我们将能做的更好。谢谢对我们的支持,尤其在这样的艰难时期。

说明:本人水平有限,翻译未免出现错误,请批评指教。

【原文】https://github.com/blog/1397-recent-code-search-outages

继续阅读