庄周梦蝶

生活、程序、未来
   :: 首页 ::  ::  :: 聚合  :: 管理

Xmemcached的FAQ和性能调整建议

Posted on 2010-07-08 18:37 dennis 阅读(20401) 评论(35)  编辑  收藏 所属分类: javamy open-source
    一些常见的关于xmemcached的问题,收集整理,集中解答在此。事实上这里的大部分问题都可以在用户指南里找到。

一、XMemcached是什么?
经常碰到的一个问题是很多朋友对memcached不了解,误以为xmemcached本身是一个缓存系统。Memcached是一个开源的,C写的分布式key-value缓存,XMemcached只是它的一个访问客户端。Memcached通过网络协议跟客户端交互,通过客户端你才可以去使用memcached,xmemcached是它的java客户端之一。

二、为什么要选择xmemcached?

memcached的java客户端有多个选择,为什么要选择xmemcached?理由如下:

1、支持所有的文本协议和二进制协议,支持连接KestrelTokyoTyrant等memcached协议兼容的系统并作特殊处理。
2、支持动态添加和删除memcached节点。
3、支持客户端统计
4、支持JMX监控和统计,可以通过JMX增删节点。
5、高性能
6、支持节点的权重设置
7、支持nio的连接池,在高负载环境下提高吞吐量。

三、对jdk版本有什么要求?

Xmemcached仅支持jdk1.5及以上版本。

四、使用的时候需要创建多个MemcachedClient对象吗?MemcachedClient是不是线程安全?

MemcachedClient是线程安全的,由于xmemcached的网络层实现是基于nio长连接的,因此你并不需要重复创建多个MemcachedClient对象,通常来说将MemcachedClient设置为全局的唯一单例的服务使用,如果是使用spring配置,那更是简单,在spring配置文件里配置一个MemcachedClient,其他对象引用即可使用。

五、为什么会抛出java.util.TimeoutException?

这是由于xmemcached的通讯层是基于非阻塞IO的,那么在请求发送给memcached之后,需要等待应答的到来,这个等待时间默认是1秒,如果超过1秒就抛出java.util.TimeoutExpcetion给用户。如果你频繁抛出此异常,可以尝试将全局的等待时间设置长一些,如我在压测中设置为5秒:
MemcachedClient  memcachedClient=……
memcachedClient.setOpTimeout(
5000L);

请注意,setOpTimeout设置的是全局的等待时间,如果你仅仅是希望将get或者set等操作的超时延长一点,那么可以通过这些方法的重载方法来使用:
<T> T get(java.lang.String key,long timeout)

boolean set(java.lang.String key, int exp,java.lang.Object value,
            
long timeout)

……


六、Kestrel和TokyoTyrant不支持flag字段,xmemcached是怎么解决的?

Xmemcached在存储的value前面自动加上和去除4个字节的flag,这一切对应用来说是透明的。具体请看用户指南。


七、连接memcacheq,取出来的消息比放进去的多?


这是由于memcacheq和kestrel一样,不支持multi get协议,因此只要关闭xmemcached的multi get优化就可以了。

memcachedClient.setOptimizeGet(false);

所谓multi get优化是指xmemcached会将连续的单个get请求合并成一个multi get请求作批量获取,提高效率。

八、连接kestrel,为什么过一段时间会自动断开并重连?

你可能使用的是kestrel 1.2以下版本,kestrel 1.2才支持version协议,xmemcached是基于version协议做心跳检测,因此当使用kestrel 1.2以下版本的时候会发生心跳检测失败并断开连接重连的情况,你可以升级kestrel,也可以关闭心跳检测:

memcachedClient.setEnableHeartBeat(false);

九、我使用maven,怎么引用xmemcached?

xmemcached 1.2.5已经加入了maven的中心仓库,因此你可以直接引用
  <dependency>
      
<groupId>com.googlecode.xmemcached</groupId>
      
<artifactId>xmemcached</artifactId>
      
<version>1.2.5</version>
 
</dependency>

如果是之前版本,我推荐你升级,或者自己手工加入私人的maven仓库。

十、连接池是怎么回事?设置多大为好?

在高负载环境下,nio的单连接也会遇到瓶颈,此时你可以通过设置连接池来让更多的连接分担memcached的请求负载,从而提高系统的吞吐量。设置连接池通过
MemcachedClientBuilder builder = new    XMemcachedClientBuilder(AddrUtil.getAddresses("localhost:12000"));

builder.setConnectionPoolSize(
5);
MemcachedClient client
=builder.build();

或者通过spring配置也可以。

连接池通常不建议设置太大,我推荐在0-30之间为好,太大则浪费系统资源,太小无法达到分担负载的目的。

十一、性能建议及优化手段

    性能的调整只能给出一般性的原则,实际情况千差万别,每次调整都需要做实际的测量才能确定是否带来期望的效果。

1、如果你的数据较小,如在1K以下,默认的配置选项已经足够。如果你的数据较大,我会推荐你调整网络层的TCP选项,如设置socket的接收和发送缓冲区更大,启用Nagle算法等等:   
            MemcachedClientBuilder builder = new XMemcachedClientBuilder(
                    AddrUtil.getAddresses(servers));
            builder.setSocketOption(StandardSocketOption.SO_RCVBUF, 
32 * 1024); // 设置接收缓存区为32K,默认16K
            builder.setSocketOption(StandardSocketOption.SO_SNDBUF, 16 * 1024); // 设置发送缓冲区为16K,默认为8K
            builder.setSocketOption(StandardSocketOption.TCP_NODELAY, false); // 启用nagle算法,提高吞吐量,默认关闭

默认如果连接超过5秒没有任何IO操作发生即认为空闲并发起心跳检测,你可以调长这个时间: 
  builder.getConfiguration().setSessionIdleTimeout(10000);  // 设置为10秒;

更多网络层配置选项请参见Configuration类。

2、Xmemcached默认会做两个优化:将连续的单个get合并成一个multi get批量操作获取,将连续的请求合并成socket发送缓冲区大小的buffer发送。
如果你对响应时间比较在意,那么可以将合并的因子减小,或者关闭合并buffer的优化:
    memcachedClient.setMergeFactor(50);   //默认是150,缩小到50
    memcachedClient.setOptimizeMergeBuffer(false);  //关闭合并buffer的优化

如果你对吞吐量更在意,那么也可将合并因子调大,默认是150。但是也不可太大,太大可能导致平均响应时间延长。

3、如果你对心跳检测不在意,也可以关闭心跳检测,减小系统开销
memcachedClient.setEnableHeartBeat(false);
这个关闭,仅仅是关闭了心跳的功能,客户端仍然会去统计连接是否空闲,禁止统计可以通过:
builder.getConfiguration().setStatisticsServer(false);






评论

# re: Xmemcached的FAQ和性能调整建议  回复  更多评论   

2010-07-09 08:34 by smxly53
感谢指导

# re: Xmemcached的FAQ和性能调整建议  回复  更多评论   

2010-08-17 18:53 by AlexJ
五、为什么会抛出java.util.TimeoutException?
这个和Memcached服务端版本有关系,用最新的服务端就没有这个问题,用1.4之前的Memcached版本会出现此问题,而且这个异常抛出来相当的不优雅~

# re: Xmemcached的FAQ和性能调整建议  回复  更多评论   

2010-08-25 23:32 by Santal Li
非常好的项目,楼主实力很强。
有个问题想问一下:
>builder.setSocketOption(StandardSocketOption.TCP_NODELAY, false); // 启用nagle算法,提高吞吐量,默认关闭
刚看的资料,Set TCP_NODELAY = false确实可以启用Nagle算法,而 Nagle算法可以合并多个小的TCP包为一个大包,以减少需要传输的总的小包量,可是好像所有的TCP Stack的实现都把TCP_NODELAY缺省的设置为True了呀,为什么要再设置一次呢?

# re: Xmemcached的FAQ和性能调整建议  回复  更多评论   

2010-08-26 09:26 by dennis
@Santal Li
默认的TCP选项,都是启用nagle算法,也就是默认是false。
xmemcached默认却是禁止nagle算法,这是为了降低响应时间,特别是在数据比较小的情况下。

# re: Xmemcached的FAQ和性能调整建议  回复  更多评论   

2010-09-15 10:50 by leixiangjian
搂主,你好!
我使用memcached版本是1.4.5,服务器开了3个节点
ip:192.168.166.156:11211
ip:192.168.166.156:11212
ip:192.168.166.156:11213

客户端使用xmemcached

情况如下:
当一个node失去,则会调用
MemcachedConnector.removeSession()方法、还会调用定位器的updateSessions()方法,当我在MemcachedHandler.onSessionClosed方法中获得相应的client后,在利用client的get方法对某个节点上的数据进行操作时,总是抛出如下异常:
java.util.concurrent.TimeoutException: Timed out(5000) waiting for operation

为什么???

# re: Xmemcached的FAQ和性能调整建议  回复  更多评论   

2010-09-15 11:05 by denniis
@leixiangjian
连接断开了,你再往这个连接发送命令是没用的,当然会超时。

# re: Xmemcached的FAQ和性能调整建议  回复  更多评论   

2010-09-15 11:13 by leixiangjian
比如:断开的node是192.168.166.156:11212
我的get的node是192.168.166.156:11211

# re: Xmemcached的FAQ和性能调整建议  回复  更多评论   

2010-09-15 11:16 by leixiangjian
虽然我的192.168.166.156:11212 节点是断开的。
但是我的192.168.166.156:11211 节点还在
我直接利用那个client去访问192.168.166.156:11211 节点上的数据,192.168.166.156:11211 节点上日志也反映出get ....但是程序中报出
java.util.concurrent.TimeoutException: Timed out(5000) waiting for operation

# re: Xmemcached的FAQ和性能调整建议  回复  更多评论   

2010-09-15 11:24 by denniis
@leixiangjian

我不知道你是怎么指定Node去发送的,貌似xmemcached目前也不支持这个指定node发送的功能。另外就是在MemcachedHandler.onSessionClosed()方法中调用任何阻塞操作都是不当的,因为这是在IO线程上,你阻塞了,根本就发不出去命令,更何谈响应的到达。

# re: Xmemcached的FAQ和性能调整建议  回复  更多评论   

2010-09-15 11:44 by leixiangjian
在这个方法MemcachedHandler.onSessionClosed()被触发时,我使用另一个线程用client来处理我的需求应该是可以的吧,这样就不会对IO线程阻塞了。
这样可以吧!

# re: Xmemcached的FAQ和性能调整建议  回复  更多评论   

2010-09-15 11:51 by leixiangjian
非常感谢你对给我的回答,刚刚那个问题已经解决了!

# re: Xmemcached的FAQ和性能调整建议  回复  更多评论   

2010-10-13 16:04 by commond
记得以前用过 spyMemcached 其中的 future对象很好用 比如 我做一批数据的 remove 我可以将future put到一个map 中 ,然后再去看结果 ,是否remove成功,否则的话 一个一个remove 查看结果 还是阻塞的,效率很低,不知道在xmemcached中 可有什么好的解决方案?

# re: Xmemcached的FAQ和性能调整建议  回复  更多评论   

2010-10-17 15:53 by dennis
@commond
可以用deleteWithNoReply,不查看回复。
xmc没有future模式,同步跟异步future谁更快,你可以测试一下。

# re: Xmemcached的FAQ和性能调整建议  回复  更多评论   

2010-10-20 15:39 by commond
感谢您的回复 xmemcached我还没有测试 ,我们现在项目用的是spy 我测了一下 性能还是有很大区别的
MemcachedClient mc = new MemcachedClient(AddrUtil.getAddresses(ip));
long t = System.currentTimeMillis();
for(int i = 0 ; i < 10000 ; i ++){
mc_self.retryRemove(i+"");

}
long usingtime = (System.currentTimeMillis() - t);
System.out.println(usingtime);



t = System.currentTimeMillis();
Map<String,Future<Boolean>> futureMap = new HashMap<String,Future<Boolean>>();
for(int i = 0 ; i < 10000 ; i ++){
Future<Boolean> future = mc.delete(i+"");
futureMap.put(i+"", future);
}
for(String key : futureMap.keySet()){
Future<Boolean> future = futureMap.get(key);
try {
future.get(1, TimeUnit.SECONDS);
} catch (TimeoutException e) {
future.cancel(true);
System.out.println("TimeoutException");
} catch (InterruptedException e) {
System.out.println("remove object error:");
} catch (ExecutionException e) {
System.out.println("remove object error:");
}
}

usingtime = (System.currentTimeMillis() - t);
System.out.println(usingtime);

11453ms
TimeoutException
1813ms

# re: Xmemcached的FAQ和性能调整建议  回复  更多评论   

2010-10-20 15:41 by denniis
@commond
这种场景我是建议用reply的,只是无法得到响应。

另外,测试还是要模拟并发,单线程测试没有多大意义。

# re: Xmemcached的FAQ和性能调整建议  回复  更多评论   

2010-10-20 15:42 by denniis
@commond
修正,是使用noreply

# re: Xmemcached的FAQ和性能调整建议[未登录]  回复  更多评论   

2010-10-23 17:35 by xzh
<bean id="cacheManager" class="*********" destroy-method="shutdown" depends-on="memcachedClient"> spring context关闭时,想在xmemcached 关闭之前先把数据提交memcached,然后在关闭xmemcached。但是发现在memcachedClient shutdown之前, 关闭钩子已经在关闭session及报错:Xmemcached is stopped。这个问题有怎么好的解决方案吗? 源码中的关闭钩子,都去掉,会有什么样的影响吗?谢谢

# re: Xmemcached的FAQ和性能调整建议  回复  更多评论   

2010-10-25 09:52 by denniis
Xmemcached is stopped的错误是在关闭了xmc之后才会抛出的,关闭的顺序应当xmc放在最后吧。

# re: Xmemcached的FAQ和性能调整建议[未登录]  回复  更多评论   

2010-10-26 19:47 by xzh
xmc 的关闭顺讯我控制不了。xmemcached加了三个关闭钩子。。jvm 一退出。立马就关闭了。spring 上的depends-on,没有本质的作用

# re: Xmemcached的FAQ和性能调整建议[未登录]  回复  更多评论   

2010-10-26 19:49 by xzh
我把源码中,三个关闭钩子去掉了。是能够按照我想的方式关闭。但是我不知道。去掉这个三个关闭钩子,会不会有什么其它方面的影响。

# re: Xmemcached的FAQ和性能调整建议  回复  更多评论   

2010-10-28 17:20 by denniis
@xzh
应该不会有问题,这些钩子只是为来保证万一用户没有调用shutdown,则在jvm退出前尝试关闭。

# re: Xmemcached的FAQ和性能调整建议  回复  更多评论   

2011-05-11 10:40 by Lucene
现在通过Spring配置memcachedClient,如果要注入一些参数不太方便啊,比如设置Builder的SocketOption。希望作者可以改进一下。

# re: Xmemcached的FAQ和性能调整建议[未登录]  回复  更多评论   

2011-08-21 10:27 by 苏林
我想问一下的是、
使用二进制协议时候会出现超时异常:
java.util.concurrent.TimeoutException: Timed out(1000) waiting for operation

代码就是:

String addrs = "127.0.0.1:11211 127.0.0.1:11212 127.0.0.1:11213";
MemcachedClientBuilder builder =
new XMemcachedClientBuilder(AddrUtil.getAddresses(addrs));
builder.addStateListener(new MemcachedListener(null));
builder.setConnectionPoolSize(5);
// builder.setFailureMode(true);
builder.setSocketOption(StandardSocketOption.SO_SNDBUF, 16*1024);
builder.setSocketOption(StandardSocketOption.TCP_NODELAY, false);
// 使用二进制协议、使用的话会出现异常:Timed out(1000) waiting for operation
builder.setCommandFactory(new BinaryCommandFactory());

接下来就是通过builder获取MemcachedClient了

然而如果我使用文本协议的话就正常了。
但是我想使用touch方法:
boolean touch(java.lang.String key, int exp)
如果不用二进制协议的话、 它会提示touch方法只支持二进制协议。

这怎么解决奥

还有一点就是、 二进制协议和文本协议各有什么优缺点啊,相对而言的

# re: Xmemcached的FAQ和性能调整建议  回复  更多评论   

2011-08-21 10:34 by 苏林
囧、 好像是我的Memcached是1.5的, 难道1.5不支持二进制?

# re: Xmemcached的FAQ和性能调整建议  回复  更多评论   

2011-09-17 22:04 by fuyou001
builder.setSocketOption(StandardSocketOption.TCP_NODELAY, false); // 启用nagle算法,提高吞吐量,默认关闭

这是不是笔误.因为你上面提到tcp默认是开启TCP_NODELAY
而我看源代码发现是关闭TCP_NODELAY(即您设置成了false)

如果有要开启TCP_NODELAY,是不是应该设置成true,但你上面却是false???

# re: Xmemcached的FAQ和性能调整建议  回复  更多评论   

2011-09-17 22:25 by fuyou001
@fuyou001
我自己弄错了,请删除或忽略

# re: Xmemcached的FAQ和性能调整建议  回复  更多评论   

2011-09-29 09:49 by storm
超时时间我也设置15000L,但是有时不到这个时间,还是会出现java.util.TimeoutException

# re: Xmemcached的FAQ和性能调整建议  回复  更多评论   

2012-02-08 11:52 by 李丹
楼主厉害,小弟初学,请问下楼主,如果采用spring3.0的配置,使用builder作为工厂类获取client的bean,那么您提到这这些通过编码方式优化性能的方法如何实现?

# re: Xmemcached的FAQ和性能调整建议  回复  更多评论   

2012-02-09 17:43 by scelong
请问一下,我的代码:
List<InetSocketAddress> addresses = AddrUtil
.getAddresses("132.122.1.204:11511 132.122.1.204:11512 132.122.1.204:11513");
MemcachedClientBuilder builder = new XMemcachedClientBuilder(addresses);
上面就是说,有三个Memcached服务器,我想在set操作时(默认是某一个服务器),把数据同时缓存到另外两个服务,xmemcachde有木有这个接口呢?还是通过其他的方式?谢谢

# re: Xmemcached的FAQ和性能调整建议  回复  更多评论   

2012-02-15 11:22 by 黎某人
请问下,Java使用xmemcached去连接ttserver的时候,就会报错Timed out waiting for operation
java是怎么使用xmemcached连接ttserver的

# re: Xmemcached的FAQ和性能调整建议  回复  更多评论   

2012-02-15 11:26 by dennis
@黎某人
参见 http://code.google.com/p/xmemcached/wiki/User_Guide_zh#%E4%B8%8Etokyotyrant%E4%BA%A4%E4%BA%92

# re: Xmemcached的FAQ和性能调整建议  回复  更多评论   

2012-02-23 11:04 by 郭建军
我目前有多台memcached做tomcat的session管理,假如A,B,C三个memcached结点. 目前想做一个memcached的failedover功能.

当前的实现思路,存储在A的Session,同时备份一个到B机器,存储在B上的Session,同时备份一份到C,以次成环形备份.

看了xmemcached的接口,没有找到可以指定key存储到哪个memcached 结点的方法.
请给一个参考意见.

# re: Xmemcached的FAQ和性能调整建议  回复  更多评论   

2012-09-11 13:08 by ai983
目前的set,和replace方法接口都必须要传入一个int exp 的参数。
我想对已有key的value做出替换,但是不想更改原有key的过期时间,请问要如何实现呢?

# re: Xmemcached的FAQ和性能调整建议  回复  更多评论   

2014-02-13 11:53 by lianzerog
请问xmemcached和libmemcached(C客户端)是否兼容,如果可以应该如何操作?新手求助,非常感谢

# re: Xmemcached的FAQ和性能调整建议  回复  更多评论   

2015-03-26 14:39 by 落尘
@leixiangjian
您好!我想请问下java.util.concurrent.TimeoutException: Timed out(5000) waiting for operation 这个问题是如何处理的!

/** 设置与缓存服务器的连接池 */
MemcachedClientBuilder builder = new XMemcachedClientBuilder(AddrUtil.getAddressMap(serverAddress));
try {
//启用failure模式。
builder.setFailureMode(true);
builder.setSessionLocator(new KetamaMemcachedSessionLocator());
builder.setConnectionPoolSize(poolSize);
builder.setHealSessionInterval(healConnectionInterval);
mcc = builder.build();
if(mcc!=null){
mcc.setConnectTimeout(soTimeout);
mcc.setOpTimeout(soTimeout);
}
log.info("Memcache initialization successful!"+serverAddress);
} catch (IOException e) {
log.error("初始化memcache连接失败:" + e.getLocalizedMessage(), e);
}

我这里也会出现超时的现象,xmemcached2.0 .网络肯定没问题的。

谢谢!

只有注册用户登录后才能发表评论。


网站导航: