Hi all,
Greg's java client is great, but when it comes to a multi-threading and
situation of high stress environment in my server program,there are some
performance issues. The most obvious one is lock contention in SockIOPool
when there are many threads. The host spots are mainly following functions:
(1) SockIOPool.getInstance()
(2) SockIOPool.getConnection()
(3) SockIOPool.checkIn()
Looking through the source code, we know that every get/set/delete and other
operation will first get an object instance of SockIOPool by invoking
(1)SockIOPool.getInstance() which is a synchronized function. Then get a
SockIO from the pool by invoking (2)SockIOPool.getConnection(), and then
invoke (3)SockIOPool.checkIn() to return the SockIO to the pool.
Unfortunately, both (2) and (3) are synchronized inside. These three
functions will cause big performance problem when there are more then 16
threads.
To avoid lock contention of the synchronized function listed above, I have
following proposal:
Firstly, to avoid lock contention of case (1), we can keep a reference of
the SockIOPool object in the MemCacheClient. This modification has no side
affect of current source code, so I have submitted a patch to Greg, also the
patch is attached in this mail.
Secondly,to avoid lock contention of case (2) and (3), I think we can use
the same idea by keeping a reference of recently used SockIO object in
MemCacheClient. But this modification is a bit complicated since we have to
know when to release the SockIO. I have two schemes of implementing this
idea.
First one is to provide an additional method in MemCacheClient to allow
user release the SockIO acquired by MemCacheClient manually. This
implementation only needs small modification to current source code, but may
cause modification of user's code.
Second one is to modify the SockIOPool to retrieved not recently used
SockIO from MemCacheClient.This implementation will lead to bigger
modification to current source code.
I am still working on this. Any comments or suggestions are welcome.
--
best regards
Jiazi Yu
--- memcache_java/src/com/danga/MemCached/MemCachedClient.java 2007-08-07
17:09:17.000000000 +0800
+++ popo6/devel/server/Common/src/com/danga/MemCached/MemCachedClient.java
2007-08-07 16:51:24.000000000 +0800
@@ -199,11 +199,15 @@
// which pool to use
private String poolName;
+ // pool instance
+ private SockIOPool poolInstance = null;
+
// optional passed in classloader
private ClassLoader classLoader;
// optional error handler
private ErrorHandler errorHandler;
+
/**
* Creates a new instance of MemCachedClient.
@@ -249,6 +253,7 @@
this.compressThreshold = COMPRESS_THRESH;
this.defaultEncoding = "UTF-8";
this.poolName = "default";
+ this.poolInstance = SockIOPool.getInstance(this.poolName);
}
/**
@@ -278,6 +283,7 @@
*/
public void setPoolName( String poolName ) {
this.poolName = poolName;
+ this.poolInstance = SockIOPool.getInstance(poolName);
}
/**
@@ -405,7 +411,7 @@
}
// get SockIO obj from hash or from key
- SockIOPool.SockIO sock = SockIOPool.getInstance( poolName
).getSock( key, hashCode );
+ SockIOPool.SockIO sock = poolInstance.getSock( key, hashCode );
// return false if unable to get SockIO obj
if ( sock == null )
@@ -656,7 +662,7 @@
}
// get SockIO obj
- SockIOPool.SockIO sock = SockIOPool.getInstance( poolName
).getSock( key, hashCode );
+ SockIOPool.SockIO sock = poolInstance.getSock( key, hashCode );
if ( sock == null )
return false;
@@ -1076,7 +1082,7 @@
}
// get SockIO obj for given cache key
- SockIOPool.SockIO sock = SockIOPool.getInstance( poolName
).getSock(key, hashCode);
+ SockIOPool.SockIO sock = poolInstance.getSock(key, hashCode);
if ( sock == null )
return -1;
@@ -1208,7 +1214,7 @@
}
// get SockIO obj using cache key
- SockIOPool.SockIO sock = SockIOPool.getInstance( poolName
).getSock( key, hashCode );
+ SockIOPool.SockIO sock = poolInstance.getSock( key, hashCode );
if ( sock == null )
return null;
@@ -1393,7 +1399,7 @@
}
// get SockIO obj from cache key
- SockIOPool.SockIO sock = SockIOPool.getInstance(
poolName ).getSock( key, hash );
+ SockIOPool.SockIO sock = poolInstance.getSock( key,
hash );
if ( sock == null )
continue;
@@ -1462,8 +1468,7 @@
for ( Iterator<String> i = cmdMap.keySet().iterator();
i.hasNext(); ) {
String host = i.next();
- SockIOPool.SockIO sock =
- SockIOPool.getInstance( poolName
).getConnection( host );
+ SockIOPool.SockIO sock = poolInstance.getConnection(
host );
try {
// get a selector
@@ -1839,7 +1844,7 @@
public boolean flushAll( String[] servers ) {
// get SockIOPool instance
- SockIOPool pool = SockIOPool.getInstance( poolName );
+ SockIOPool pool = poolInstance;
// return false if unable to get SockIO obj
if ( pool == null ) {
@@ -2028,7 +2033,7 @@
}
// get SockIOPool instance
- SockIOPool pool = SockIOPool.getInstance( poolName );
+ SockIOPool pool = poolInstance;
// return false if unable to get SockIO obj
if ( pool == null ) {