`

关于RPC事务过载保护

阅读更多
最近系统出现一个问题,少量Proxy出现故障,群组消息应用服务器会出现内存资源不够导致的崩溃的情况。我们对每个worker做了过载的保护,并且对每个worker的内存使用做了限制。从抓下来的dump来看,内存中的sipc对象占用了过多内存导致的崩溃。sipc请求对象在内存中的数量远远超过设置的数量,说明过载没有起到作用。

现场描述:
群消息服务器会访问多台Proxy给同的用户下行消息。
坏了两台proxy。
群组消息应用worker与zookeeper断掉连接,没有任何请求过来从proxy过来。内存占用设定的2.4G,每颗cpu在20%左右,正常地对进程抓dump抓不下来,得加-F参数。kill进程的操作,需要一段时间后,进程才会消失。


事故原因分析:
SipcHost在做过载保护的机制是这样的:
Sipc请求进来的时候,计数器加1,Sipc应答的时候,计数器减1;
计数器如果到达阈值,对于新请求,直接返回server busy;

但是目前上线的很多应答无内容的应用为了快速响应客户端的请求,都是直接发送应答之后再开始做业务逻辑,群消息就是个典型的例子,先给客户端reponse,再做群消息的分发。

SipcHost的线程池使用的是 java.util.concurrent.Executors.newFixedThreadPool(int nThreads),而这个线程池使用的是无容量限制的LinkedBlockingQueue。

基于以上三点,群消息在做消息分发的时候由于proxy的问题RPC消息发不下去,进入RPC重试机制;由于群消息快速reponse了,所以群消息的Sipc计数器一直为一个比较小的值,群消息的请求一直会进入到SipcHost的Queue中,最终导致内存被使用完毕,所有的线程被hang死。



经验总结:
尽量不要使用计数器做过载保护,因为计数器由于应用多使用异步的原因,不能准确判断事务是否完成,只能根据应用的response来计数,不是很准确。建议使用有一定容量的queue的线程池,queue满了直接报busy来做过载保护。
0
4
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics