写在前面
请先阅读HDFSRPC通信框架详解,对整体框架先有一定的了解。
参数列表
参数 | 默认值 | 描述 |
---|---|---|
ipc.server.read.connection-queue.size | 100 | reader |
ipc.server.read.threadpool.size | 1 | reader |
ipc.server.listen.queue.size | 128 | Listener:backlog |
ipc.server.tcpnodelay | true | Listener |
ipc.maximum.data.length | 64 * 1024 * 1024 | Connection:rpc data len |
dfs.namenode.handler.count | 10 | handler nn requests from clients |
dfs.namenode.service.handler.count | 10 | handler nn requests from DataNodes |
dfs.namenode.lifeline.handler.count | 10 | handler nn lifeline requests |
dfs.datanode.handler.count | 10 | handler dn |
ipc.server.read.connection-queue.size
reader的处理连接数,默认是100。使用BlockingQueue实现。
final private BlockingQueue<Connection> pendingConnections;public void addConnection(Connection conn) throws InterruptedException {pendingConnections.put(conn);readSelector.wakeup();}
使用addConnection加入队列,队列满了此方法会阻塞。
ipc.server.read.threadpool.size
reader的线程数,默认为1。reader主要用于连接头,连接上下文的处理,还是要花费一定的时间的,特别在使用Kerberos的时候。reader多线程处理会比较合理,所以笔者认为这个默认值不太合理,设置为不小于1会比较合理。
ipc.server.listen.queue.size
默认值为128,属于listener。本参数虽然叫queuesize,单实际上不是listenr的数量或者listener的队列长度,而是来源于ServerSocket的bind(SocketAddress endpoint, int backlog) 方法中的backlog。listener源码为
private int backlogLength = Config.getInt(CommonConfigurationKeysPublic.IPC_SERVER_LISTEN_QUEUE_SIZE_KEY,CommonConfigurationKeysPublic.IPC_SERVER_LISTEN_QUEUE_SIZE_DEFAULT);public Listener(String bindAddress, int port, int readThreads) throws IOException {...acceptChannel.socket().bind(address, backlogLength);...
}
backlog参数为如果server.accept()没有及时接收,系统会把socket缓存起来,代表这个缓存队列的大小。如果队列已满,新连接会被拒接。
void doAccept(SelectionKey key) throws InterruptedException, IOException, OutOfMemoryError {ServerSocketChannel server = (ServerSocketChannel) key.channel();SocketChannel channel;while ((channel = server.accept()) != null) {channel.configureBlocking(false);channel.socket().setTcpNoDelay(tcpNoDelay);channel.socket().setKeepAlive(true);Reader reader = getReader();Connection c = Server.connectionManager.register(channel);// If the connectionManager can't take it, close the connection.if (c == null) {if (channel.isOpen()) {IOUtils.cleanup(null, channel);}Server.connectionManager.droppedConnections.getAndIncrement();continue;}key.attach(c); // so closeCurrentConnection can get the objectreader.addConnection(c);}}
看doAccept方法,Connection接收到了以后会放入connectionManager,如果connectionManager的队列满了(ipc.server.max.connections)会直接关闭连接,ipc.server.max.connections默认值为0,代表没有上限。reader.addConnection代表连接会放入reader的pendingConnections,pendingConnections为BlockingQueue,满了会阻塞,默认值为100。所以默认值情况下,可以处理100+128个连接,超过了以后会被拒绝。如果ipc.server.max.connections设置为50,此值会直接失效,因为连接超过50以后,会直接关闭连接。
ipc.server.tcpnodelay
连接的TcpNoDelay属性,默认为true。
channel.configureBlocking(false);
channel.socket().setTcpNoDelay(tcpNoDelay);
channel.socket().setKeepAlive(true);
对应的就是TCP_NODELAY,本质上设置是否使用Nagle 算法,缓存数据合并发送。建议使用默认值true,关闭Nagle 算法。
ipc.maximum.data.length
请求的数据最大长度,默认是64MB。
this.maxDataLength = Config.getInt(CommonConfigurationKeys.IPC_MAXIMUM_DATA_LENGTH,CommonConfigurationKeys.IPC_MAXIMUM_DATA_LENGTH_DEFAULT);private void checkDataLength(int dataLength) throws IOException {if (dataLength < 0) {String error = "Unexpected data length " + dataLength +"!! from " + getHostAddress();LOG.warn(error);throw new IOException(error);} else if (dataLength > maxDataLength) {String error = "Requested data length " + dataLength +" is longer than maximum configured RPC length " + maxDataLength + ". RPC came from " + getHostAddress();LOG.warn(error);throw new IOException(error);}}
如果长度超过最大长度,server不会返回任何数据,会直接关闭连接。
handler.count
handler的数量,默认为10。有4个参数,分别为dfs.namenode.handler.count,dfs.namenode.service.handler.count,dfs.namenode.lifeline.handler.count,dfs.datanode.handler.count 。handler是用于实际处理rpc请求的,比如createfile,mkdir等。这些操作都是要花费一定的时间,而且随着存储文件数,存储集群的变大,理论上会变慢。所以handler.count可以设置的大一点。当然建议dfs.namenode.handler.count设置大一点就行,dfs.namenode.handler.count主要用于处理客户端请求,网上建议设置为20logN,N为集群服务器数量。其他都是集群内部的请求处理,没有特殊情况,使用默认值即可。