关于Memcached的CAS和Set方法造成Socket泄漏的问题
为了解决多并发下写Memcached的冲突方案,我们项目组引入了CAS机制,类同于Java并发包中的CAS(Compareand set)原子操作,用来处理同一个Item被多个线程更改的并发问题。Memcached的CAS是原理是引入版本号概念,每个存储数据对象都有一个64bit长度的数值作为该key对应value的版本号。具体使用代码如下:
// 此方法不同于get方法 获取MemcachedItem对象 MemcachedItem item = mc.gets(key); mc.cas(key, item.getValue() + String.valueOf(sleep), item.getCasUnique());
在项目中对于单线程的场景,我们就使用了Memcached的Set方法。但是在项目耐久性测试过程中,我们发现网站后台管理服务器的Weblogic进程的句柄数在不断的增加,在Weblogic进行安全备份时,触发了一错误,并造成后续的线程都Too many open files了。相关错误信息如下:
<2015-5-30 下午11时05分16秒 CST> <Critical> <EmbeddedLDAP> <BEA-000000> <java.io.FileNotFoundException: /weblogic/Oracle/Middleware/user_projects/domains/shch_domain1/servers/shchbdf1/data/ldap/backup/EmbeddedLDAPBackup.zip (Too many open files) at java.io.FileOutputStream.open(Native Method) at java.io.FileOutputStream.<init>(FileOutputStream.java:194) at java.io.FileOutputStream.<init>(FileOutputStream.java:84) at com.octetstring.vde.backend.standard.BackupTask.runTask(BackupTask.java:55)
我们通过命令检查了未关闭的句柄,具体未关闭的句柄如下,我们知道socke通讯中can’t identify protocol是由于服务器异常中断socket通讯后,并未通知客户端,造成的客户端句柄不释放。
我们知道应用和Memcached直接的通讯是使用NIO的Socket通讯,socket是连接是会产生句柄数的,但是正常关闭通道,句柄是会释放的,除非socket通道被非正常关闭。从这个角度出发,我们对项目代码和异常场景进行了梳理。首先,只有后台管理的进程会产生句柄数增加,而前台的集群报价系统多台服务器上都未发生这种情况。分析后台管理代码,有一个定时任务去定时更新Memcached的值,因为是单线程,使用的是Set方法。但是这个set方法和报价的CAS方法都是对通过值进行修改,根据直觉判断是set方法和CAS方法在同时对一个值进行修改时,如果正好同时触发了,set方法的修改不成功,Memcached自动断开set值得连接,而未通知客户端,造成socket泄漏。我们把Memcached的Set方法修改成CAS后,问题解决。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。