使用 netty 监听端口

// org.apache.rocketmq.remoting.netty.NettyRemotingServer#start
ServerBootstrap childHandler =
this.serverBootstrap.group(this.eventLoopGroupBoss, this.eventLoopGroupSelector)
.channel(useEpoll() ? EpollServerSocketChannel.class : NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 1024)
.option(ChannelOption.SO_REUSEADDR, true)
.option(ChannelOption.SO_KEEPALIVE, false)
.childOption(ChannelOption.TCP_NODELAY, true)
.childOption(ChannelOption.SO_SNDBUF, nettyServerConfig.getServerSocketSndBufSize())
.childOption(ChannelOption.SO_RCVBUF, nettyServerConfig.getServerSocketRcvBufSize())
// 绑定端口
.localAddress(new InetSocketAddress(this.nettyServerConfig.getListenPort()))
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline()
.addLast(defaultEventExecutorGroup, HANDSHAKE_HANDLER_NAME,
new HandshakeHandler(TlsSystemConfig.tlsMode))
.addLast(defaultEventExecutorGroup,
new NettyEncoder(),
new NettyDecoder(),
new IdleStateHandler(0, 0, nettyServerConfig.getServerChannelMaxIdleTimeSeconds()),
new NettyConnectManageHandler(),
// 分发请求
new NettyServerHandler()
);
}
});
// 启动
ChannelFuture sync = this.serverBootstrap.bind().sync();

接收请求

// org.apache.rocketmq.remoting.netty.NettyRemotingServer.NettyServerHandler
class NettyServerHandler extends SimpleChannelInboundHandler<RemotingCommand> { @Override
protected void channelRead0(ChannelHandlerContext ctx, RemotingCommand msg) throws Exception {
processMessageReceived(ctx, msg);
}
}

分发请求

public void processRequestCommand(final ChannelHandlerContext ctx, final RemotingCommand cmd) {
// NettyRequestProcessor 是处理具体请求的处理器,ExecutorService 是对应的线程池
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) {
log.error("process request over, but response failed", e);
log.error(cmd.toString());
log.error(response.toString());
}
} else { }
}
} catch (Throwable e) {
log.error("process request exception", e);
log.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) {
log.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);
log.error(RemotingHelper.parseChannelRemoteAddr(ctx.channel()) + error);
}
}

broker 启动时,把不同类型的请求对应到各自的处理器

// org.apache.rocketmq.broker.BrokerController#BrokerController
// 创建队列
this.sendThreadPoolQueue = new LinkedBlockingQueue<Runnable>(this.brokerConfig.getSendThreadPoolQueueCapacity());
// org.apache.rocketmq.broker.BrokerController#initialize
// 创建线程池
this.sendMessageExecutor = new BrokerFixedThreadPoolExecutor(
this.brokerConfig.getSendMessageThreadPoolNums(),
this.brokerConfig.getSendMessageThreadPoolNums(),
1000 * 60,
TimeUnit.MILLISECONDS,
this.sendThreadPoolQueue,
new ThreadFactoryImpl("SendMessageThread_"));
// org.apache.rocketmq.broker.BrokerController#registerProcessor
// 把不同的请求,请求处理器,线程池对应起来
public void registerProcessor() {
/**
* SendMessageProcessor
*/
SendMessageProcessor sendProcessor = new SendMessageProcessor(this);
sendProcessor.registerSendMessageHook(sendMessageHookList);
sendProcessor.registerConsumeMessageHook(consumeMessageHookList); this.remotingServer.registerProcessor(RequestCode.SEND_MESSAGE, sendProcessor, this.sendMessageExecutor);
this.remotingServer.registerProcessor(RequestCode.SEND_MESSAGE_V2, sendProcessor, this.sendMessageExecutor);
this.remotingServer.registerProcessor(RequestCode.SEND_BATCH_MESSAGE, sendProcessor, this.sendMessageExecutor);
this.remotingServer.registerProcessor(RequestCode.CONSUMER_SEND_MSG_BACK, sendProcessor, this.sendMessageExecutor);
this.fastRemotingServer.registerProcessor(RequestCode.SEND_MESSAGE, sendProcessor, this.sendMessageExecutor);
this.fastRemotingServer.registerProcessor(RequestCode.SEND_MESSAGE_V2, sendProcessor, this.sendMessageExecutor);
this.fastRemotingServer.registerProcessor(RequestCode.SEND_BATCH_MESSAGE, sendProcessor, this.sendMessageExecutor);
this.fastRemotingServer.registerProcessor(RequestCode.CONSUMER_SEND_MSG_BACK, sendProcessor, this.sendMessageExecutor);
}

不同的线程池处理不同的请求,做到很好的隔离。

rocketMQ broker 分发并处理请求的更多相关文章

  1. ipvsadm分发MySQL读请求

    在MySQL的部署场景中,经常使用HAproxy和ipvs来作为读请求转发的网关.ipvs的好处在于本身不需要daemon的方式来运行,而是直接作为kernel的服务来提供:当ipvs和应用程序服务器 ...

  2. rocketMq排坑:如何设置rocketMq broker的ip地址

    在工作中遇到了一个这个问题,就是我们rocketmq是部署在云主机上的 但是我们的开发同事在自己的电脑连接rocketmq链接不上 报错显示Caused by: org.apache.rocketmq ...

  3. 记一次 RocketMQ broker 因内存不足导致的启动失败

    原创:西狩 编写日期 / 修订日期:2020-01-12 / 2020-01-12 版权声明:本文为博主原创文章,遵循 CC BY-SA-4.0 版权协议,转载请附上原文出处链接和本声明. 背景 该小 ...

  4. RocketMQ broker jvm 监控

    1. jps 获取要监控broker jvm 的进程ID jsp 2. nohup 输出监控日志 nohup jstat -gc -t [pid] [interval] -t 会在每一条记录前加时间戳 ...

  5. Rocketmq Broker启动网卡顺序问题

    方法一.修改网卡名称,因为网卡顺序是通过名称排列的 方法二.指定broker使用IP echo "brokerIP1=192.168.1.220" > conf/broker ...

  6. rocketMq broker.conf全部参数解释

    #4.7.1版本 #所属集群名字brokerClusterName=rocketmq-cluster#broker名字,名字可重复,为了管理,每个master起一个名字,他的slave同他,eg:Am ...

  7. RocketMQ中Broker的启动源码分析(一)

    在RocketMQ中,使用BrokerStartup作为启动类,相较于NameServer的启动,Broker作为RocketMQ的核心可复杂得多 [RocketMQ中NameServer的启动源码分 ...

  8. RocketMQ源码详解 | Broker篇 · 其三:CommitLog、索引、消费队列

    概述 上一章中,已经介绍了 Broker 的文件系统的各个层次与部分细节,本章将继续了解在逻辑存储层的三个文件 CommitLog.IndexFile.ConsumerQueue 的一些细节.文章最后 ...

  9. RocketMQ源码详解 | Broker篇 · 其五:高可用之主从架构

    概述 对于一个消息中间件来讲,高可用功能是极其重要的,RocketMQ 当然也具有其对应的高可用方案. 在 RocketMQ 中,有主从架构和 Dledger 两种高可用方案: 第一种通过主 Brok ...

随机推荐

  1. Python测开面试题之装饰器

    Python的装饰器是面试常被问到的问题之一,在面试Python测试开发时被问到的概率不低于70%,那么装饰器的原理是什么,怎么快速写出一个装饰器呢,接下来我们详细讲解装饰器的实现方法. Python ...

  2. 微信小程序 点击事件 传递参数

    wxml: data-参数名="值" bindtap="函数名" <view class="buy-button {{cap_select == ...

  3. 【转载】Java File操作汇总

    转载自博客:https://passport.cnblogs.com/user/signin?ReturnUrl=https%3A%2F%2Fwww.cnblogs.com%2F 本文通过大量的示例, ...

  4. 提高docker加载速度

    由于国情,我们需要对配置一下docker的下载镜像,提高一下后续的加载速度. 使用vim编辑 /etc/docker/daemon.json, 增加如下内容. { "registry-mir ...

  5. js 点击不同li 切换颜色

    html <div> <li " onclick='addColor(this.id)'> 会议简介 </li> <li " onclic ...

  6. 【CF1181C】Flag

    题目大意:给定一个 N*M 的矩阵,定义一个矩形区域为一个"国旗",满足:矩形区域可以按行划分成三个高度相同的部分,其中每一个部分中的颜色完全相同,第一部分的颜色与第二部分颜色不同 ...

  7. MFC界面库BCGControlBar v30.1——Grid/Report控件

    亲爱的BCGSoft用户,我们非常高兴地宣布BCGControlBar Professional for MFC和BCGSuite for MFC v30.1正式发布!此版本包含themed find ...

  8. sublime text 前端插件安装

    Package Control安装 打开sublime编辑器,ctrl + ` 打开安装PackageControl界面: sublime text3: import urllib.request,o ...

  9. 【leetcode】LCP 2. 分式化简

    题目如下: 有一个同学在学习分式.他需要将一个连分数化成最简分数,你能帮助他吗? 连分数是形如上图的分式.在本题中,所有系数都是大于等于0的整数. 输入的cont代表连分数的系数(cont[0]代表上 ...

  10. Mybatis中通过父类/接口来限定类的别名(TypeAlias)配置