转于自己在公司的Blog:
http://pt.alibaba-inc.com/wp/experience_766/danga_memcached_nio_leak.html
某次,服务器出现故障,分析日志:
最先开始的是danga.memcached报"too many open files",句柄数达到上限(ulimit上限已经是加大的),
导致danga.memcached无法创建新的套接字,连接缓存服务器失败,
紧接着压力全部转移到数据库,数据库连接池用完,很快就撑不住,
因为数据库响应慢,线程占用率变高,接收请求的线程池也达到上限,很多请求被拒绝,
页面出现时而可以访问,时而访问不了,重启后恢复正常,
lsof查看Java进程持有的句柄,大部分为pipe和event poll,
初步判断是danga.memcached中使用的nio管道未正确关闭。
为了进一步了解问题,分析源码:
首先来看danga是怎么获取套接字的:
SocketIO.getSocket()
SocketChannel sock = SocketChannel.open();
sock.socket().connect( new InetSocketAddress( host, port ), timeout );
return sock.socket(); // 直接拿到Socket使用,把SocketChannel的引用丢了,并且没有注册Selector
再来看应用调用API发生了什么:
MemCachedClient.get()
// 省略了不相关代码
sock.write( cmd.getBytes() );
String line = sock.readLine();
内部调用关系等价于:
// sock.write( cmd.getBytes() ); 等价于
out = new BufferedOutputStream( sock.getOutputStream() ); // 把nio当bio用
out.write( b );
// String line = sock.readLine(); 等价于
in = new DataInputStream( sock.getInputStream() ); // 把nio当bio用
in.read( b );
再看看它是怎么关闭的:
SockIO.trueClose()
// 省略了不相关代码
in.close();
out.close();
sock.close(); // Soket内部会同时关闭Channel,但不会关闭Selector
这种把非阻塞式管道当作阻塞式套接字用法,我们来看看SunJDK是怎么处理的:
SocketChannelImpl.socket().connect()最终调用的是:
SocketAdaptor.connect()
// 省略了部分代码
sel = Util.getTemporarySelector(sc); // 当没有注册Selector时,JDK会获取一个临时Selector
sk = sc.register(sel, SelectionKey.OP_CONNECT);
再看看Util.getTemporarySelector()怎么实现的:
// 省略了部分代码
private static ThreadLocal localSelector = new ThreadLocal(); // 放在ThreadLocal中缓存
SoftReference ref = (SoftReference)localSelector.get(); // 并使用了软引用
sel = sc.provider().openSelector();
localSelector.set(new SoftReference(new SelectorWrapper(sel)));
return sel;
通过上面的代码,基本结论是:
danga.memcached2.0.1使用nio非阻塞式管道,
但却把非阻塞式管道当作阻塞式套接字用,没有注册Selector,
JDK会注册一个临时的Selector,使用Soft引用,并使用ThreadLocal做缓存,
当线程池剧烈收缩和扩张时,就会出现很多垃圾Soft引用的Selector,
如果内存够用,这些Soft引用都不会释放,句柄数就有可能达到上限。
而danga.memcached1.6.0使用的是常规阻塞式套接字,性能稍慢,但资源管理都比较正确,
降级使用1.6.0版本后,服务器恢复正常,
但1.6.0版本存在memcached服务器重启后,客户端无法自动恢复连接的问题,需将连接超时设置足够短(50ms以内)。
另外,将接收请求的线程池最大值和最小值设为一样,固定大小,避免收缩。
分享到:
相关推荐
**标题:“danga memcached使用”** memcached是一款高性能、分布式内存对象缓存系统,它广泛应用于Web应用中,用于减轻数据库的负载,通过在内存中缓存数据和对象来减少读取数据库的次数。Danga是memcached的原始...
Memcache java jar 包 java_memcached-release_2.5.1.jar import com.danga.MemCached.MemCachedClient; import net.spy.memcached.MemcachedClient;
2. **缓存操作**:通过简单的API,开发者可以设置、获取、删除或检查缓存在Memcached中的键值对。这些操作通常都是原子性的,确保了数据的一致性。 3. **序列化与反序列化**:Java Memcached客户端库通常会处理对象...
memcached在JAVA中调用的DEMO,直接导入项目,无需新建工程。前提是必须按安装memcached,并启动memcached server服务
使用memcached 方法 package com.war.common.util; import com.danga.MemCached.*; import java.util.Date; public class MemCached { protected static MemCachedClient mcc; protected static Logger log; ...
【Memcached 使用说明】 Memcached 是一套由 danga.com(LiveJournal 技术团队)开发的分布式内存对象缓存系统,旨在减少数据库负载并提升应用性能。它通过将数据存储在内存中,使得高并发环境下的数据访问更为快速...
java-memcached-2.6.6.jar
Memcached由Danga Interactive公司开发,最初服务于LiveJournal,现在已经成为一种开源、高性能、分布式的内存对象缓存系统。它的工作原理是将数据存储在内存中,避免了频繁读取硬盘带来的I/O延迟,从而提高了数据...
在IT领域,尤其是在JavaWeb开发中,Memcached作为一种高性能、分布式的内存对象缓存系统,被广泛用于加速动态网络应用的加载速度。本文将详细解析如何在Java项目中使用Memcached,包括其配置方法以及一个具体的示例...
当检测到特定的查询操作时,可以先尝试从Memcached中获取数据,如果不存在则从数据库查询并存入缓存。这种方式可以显著提高查询速度,尤其是在高并发场景下。 **总结** Memcached作为一个高效的分布式缓存系统,...
com.danga package 下的 memcached.jar
在Java开发中,有三种主流的Memcached客户端库供开发者选择:官方的基于传统阻塞IO的客户端、Dustin Sallings实现的基于Java NIO的Spymemcached以及XMemcached。 1. **官方客户端** 官方提供的客户端是由Greg ...
最近一直在做一个项目的前期设计工作,考虑到后期系统的扩展和性能问题也找了很多解决方法,有一个就是用到了数据库的缓存工具memcached(当然该工具并不仅仅局限于数据库的缓存)。先简单的介绍下什么是memcached。...
library, 一个与Memcached缓存系统接口的CodeIgniter库 用于CodeIgniter的#Memcached 库##Description这个库是为了帮助一个基于CodeIgniter的项目与 1或者更多的Memcached服务器( http://www.danga.com/memcached
memcached是由Danga Interactive开发的一个开源项目,旨在提高动态Web应用的性能。它是一个基于内存的键值存储系统,用于临时存储(非持久化)中小规模的数据,如网页内容、数据库查询结果等。memcached通过在服务器...