人人城市出错,但一些错误是如此的谬妄,我想不通怎么会有人犯这种错误。更没想到的是,这种事竟产生在了我们身上。虽然,这种对象只有过后才气发明真相。接下来,我将报告一系列最近在我们一个应用上犯过的这种错误。最有意思的是,一开始的迹象展现的问题,与实际产生的问题完全差异。
在一个苦楚的午夜
午夜刚过,我就被一条来自监控系统的警报吵醒了。Adventory,我们的 PPC (以点击次数收费)告白系统中一个认真索引告白的应用,很明明持续重启了好屡次。在云端的情况里,实例的重启是很正常的,也不会触发报警,但这次实例重启的次数在短时间内高出了阈值。我打开了条记本电脑,一头扎进项目标日志里。
必然是网络的问题
我看随处事在毗连 ZooKeeper 时产生了数次超时。我们利用 ZooKeeper(ZK)协调多个实例间的索引操纵,并依赖它实现鲁棒性。很显然,一次 Zookeeper 失败会阻止索引操纵的继承运行,不外它应该不会导致整个系统挂掉。并且,这种环境很是稀有(这是我第一次碰着 ZK 在出产情况挂掉),我以为这个问题大概不太容易搞定。于是我把 ZooKeeper 的值班人员喊醒了,让他们看看产生了什么。
同时,我查抄了我们的设置,发明 ZooKeeper 毗连的超时时间是秒级的。很明明,ZooKeeper 全挂了,由于其他处事也在利用它,这意味着问题很是严重。我给其他几个团队发了动静,他们显然还不知道这事儿。
ZooKeeper 团队的同事回覆我了,在他看来,系统运行一切正常。由于其他用户看起来没有受到影响,我逐步意识到不是 ZooKeeper 的问题。日志里明明是网络超时,于是我把认真网络的同事唤醒了。
认真网络的团队查抄了他们的监控,没有发明任何异常。由于单个网段,甚至单个节点,都有大概和剩余的其他节点断开毗连,他们查抄了我们系统实例地址的几台呆板,没有发明异常。其间,我实验了其他几种思路,不外都行不通,我也到了本身智力的极限。时间已经很晚了(可能说很早了),同时,跟我的实验没有任何关系,重启变得不那么频繁了。由于这个处事仅仅认真数据的刷新,并不会影响到数据的可用性,我们抉择把问题放到上午再说。
必然是 GC 的问题
有时候把困难放一放,睡一觉,等脑筋清醒了再去办理是一个好主意。没人知道其时产生了什么,处事表示的很是独特。溘然间,我想到了什么。Java 处事表示独特的主要来源是什么?虽然是垃圾接纳。
为了应对今朝这种环境的产生,我们一直打印着 GC 的日志。我顿时把 GC 日志下载了下来,然后打开 Censum开始阐嫡志。我还没仔细看,就发明白一个可怕的环境:每15分钟产生一次 full GC,每次 GC 激发长达 20 秒的处事搁浅。怪不得毗连 ZooKeeper 超时了,纵然 ZooKeeper 和网络都没有问题。
这些搁浅也表明白为什么整个处事一直是死掉的,而不是超时之后只打一条错误日志。我们的处事运行在 Marathon 上,它按时查抄每个实例的康健状态,假如某个端点在一段时间内没有响应,Marathon 就重启谁人处事。
苏州软件公司 个步调" class="aligncenter size-large wp-image-29592" title="68747470733a2f2f616c6c6567726f2e746563682f696d672f61727469636c65732f323031382d30322d30392d612d636f6d6564792d6f662d6572726f72732d646562756767696e672d6a6176612d6d656d6f72792d6c65616b732f616476656e746f72792d67632d706" src="/uploads/allimg/c180831/1535A93PLM0-1F08.png" />
知道原因之后,问题就办理一半了,因此我相信这个问题很快就能办理。为了表明后头的推理,我需要说明一下 Adventory 是如何事情的,它不像你们那种尺度的微处事。
Adventory 是用来把我们的告白索引到 ElasticSearch (ES) 的。这需要两个步调。第一步是获取所需的数据。到今朝为止,这个处事从其他几个系统中吸收通过 Hermes 发来的事件。数据生存到 MongoDB 集群中。数据量最多每秒几百个请求,每个操纵都出格轻量,因此即便触发一些内存的接纳,也淹灭不了几多资源。第二步就是数据的索引。这个操纵按时执行(或许两分钟执行一次),把所有 MongoDB 集群存储的数据通过 RxJava 收集到一个流中,组合为非范式的记录,发送给 ElasticSearch。这部门操纵雷同离线的批处理惩罚任务,而不是一个处事。
由于常常需要对数据做大量的更新,维护索引就不太值得,所以每执行一次按时任务,整个索引城市重建一次。这意味着一整块数据都要颠末这个系统,从而激发大量的内存接纳。尽量利用了流的方法,我们也被迫把堆加到了 12 GB 这么大。由于堆是如此庞大(并且今朝被全力支持),我们的 GC 选择了 G1。