为什么ZooKeeper Server出现java.io.IOException: Len的错误日志
问题
在父目录中创建大量的znode之后,当ZooKeeper客户端尝试在单个请求中获取该父目录中的所有子节点时,将返回失败。
客户端日志,如下所示:
2017-07-11 13:17:19,610 [myid:] - WARN [New I/O worker #3:ClientCnxnSocketNetty$ZKClientHandler@468] - Exception caught: [id: 0xb66cbb85, /10.18.97.97:49192 :> 10.18.97.97/10.18.97.97:2181] EXCEPTION: java.nio.channels.ClosedChannelException java.nio.channels.ClosedChannelException at org.jboss.netty.handler.ssl.SslHandler$6.run(SslHandler.java:1580) at org.jboss.netty.channel.socket.ChannelRunnableWrapper.run(ChannelRunnableWrapper.java:40) at org.jboss.netty.channel.socket.nio.AbstractNioWorker.executeInIoThread(AbstractNioWorker.java:71) at org.jboss.netty.channel.socket.nio.NioWorker.executeInIoThread(NioWorker.java:36) at org.jboss.netty.channel.socket.nio.AbstractNioWorker.executeInIoThread(AbstractNioWorker.java:57) at org.jboss.netty.channel.socket.nio.NioWorker.executeInIoThread(NioWorker.java:36) at org.jboss.netty.channel.socket.nio.AbstractNioChannelSink.execute(AbstractNioChannelSink.java:34) at org.jboss.netty.handler.ssl.SslHandler.channelClosed(SslHandler.java:1566) at org.jboss.netty.channel.Channels.fireChannelClosed(Channels.java:468 at org.jboss.netty.channel.socket.nio.AbstractNioWorker.close(AbstractNioWorker.java:376) at org.jboss.netty.channel.socket.nio.NioWorker.read(NioWorker.java:93) at org.jboss.netty.channel.socket.nio.AbstractNioWorker.process(AbstractNioWorker.java:109) at org.jboss.netty.channel.socket.nio.AbstractNioSelector.run(AbstractNioSelector.java:312) at org.jboss.netty.channel.socket.nio.AbstractNioWorker.run(AbstractNioWorker.java:90) at org.jboss.netty.channel.socket.nio.NioWorker.run(NioWorker.java:178) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:745)
Leader节点的日志,如下所示:
2017-07-11 13:17:33,043 [myid:1] - WARN [New I/O worker #7:NettyServerCnxn@445] - Closing connection to /10.18.101.110:39856 java.io.IOException: Len error 45 at org.apache.zookeeper.server.NettyServerCnxn.receiveMessage(NettyServerCnxn.java:438) at org.apache.zookeeper.server.NettyServerCnxnFactory$CnxnChannelHandler.processMessage(NettyServerCnxnFactory.java:267) at org.apache.zookeeper.server.NettyServerCnxnFactory$CnxnChannelHandler.messageReceived(NettyServerCnxnFactory.java:187) at org.jboss.netty.channel.SimpleChannelHandler.handleUpstream(SimpleChannelHandler.java:88) at org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:564) at org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:559) at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:268) at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:255) at org.jboss.netty.channel.socket.nio.NioWorker.read(NioWorker.java:88) at org.jboss.netty.channel.socket.nio.AbstractNioWorker.process(AbstractNioWorker.java:109) at org.jboss.netty.channel.socket.nio.AbstractNioSelector.run(AbstractNioSelector.java:312) at org.jboss.netty.channel.socket.nio.AbstractNioWorker.run(AbstractNioWorker.java:90) at org.jboss.netty.channel.socket.nio.NioWorker.run(NioWorker.java:178) at org.jboss.netty.util.ThreadRenamingRunnable.run(ThreadRenamingRunnable.java:108) at org.jboss.netty.util.internal.DeadLockProofWorker$1.run(DeadLockProofWorker.java:42) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:745)
回答
在单个父目录中创建大量的znode后,当客户端尝试在单个请求中获取所有子节点时,服务端将无法返回,因为结果将超出可存储在znode上的数据的最大长度。
为了避免这个问题,应该根据客户端应用的实际情况将“jute.maxbuffer”参数配置为一个更高的值。
“jute.maxbuffer”只能设置为Java系统属性,且没有zookeeper前缀。如果要将“jute.maxbuffer”的值设为X,在ZooKeeper客户端或服务端启动时传入以下系统属性:-Djute.maxbuffer=X。
例如,将参数值设置为4MB:-Djute.maxbuffer=0x400000。
参数 |
描述 |
默认值 |
---|---|---|
jute.maxbuffer |
指定可以存储在znode中的数据的最大长度。单位是Byte。默认值为0xfffff,即低于1MB。
说明:
如果更改此选项,则必须在所有服务器和客户端上设置该系统属性,否则将出现问题。 |
0xfffff |