1、 serverWorkerThreads
含义:业务线程池的线程个数,RocketMQ 按任务类型,每个任务类型会拥有一个专门的线程池,比如发送消息,消费消息,另外再加一个其他线程池(默认的业务线程池)。默认业务线程池,采用 fixed 类型,其线程名称:RemotingExecutorThread_。
作用范围:该参数目前主要用于 NameServer 的默认业务线程池,处理诸如 broker、producer,consume 与 NameServer 的所有交互命令。
源码来源:org.apache.rocketmq.namesrv.NamesrvController
public boolean initialize() {
this.kvConfigManager.load();
this.remotingServer = new NettyRemotingServer(this.nettyServerConfig, this.brokerHousekeepingService);
this.remotingExecutor =
Executors.newFixedThreadPool(nettyServerConfig.getServerWorkerThreads(), new ThreadFactoryImpl("RemotingExecutorThread_")); // @1
this.registerProcessor(); // @2
this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
NamesrvController.this.routeInfoManager.scanNotActiveBroker();
}
}, 5, 10, TimeUnit.SECONDS);
this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
NamesrvController.this.kvConfigManager.printAllPeriodically();
}
}, 1, 10, TimeUnit.MINUTES);
return true;
}
private void registerProcessor() {
if (namesrvConfig.isClusterTest()) {
this.remotingServer.registerDefaultProcessor(new ClusterTestRequestProcessor(this, namesrvConfig.getProductEnvName()),
this.remotingExecutor);
} else {
this.remotingServer.registerDefaultProcessor(new DefaultRequestProcessor(this), this.remotingExecutor);
}
代码@1,创建一个线程容量为 serverWorkerThreads 的固定长度的线程池,该线程池供 DefaultRequestProcessor 类使用,实现具体的默认的请求命令处理。
代码@2,就是将 DefaultRequestProcessor 与代码@1创建的线程池绑定在一起。
具体的命令调用类:org.apache.rocketmq.remoting.netty.NettyRemotingAbstract。
/**
* Process incoming request command issued by remote peer.
* @param ctx channel handler context.
* @param cmd request command.
*/
public void processRequestCommand(final ChannelHandlerContext ctx, final RemotingCommand cmd) {
final Pair<NettyRequestProcessor, ExecutorService> matched = this.processorTable.get(cmd.getCode());
final Pair<NettyRequestProcessor, ExecutorService> pair = null == matched ? this.defaultRequestProcessor : matched;
final int opaque = cmd.getOpaque();
if (pair != null) {
Runnable run = new Runnable() {
@Override
public void run() {
try {
RPCHook rpcHook = NettyRemotingAbstract.this.getRPCHook();
if (rpcHook != null) {
rpcHook.doBeforeRequest(RemotingHelper.parseChannelRemoteAddr(ctx.channel()), cmd);
}
final RemotingCommand response = pair.getObject1().processRequest(ctx, cmd);
if (rpcHook != null) {
rpcHook.doAfterResponse(RemotingHelper.parseChannelRemoteAddr(ctx.channel()), cmd, response);
}
if (!cmd.isOnewayRPC()) {
if (response != null) {
response.setOpaque(opaque);
response.markResponseType();
try {
ctx.writeAndFlush(response);
} catch (Throwable e) {
PLOG.error("process request over, but response failed", e);
PLOG.error(cmd.toString());
PLOG.error(response.toString());
}
} else {
}
}
} catch (Throwable e) {
PLOG.error("process request exception", e);
PLOG.error(cmd.toString());
if (!cmd.isOnewayRPC()) {
final RemotingCommand response = RemotingCommand.createResponseCommand(RemotingSysResponseCode.SYSTEM_ERROR, //
RemotingHelper.exceptionSimpleDesc(e));
response.setOpaque(opaque);
ctx.writeAndFlush(response);
}
}
}
};
if (pair.getObject1().rejectRequest()) {
final RemotingCommand response = RemotingCommand.createResponseCommand(RemotingSysResponseCode.SYSTEM_BUSY,
"[REJECTREQUEST]system busy, start flow control for a while");
response.setOpaque(opaque);
ctx.writeAndFlush(response);
return;
}
try {
final RequestTask requestTask = new RequestTask(run, ctx.channel(), cmd);
pair.getObject2().submit(requestTask);
} catch (RejectedExecutionException e) {
if ((System.currentTimeMillis() % 10000) == 0) {
PLOG.warn(RemotingHelper.parseChannelRemoteAddr(ctx.channel()) //
+ ", too many requests and system thread pool busy, RejectedExecutionException " //
+ pair.getObject2().toString() //
+ " request code: " + cmd.getCode());
}
if (!cmd.isOnewayRPC()) {
final RemotingCommand response = RemotingCommand.createResponseCommand(RemotingSysResponseCode.SYSTEM_BUSY,
"[OVERLOAD]system busy, start flow control for a while");
response.setOpaque(opaque);
ctx.writeAndFlush(response);
}
}
} else {
String error = " request type " + cmd.getCode() + " not supported";
final RemotingCommand response =
RemotingCommand.createResponseCommand(RemotingSysResponseCode.REQUEST_CODE_NOT_SUPPORTED, error);
response.setOpaque(opaque);
ctx.writeAndFlush(response);
PLOG.error(RemotingHelper.parseChannelRemoteAddr(ctx.channel()) + error);
}
该方法比较简单,该方法其实就是一个具体命令的处理模板(模板方法),具体的命令实现由各个子类实现,该类的主要责任就是将命令封装成一个线程对象,然后丢到线程池去执行。
2、serverCallbackExecutorThreads
含义:Netty public 任务线程池格式。线程名称:NettyServerPublicExecutor_。
源码来源:org.apache.rocketmq.remoting.netty.NettyRemotingServer。
3、serverSelectorThreads
含义:Netty IO 线程个数,Selector 所在的线程个数,也就主从 Reactor 模型中的从 Reactor 线程数量 。
线程名称:NettyServerNIOSelector_。
作用范围:broker,product,consume 服务端的IO线程数量。
源码来源:org.apache.rocketmq.remoting.netty.NettyRemotingServer。
4、serverOnewaySemaphoreValue、 serverAsyncSemaphoreValue
含义:服务端 oneWay(单向执行)、异步调用的信号量(并发度)。
源码来源:org.apache.rocketmq.remoting.netty.NettyRemotingServer。
org.apache.rocketmq.remoting.netty.NettyRemotingAbstract:
备注:单向(Oneway)发送特点为只负责发送消息,不等待服务器回应且没有回调函数触发,即只发送请求不等待应答。
应用场景:适用于某些耗时非常短,但对可靠性要求并不高的场景,例如日志收集。
5、 其他配置参数
// 通道空闲时间,默认120S, 通过Netty的IdleStateHandler实现
private int serverChannelMaxIdleTimeSeconds = 120;
// socket发送缓存区大小
private int serverSocketSndBufSize = NettySystemConfig.socketSndbufSize;
// socket接收缓存区大小
private int serverSocketRcvBufSize = NettySystemConfig.socketRcvbufSize;
// 是否使用PooledByteBuf(可重用,缓存ByteBuf)
本文关主要分析了 Nameserver 作为 RocketMQ 的注册中心,主要存储了哪些信息,如何存储以及其核心参数。
备注:本文是《RocketMQ技术内幕》的前期素材,建议关注笔者的书籍:《RocketMQ技术内幕》。