elasticsearch发生脑裂时JAVA客户端的行为
来自: https://segmentfault.com/a/1190000004513147
这篇文章的原文地址是 http://blog.trifork.com/2013/10/31/java-clients-behavior-during-creating-a-split-brain-situation-in-elasticsearch/ ,发布于2013年10月
之前的博文解释了 如何避免elasticsearch的脑裂问题 ,但只是大概讲了它是怎么发生的。这次我会详细讲解下脑裂发生时索引和查询请求会怎么样。我想你已经知道了,这要看情况!这取决于你用的是什么类型的客户端。因为我熟悉Java,所以我会用elasticsearch支持的Java API写两种类型的客户端: transport客户端和node客户端。
模拟脑裂问题
首先我们先用Oracle的VirtualBox起两个跑Ubuntu 13.10的虚拟机。使用网络设置的“Bridged Adapter”模式,我很快的启动了一个“虚拟”的elasticsearch集群。
在建立了一个独立分片,一个独立复制索引后,我写了两个Java小程序用两个独立线程(一个索引一个查询)不断地索引文档和从新生成的索引进行查询。
为了模拟脑裂我给iptables加了一个rule,阻塞两个机器间的通讯:
iptables -A INPUT -s 192.168.0.1 -j DROP iptables -A OUTPUT -d 192.168.0.1 -j DROP
在索引了大约200个文档后我执行了以上命令。我同样的测试做了两次,一次使用 transport客户端 一次使用 node客户端 。 所有的测试用的是0.90.5版本的elasticsearch(发文时的最新版)
transport客户端的测试
不出意料(transport客户端是对集群无感知的),将两个节点间的通信阻塞并没有对索引和查询产生错误。当我执行iptables exclusion后,elasticsearch用了差不多一分钟来决定对方已经无响应了。在这期间,transport客户端暂停了所有的排序和查询。我给代码里设置了无超时,所以所有的请求都在静静的等待elasticsearch返回一个可用的集群。跟预期一样,每个节点都选举自己为主所以现在每个节点都有一份索引的独立拷贝。
索引和查询请求随机的请求到每个节点。运行期间每个索引请求并没有报告两份索引分开了。 没有观察到任何失败和警告 - 以客户端的视角整个测试期间一切都很正常。
node客户端的测试
因为node客户端在elasticsearch集群中创建了一个节点(node), 我期望这次测试与transport客户端的那次结果会不一样。 在执行了iptables命令后, 索引请求完全暂停了, 但查询请求仍然在运行,以round robin的形式在两个节点间发生。 请求返回了不同的结果,在我切断了两个分片间的通信时复制分片与主分片失去了同步。
当两个节点决定对方已经失效了, node客户端随机的选了其中一个座位新的集群主节点。从那时起,所有的索引和查询请求都指向了这个新的主节点。一样的,在测试期间没有观测到任何失败,但node客户端报告了它切换了主节点(INFO级别的日志)。
由于node客户端在发生了脑裂后只指向了一个节点,所以两份索引的拷贝并没有分裂,但是只有其中一个是最新的。我相信这是node客户端相对于transport客户端的一个优点。
那么集群重启呢?
当脑裂发生后,唯一的修复办法是解决这个问题并重启集群。 这儿有点复杂和可怕。 当elasticsearch集群启动时,会选出一个主节点(一般是启动的第一个节点被选为主)。由于索引的两份拷贝已经不一样了,elasticsearch会认为选出来的主保留的分片是“主拷贝”并将这份拷贝推送给集群中的其他节点。这很严重。让我们设想下你是用的是node客户端并且一个节点保留了索引中的正确数据。但如果是另外的一个节点先启动并被选为主,它会将一份过期的索引数据推送给另一个节点,覆盖它,导致丢失了有效数据。
结论
所以怎么从脑裂中恢复?第一个建议是给所有重索引的数据做备份。第二,如果脑裂发生了,要十分小心的重启你的集群。停掉所有节点并决定哪一个节点第一个启动。 如果需要,单独启动每个节点并分析它保存的数据。如果不是有效的,关掉它,并删除它数据目录的内容(删前先做个备份)。如果你找到了你想要保存数据的节点,启动它并且检查日志确保它被选为主节点。这之后你可以安全的启动你集群里的其他节点了。
文章来自微信平台「麦芽面包」
微信公众号「darkjune_think」
转载请注明。
如果觉得文章有趣,微信扫二维码关注我