云原生中间件RocketMQ-生产者消息返回状态,延迟消息,自定义消息发送规则,netty框架部分代码分析_rocketmq等待消息返回

文章详细解析了Netty框架中ServerBootstrap的启动过程,涉及ChannelHandler的配置,如HandshakeHandler处理TLS协议、NettyEncoder和Decoder的自定义编解码,以及IdleStateHandler和NettyConnectManageHandler的作用。同时介绍了NettyRemotingServer和NettyRemotingClient的start方法,以及RemotingCommand在消息处理中的关键作用。
摘要由CSDN通过智能技术生成
public MessageQueue select(List<MessageQueue> mqs, Message msg, Object arg) {
    Integer queueNumber = (Integer)arg;
    return mqs.get(queueNumber);
}

}, 2);
System.err.println(sr);


### Netty底层框架解析


![在这里插入图片描述](https://img-blog.csdnimg.cn/8d0bc573baeb4e66bab9d6560ec66c3a.png)  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/024407c5d88542c69825cf518921c128.png)  
 `NettyRemotingServer`实现Netty服务器端功能,接受数据包,在服务器端处理后发送给客户端。  
 `NettyRemotingClient`实现Netty客户端功能。


#### NettyRemotingServer


##### start() 方法


start方法主要启动Netty服务器,并在绑定端口后阻塞主线程。这里主要看看Netty服务器端装配了哪些ChannelHandler:



ServerBootstrap childHandler =
this.serverBootstrap.group(this.eventLoopGroupBoss, this.eventLoopGroupSelector)
.channel(useEpoll() ? EpollServerSocketChannel.class : NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, nettyServerConfig.getServerSocketBacklog())
.option(ChannelOption.SO_REUSEADDR, true)
.option(ChannelOption.SO_KEEPALIVE, false)
.childOption(ChannelOption.TCP_NODELAY, true)
.localAddress(new InetSocketAddress(this.nettyServerConfig.getListenPort()))
.childHandler(new ChannelInitializer() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline()
// SocketChannel添加ChannelHandler
.addLast(defaultEventExecutorGroup, HANDSHAKE_HANDLER_NAME, handshakeHandler)
.addLast(defaultEventExecutorGroup,
encoder,
new NettyDecoder(),
new IdleStateHandler(0, 0, nettyServerConfig.getServerChannelMaxIdleTimeSeconds()),
connectionManageHandler,
serverHandler
);
}
});


HandshakeHandler:检测传输的包体是否使用TLS协议(传输层安全性协议,Transport Layer Security)传输 ,如果包体使用TSL协议,将会在Pipeline中加入处理TSL协议握手的Handler。



ctx.pipeline()
.addAfter(defaultEventExecutorGroup, HANDSHAKE_HANDLER_NAME, TLS_HANDLER_NAME, sslContext.newHandler(ctx.channel().alloc()))
.addAfter(defaultEventExecutorGroup, TLS_HANDLER_NAME, FILE_REGION_ENCODER_NAME, new FileRegionEncoder());


![在这里插入图片描述](https://img-blog.csdnimg.cn/4ce14ef0b24c4925a71f41967858d137.png)  
 ![image.png](https://img-blog.csdnimg.cn/img_convert/ea866cd7215184336abbff3998033021.png#clientId=u4938fe88-11c1-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=163&id=ue65c776d&margin=%5BobjectObject%5D&name=image.png&originHeight=183&originWidth=719&originalType=binary&ratio=1&rotation=0&showTitle=false&size=18931&status=done&style=none&taskId=uc0a1ea51-845b-4cba-bb97-dacc77bc00f&title=&width=639.1111111111111)  
 `NettyEncoder/NettyDecoder`:RocketMQ自定义的编解码Handler,其中编码器将RemotingCommand(RocketMQ的服务器端和客户端交互的数据结构)序列化,其中序列化的方式有json或者二进制,具体编解码方式这里不讨论了。而解码器NettyDecoder继承LengthFieldBasedFrameDecoder,基于长度编解码方式,将二进制反序列化为RemotingCommand。  
 `IdleStateHandler`:Netty包中定义的心跳检测包。读写超时时间由NettyServerConfig.serverChannelMaxIdleTimeSeconds变量控制,默认时间120s。  
 `NettyConnectManageHandler`:Channel连接的管理handler,当发生channel连接的激活、失效、超时和异常时,NettyRemotingServer会生成一个Netty事件,管理连接的组件相应的会处理事件。



NettyRemotingServer.this.putNettyEvent(new NettyEvent(NettyEventType.CONNECT, remoteAddress, ctx.channel()));
NettyRemotingServer.this.putNettyEvent(new NettyEvent(NettyEventType.CLOSE, remoteAddress, ctx.channel()));
NettyRemotingServer.this.putNettyEvent(new NettyEvent(NettyEventType.IDLE, remoteAddress, ctx.channel()));
NettyRemotingServer.this.putNettyEvent(new NettyEvent(NettyEventType.EXCEPTION, remoteAddress, ctx.channel()));


`NettyServerHandler`:处理RemotingCommand消息,并且返回相应的处理结果。具体实现如下:



class NettyServerHandler extends SimpleChannelInboundHandler {
@Override
protected void channelRead0(ChannelHandlerContext ctx, RemotingCommand msg) throws Exception {
processMessageReceived(ctx, msg);
}
}


而processMessageReceived()方法在NettyRemotingServer的父类NettyRemotingAbstract中实现:



public void processMessageReceived(ChannelHandlerContext ctx, RemotingCommand msg) throws Exception {
final RemotingCommand cmd = msg;
if (cmd != null) {
switch (cmd.getType()) {
case REQUEST_COMMAND:
processRequestCommand(ctx, cmd);
break;
case RESPONSE_COMMAND:
processResponseCommand(ctx, cmd);
break;
default:
break;
}
}
}


在看processRequestCommand和processResponseCommand这两个方法之前,先了解一下RemotingCommand这个对象:



public class RemotingCommand {
private static SerializeType serializeTypeConfigInThisServer = SerializeType.JSON;
static {
// 获取配置的序列化方式
final String protocol = System.getProperty(SERIALIZE_TYPE_PROPERTY, System.getenv(SERIALIZE_TYPE_ENV));
if (!isBlank(protocol)) {
try {
serializeTypeConfigInThisServer = SerializeType.valueOf(protocol);
} catch (IllegalArgumentException e) {
throw new RuntimeException(“parser specified protocol error. protocol=” + protocol, e);
}
}
}

private int code;  // 请求类型
private LanguageCode language = LanguageCode.JAVA;
private int version = 0; // RocketMQ版本编号
private int opaque = requestId.getAndIncrement(); // 请求序号
private int flag = 0;  // 标记请求是普通请求,还是无回应的请求
private String remark; // 失败提示
private HashMap<String, String> extFields;  // 参数字段的数值
private transient CommandCustomHeader customHeader;  // 参数的类型

private SerializeType serializeTypeCurrentRPC = serializeTypeConfigInThisServer;

private transient byte[] body;  // 解码时缓存的字节流

}


#### NettyRemotingClient


NettyRemotingClient的start()方法与NettyRemotingServer类似,在添加ChannelHandler处理包的handler是NettyClientHandler,其功能与NettyServerHandler一样。



public RemotingCommand invokeSync(String addr, final RemotingCommand request, long timeoutMillis)
throws InterruptedException, RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException {
long beginStartTime = System.currentTimeMillis();
final Channel channel = this.getAndCreateChannel(addr);
if (channel != null && channel.isActive()) {
try {
doBeforeRpcHooks(addr, request);
long costTime = System.currentTimeMillis() - beginStartTime;
if (timeoutMillis < costTime) {
throw new RemotingTimeoutException(“invokeSync call timeout”);
}
RemotingCommand response = this.invokeSyncImpl(channel, request, timeoutMillis - costTime);
doAfterRpcHooks(RemotingHelper.parseChannelRemoteAddr(channel), request, response);
return response;
} catch (Exception e) {
// …

总结

面试前的“练手”还是很重要的,所以开始面试之前一定要准备好啊,不然也是耽搁面试官和自己的时间。

我自己是刷了不少面试题的,所以在面试过程中才能够做到心中有数,基本上会清楚面试过程中会问到哪些知识点,高频题又有哪些,所以刷题是面试前期准备过程中非常重要的一点。

面试题及解析总结

三年Java开发,刚从美团、京东、阿里面试归来,分享个人面经

大厂面试场景

三年Java开发,刚从美团、京东、阿里面试归来,分享个人面经

知识点总结

三年Java开发,刚从美团、京东、阿里面试归来,分享个人面经

有哪些,所以刷题是面试前期准备过程中非常重要的一点。

面试题及解析总结

[外链图片转存中…(img-oetymk6O-1714559821384)]

大厂面试场景

[外链图片转存中…(img-Ccv94orR-1714559821384)]

知识点总结

[外链图片转存中…(img-XEcUg4nn-1714559821385)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

  • 25
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值