我之前写了一个sparksql server,提供标准的jdbc接口去执行spark sql,从而弥补spark这部分的能力的缺失,由于考虑到hive的driver的兼容,也就是我希望对于现有的hive使用者,只需要切换一下端口就能直接使用。
而hs2是把ha信息注册在zk中,考虑到存储的一致性,这个server也就选择了zk作为存储介质,除了ha信息外,也存储一些状态信息,前段时间在压测的时候遇到一个zk的问题:

java.io.IOException: Packet len8854970 is out of range!

java.io.IOException: Packet len8854970 is out of range!,out of range就是超过了某个限制,只能查看代码了。

protected final ByteBuffer lenBuffer = ByteBuffer.allocateDirect(4);
protected ByteBuffer incomingBuffer = lenBuffer;

protected void readLength() throws IOException {
int len = incomingBuffer.getInt();
if (len < 0 || len >= ClientCnxn.packetLen) {
throw new IOException("Packet len" + len + " is out of range!");
}
incomingBuffer = ByteBuffer.allocate(len);
}

public static final int packetLen = Integer.getInteger("jute.maxbuffer", 4096 * 1024);

从代码就能够很容易的看出,这个错误是因为len小于0或大于packetLen,根据代码逻辑,len不小于0,那就是大于packetLen。而packetLen的值是jute.maxbuffer系统变量定义或默认的4096 * 1024(4M)。

继续深扒代码,因为代码比较长,这里就不写了。大体逻辑就是,创建与zookeeper连接之后,要对某个节点进行读写操作,为了提高吞吐量,先判断下该节点数据量大小是否超过设置的jute.maxbuffer,如果是,就抛出异常。在zookeeper客户端中,这一部分异常的处理比较粗糙,因为注释上也写着“this is ugly, you have a better way speak up”。

答案就很明显了,只有两种方案:

  • 把待操作节点的大小减下来,小于默认的4M
  • 把默认的jute.maxbuffer大小提高
    对于第一种方式,需要根据自身具体情况具体操作。这里没有什么有效建议。

对于第二种方式,就比较简单了。只要在创建Zookeeper对象之前,设置System.setProperty(“jute.maxbuffer”, 4096 * 1024 * 10 + “”);,这里的大小根据自己的系统设置,我这里只是一个测试值(如果设置太大,这个节点真的比较大的话,会影响吞吐)。

但是这个问题解决后,还会碰到另一个问题:

EndOfStreamException: Unable to read additional data from client sessionid 0x0, likely client has closed socket
at org.apache.zookeeper.server.NIOServerCnxn.doIO(NIOServerCnxn.java:230)
at org.apache.zookeeper.server.NIOServerCnxnFactory.run(NIOServerCnxnFactory.java:203)
at java.lang.Thread.run(Thread.java:745)
INFO [NIOServerCxn.Factory:0.0.0.0/0.0.0.0:2181:NIOServerCnxn@1008] - Closed socket

开始增加Zookeeper的链接设置:
tickTime=2000
改为tickTime=10000


扫码手机观看或分享: