vaseems / xmemcached

Automatically exported from code.google.com/p/xmemcached
Apache License 2.0
0 stars 0 forks source link

老报告MemcachedException异常 #119

Closed GoogleCodeExporter closed 8 years ago

GoogleCodeExporter commented 8 years ago
1.循环一个Map<String, 
String>(大概有6000多条数据),然后set到xmemcached(共3个memcach
ed的server),如果是直接set,则老报告
net.rubyeye.xmemcached.exception.MemcachedException: There is no available 
connection at this moment
异常,始终没有timeout异常。 

加大poolsize(已到5),或加大SerializingTranscoder(10*1024*1024),也��
�会报错误

后来在Map的循环中加入Thread.sleep(5),好些了,但还会出上面��
�异常,一直增加到sleep(35)就基本都正确了

版本是
xmemcached-1.3.1.jar, 程序是console控制台执行的,

看了下源代码 
,是session不可用时会抛这个异常,很奇怪呀,难道说当set过快
时session会被消耗光?
if (session == null || session.isClosed()) {
        throw new MemcachedException("There is no available connection at this moment");   }

如何解决这个问题呢,加大poolsize吗? 
谢谢

Original issue reported on code.google.com by cpus...@gmail.com on 30 Mar 2011 at 8:58

GoogleCodeExporter commented 8 years ago
不可能有session耗光这种事情,你有打开日志吗?有没有其他�
��常信息。打开日志看下。

Original comment by killme2...@gmail.com on 30 Mar 2011 at 9:29

GoogleCodeExporter commented 8 years ago
有没有后续反馈呢?

Original comment by killme2...@gmail.com on 2 Apr 2011 at 12:30

GoogleCodeExporter commented 8 years ago
还没看完代码,不过我估计是这样的:
1. 连接太多,nio自动开了Connection
2. MemcachedConnnector.onConnect()被调用
3. 调用addMainSession,然后调用
// Remove old session and close it
        while (sessions.size() > this.connectionPoolSize) {
            Session oldSession = sessions.poll();
            ((MemcachedSession) oldSession).setAllowReconnect(false);
            oldSession.close();
        }

这时候,不好意思,oldSession被关闭了。但是这个oldSession已经
被分配出去了,所以你那儿报了异常。异常的原因是session.isC
losed()返回了true。

不知道对不对。

要解决的话,无非是在超限制关闭前,检查Session是否被使用�
��放个Future,等他用完了再关。但这样的话,poolsize肯定会在�
��际使用中会超出。或者的话,是不是应该把poolsize放到nio打�
��连接上做限制;超过poolsize,连接就不在创建。或者像db 
pool似的设置init, min, max size大小。

我没有实际用过nio,如果对nio理解不对还请指正。我感觉中ni
o好像是会玩命的创建连接,和不要钱似的~~ 
poolsize做普通的socket长连接还行,nio肯定不够。

Original comment by liukaix...@gmail.com on 2 Apr 2011 at 3:41

GoogleCodeExporter commented 8 years ago
修正下最后一句话:poolsize=5做普通的socket长连接还行,nio肯�
��不够。设置成200还差不多。

Original comment by liukaix...@gmail.com on 2 Apr 2011 at 3:45

GoogleCodeExporter commented 8 years ago
默认情况下不会自动断开连接,5个连接并不多。
除非你的memcached的连接数达到上限,可以通过-c选项改变。默
认是1024.

Original comment by killme2...@gmail.com on 3 Apr 2011 at 8:06

GoogleCodeExporter commented 8 years ago
给楼主发邮件。楼主debug下啊,看到底报错的原因是什么,是
session=null还是isClosed返回true。

我在做socket连接池的调研,用普通的方式想基于apache commons 
pool来做,但xmemcached好像提供了另外一个办法,让nio自己管理
,超时自己关闭连接。但这样的话,poolsize真的好控制吗?假
设poolsize=10,那么当需要超过时会怎么处理?开到第11个的时�
��,策略好像是强制自动关闭第1个,再新开第11个?这样会不
会有内容发送一半发现连接关闭的问题?或者这样的代价是��
�是比让调用方等一会要高?毕竟都要等待,nio方式还要重开�
��下连接。

Original comment by liukaix...@gmail.com on 6 Apr 2011 at 3:07

GoogleCodeExporter commented 8 years ago
不好意思,回复有些晚了,后来是加大poolsize=25 
就不会出错了,
具体是session=null还是isClosed返回true没来得及查,(被其他项��
�抓走了)

服务器端是-c 10240,足够了

回复很快呀,还是很nice的呀

Original comment by cpus...@gmail.com on 6 Apr 2011 at 10:14

GoogleCodeExporter commented 8 years ago
我在本地测试,没有出现你提的问题。xmc的连接池是自己管��
�的,不会出现连接耗尽这种情况。

我估计是你误用造成的,可以的话将你的代码附上来看看吧��
�

Original comment by killme2...@gmail.com on 7 Apr 2011 at 7:22

GoogleCodeExporter commented 8 years ago
继续关注下。将poolsize设置成2,然后开100个线程写试试?netst
at看实际的连接数会不会超过,能不能重现错误?

Original comment by liukaix...@gmail.com on 7 Apr 2011 at 7:38

GoogleCodeExporter commented 8 years ago
xmc的压测,500个并发线程都测试过的。每一个版本在release之�
��都会做这个压测的。

Original comment by killme2...@gmail.com on 7 Apr 2011 at 7:47

GoogleCodeExporter commented 8 years ago
[deleted comment]
GoogleCodeExporter commented 8 years ago
代码很简单,没有调用spring等,是直接生成的,也没有起子��
�程,
大家看看有没有啥问题,谢谢了呀

初始化:几个server端都是局域网内部的server,网速应该没问��
�,不过server端服务比较多可能压力比较大
MemcachedClientBuilder builder = new 
XMemcachedClientBuilder(AddrUtil.getAddresses("****:1121 ****:1121 ****:1121"));
builder.setSessionLocator(new KetamaMemcachedSessionLocator());       
builder.setBufferAllocator(new SimpleBufferAllocator());
builder.setCommandFactory(new BinaryCommandFactory());
builder.setConnectionPoolSize(25);  
//设成25或更高就ok,设小了就出异常
builder.setFailureMode(false);
builder.setTranscoder(new SerializingTranscoder());
client=builder.build();//client是成功了

调用,都是简单的String
for(Map.Entry<String, String> entry : map.entrySet()) {   
  try{
     client.set(entry.getKey(),1000, (String)entry.getValue());
  }catch(Exception e){
  //当前面poolsize比较小时,这里就会抛出前面说的异常

  }
} 

Original comment by cpus...@gmail.com on 8 Apr 2011 at 1:06

GoogleCodeExporter commented 8 years ago
我完全使用你给的代码来测试,也没有出现你提到的问题。
有个疑问,你用的memcached是哪个版本,支持二进制协议吗?��
�猜测是不是因为使用了不支持二进制协议的memcached引起连接�
��开的。
你用的memcached的os是什么?版本是多少?

Original comment by killme2...@gmail.com on 9 Apr 2011 at 1:15

GoogleCodeExporter commented 8 years ago
memcached版本是1.4.5,应该是比较新的了吧
$ telnet localhost 11211
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
version
VERSION 1.4.5

os的版本 linux内核是2.6
$ uname -a
Linux 2.6.9-42.ELsmp #1 SMP Wed Jul 12 23:32:02 EDT 2006 x86_64 x86_64 x86_64 
GNU/Linux
服务器版本是AS4 
$ lsb_release -a
LSB Version:    
:core-3.0-amd64:core-3.0-ia32:core-3.0-noarch:graphics-3.0-amd64:graphics-3.0-ia
32:graphics-3.0-noarch
Distributor ID: RedHatEnterpriseAS
Description:    Red Hat Enterprise Linux AS release 4 (Nahant Update 4)
Release:        4
Codename:       NahantUpdate4

另外,往memcached提交的这个map大概有上万的数据量吧,
要么就加大poolsize,要么就在client.set前加Thread.sleep(5), 
这样就不会报告异常了
for(Map.Entry<String, String> entry : map.entrySet()) {   
  try{
     client.set(entry.getKey(),1000, (String)entry.getValue());
  }catch(Exception e){
  //当前面poolsize比较小时,这里就会抛出前面说的异常
  }
}

Original comment by cpus...@gmail.com on 11 Apr 2011 at 2:07

GoogleCodeExporter commented 8 years ago
我直接用你的代码,不设置连接池,也就是默认一个连接,��
�后设置10000个map数据大小,也没抛异常,暂时没有重现。

你有打开日志吗?配置下log4j.properties,看看输出什么错误,�
��常之外应该有日志提示为什么断开连接。

Original comment by killme2...@gmail.com on 11 Apr 2011 at 2:11

GoogleCodeExporter commented 8 years ago
当poolsize=5,只用了一个memcached server
执行时,开始都成功,突然就一个失败了,然后后面的就开��
�有失败了,也会有成功的。 
而且每次开始失败不是同一个地方,这个很郁闷。

有办法打印详细的xmemcache的log4j吗?在失败时没有什么日志提
示断开连接
是在工程的log4j.properties中设置的debug输出,log4j.logger.net.rubyey
e=DEBUG  但除了抛异常外,没其它输出,

日志如下:
set():key:www.**********   value:2010***************   
e:There is no available connection at this moment
[ERROR]net.rubyeye.xmemcached.exception.MemcachedException: 
There is no available connection at this moment
    at net.rubyeye.xmemcached.impl.MemcachedConnector.send(MemcachedConnector.java:454)
    at net.rubyeye.xmemcached.XMemcachedClient.sendCommand(XMemcachedClient.java:244)
    at net.rubyeye.xmemcached.XMemcachedClient.sendStoreCommand(XMemcachedClient.java:2316)
    at net.rubyeye.xmemcached.XMemcachedClient.set(XMemcachedClient.java:1241)
    at net.rubyeye.xmemcached.XMemcachedClient.set(XMemcachedClient.java:1299)
    at net.rubyeye.xmemcached.XMemcachedClient.set(XMemcachedClient.java:1286)

然后取了下当前的stats:
client.getStats():
InetSocketAddress:***.***.***.***
delete_misses:0
threads:4
connection_structures:36
evictions:0
cmd_set:38091
time:1302504628
incr_misses:0
get_misses:0
decr_hits:0
listen_disabled_num:0
pid:28992
incr_hits:0
accepting_conns:1
curr_connections:14
limit_maxbytes:2147483648
decr_misses:0
cas_misses:0
auth_errors:0
cmd_get:0
cas_hits:0
bytes_written:1230656
cmd_flush:0
total_connections:972
uptime:1571742
total_items:38091
rusage_user:0.465929
auth_cmds:0
curr_items:6888
bytes:1556302
version:1.4.5
rusage_system:0.679896
bytes_read:8341711
reclaimed:7403
get_hits:0
conn_yields:0
cas_badval:0
delete_hits:0
pointer_size:64

Original comment by cpus...@gmail.com on 11 Apr 2011 at 7:07

GoogleCodeExporter commented 8 years ago
彻底查了下,估计找到问题了,是key值太长造成的,某些key��
�url地址,会超过250的长度,因此可能会导致失败,如果判断k
ey长度超过250时就不client.set(),只设置key小于250的,那么就能
都成功了

不过还有个疑问:
1 当poolsize值比较大时,就能在client.set()时不抛出异常,
(后来又取下了值client.get(),应该是没有存进去)
就是说,set赋值时,不一定能成功保存吗,有没有办法能确��
�下是否保存成功?

PS:网上说可以改memcached.h的一个宏,可以改大key值: 
#define KEY_MAX_LENGTH 250
改大些,试下了改为
#define KEY_MAX_LENGTH 1024
但光改这个一个不行,会make编译错误,同时要改items.c,细节
就不说了
反正,改完了以后,虽然memcached能跑了,但一旦客户端设置��
�key大于250了,memcached的server就直接挂掉了~~~~~~~~

memcached版本是1.4.5,
to “killme2...@gmail.com,” 有办法加大memcached的key值码吗?
很负责呀,回复问题很及时,还帮忙测试了下,
谢谢了呀

Original comment by cpus...@gmail.com on 11 Apr 2011 at 8:41

GoogleCodeExporter commented 8 years ago
我也重现了,果然是key太长引起的连接断开。我用spy测试,��
�脆不让我设置长度超过250的key,修改了spy源码忽略长度验证�
��测试,也是一样的错误,引起连接断开。

从这个来看,貌似memcached的二进制协议还是没办法支持大长��
�的key,协议上支持,但是服务器端还不行。

Original comment by killme2...@gmail.com on 12 Apr 2011 at 12:51

GoogleCodeExporter commented 8 years ago
如果是文本格式的协议,能支持大长度的key吗?

Original comment by cpus...@gmail.com on 12 Apr 2011 at 7:44

GoogleCodeExporter commented 8 years ago
文本协议更是不行的,文本协议限定在250个字节。

Original comment by killme2...@gmail.com on 13 Apr 2011 at 5:55

GoogleCodeExporter commented 8 years ago
这个问题暂时无法修复,我先关闭了。

Original comment by killme2...@gmail.com on 25 Jun 2011 at 12:06

GoogleCodeExporter commented 8 years ago
如果真是key太长的问题的话,为什么你之前调大poolsize或者sle
ep长一点就没问题了??

Original comment by billbarg...@gmail.com on 16 Apr 2013 at 7:28