分布式消息队列RocketMQ之Netty -- 1+N+M1+M2模型
来源:互联网 发布:淘宝瑕疵冰箱上当受骗 编辑:程序博客网 时间:2024/06/05 10:53
我们知道Kafka的network层是直接基于JavaNIO写的,在前面Kafka源码分析序列中已经有详细分析。 RocketMQ的network层是基于Netty写的,实现起来相对简单一些,毕竟Netty已经是很成熟的网络框架。
本篇就来分析一下,直接使用javaNIO写网络层,和基于Netty写,模型上有什么区别。
1
我们知道,Java NIO的1+N+M模型:1个acceptor线程,N个IO线程,M个worker 线程。那对应到Netty里面,是什么样呢?
下面的代码来自RocketMQ的NettyRemotingServer类里面,可以看到,它也是1个thread。
这里有2个概念提一下:EventLoop和EventLoopGroup。EventLoop就是对应1个线程,EventLoopGroup是EventLoop的集合,也就是对应一个线程池。
this.eventLoopGroupBoss = new NioEventLoopGroup(1, new ThreadFactory() { private AtomicInteger threadIndex = new AtomicInteger(0); @Override public Thread newThread(Runnable r) { return new Thread(r, String.format("NettyBoss_%d", this.threadIndex.incrementAndGet())); } });
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 1
- 2
- 3
- 4
- 5
- 6
- 7
N
如果是Linux平台,并且开启了native epoll,就用EpollEventLoopGroup,这个也就是用JNI,调的c写的epoll;否则,就用Java NIO的NioEventLoopGroup。
这里也是开了N个IO thread。
if (RemotingUtil.isLinuxPlatform() // && nettyServerConfig.isUseEpollNativeSelector()) { this.eventLoopGroupSelector = new EpollEventLoopGroup(nettyServerConfig.getServerSelectorThreads(), new ThreadFactory() { private AtomicInteger threadIndex = new AtomicInteger(0); private int threadTotal = nettyServerConfig.getServerSelectorThreads(); @Override public Thread newThread(Runnable r) { return new Thread(r, String.format("NettyServerEPOLLSelector_%d_%d", threadTotal, this.threadIndex.incrementAndGet())); } }); } else { this.eventLoopGroupSelector = new NioEventLoopGroup(nettyServerConfig.getServerSelectorThreads(), new ThreadFactory() { private AtomicInteger threadIndex = new AtomicInteger(0); private int threadTotal = nettyServerConfig.getServerSelectorThreads(); @Override public Thread newThread(Runnable r) { return new Thread(r, String.format("NettyServerNIOSelector_%d_%d", threadTotal, this.threadIndex.incrementAndGet())); } }); }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
ServerBootstrap childHandler = this.serverBootstrap.group(this.eventLoopGroupBoss, this.eventLoopGroupSelector).channel(NioServerSocketChannel.class) .option(ChannelOption.SO_BACKLOG, 1024) .option(ChannelOption.SO_REUSEADDR, true) .option(ChannelOption.SO_KEEPALIVE, false) .childOption(ChannelOption.TCP_NODELAY, true) .option(ChannelOption.SO_SNDBUF, nettyServerConfig.getServerSocketSndBufSize()) .option(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, new NettyEncoder(), new NettyDecoder(), new IdleStateHandler(0, 0, nettyServerConfig.getServerChannelMaxIdleTimeSeconds()), new NettyConnetManageHandler(), new NettyServerHandler()); } });
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
M
M这个地方是最容易看不清楚的地方。在RocketMQ对Netty的封装中,这个M其实又分成了2个线程池,我称之为M1+M2。
其中M1是在NettyRemotingServer里面,也就是上面代码中的defaultEventExecutorGroup,主要职责是encode/decode。
M2在上面的应用层,拿NameServer中的NamesrvController为例,在使用NettyRemotingServer的时候,传进去了一个Processor + 1个线程池,也就是M2。
this.remotingServer.registerDefaultProcessor(new DefaultRequestProcessor(this), this.remotingExecutor);
- 1
- 1
总结
RocketMQ基于Netty的网络层,有4个线程池,线程名字分别如下:
1: “NettyBoss_%d”
N: “NettyServerEPOLLSelector_%d_%d”
M1: “NettyServerCodecThread_”
M2: “RemotingExecutorThread_”
其中,前3个处于RocketMQ的网络层,最后1个是应用层传下去的。
- 分布式消息队列RocketMQ之Netty -- 1+N+M1+M2模型
- 分布式消息队列RocketMQ之Netty -- 1+N+M1+M2模型
- 分布式消息队列RocketMQ与Kafka架构上的巨大差异之1 -- 为什么RocketMQ要去除ZK依赖?
- 分布式消息队列RocketMQ与Kafka架构上的巨大差异之1 -- 为什么RocketMQ要去除ZK依赖?
- 分布式消息队列RocketMQ与Kafka架构上的巨大差异之1 -- 为什么RocketMQ要去除ZK依赖?
- 分布式消息队列RocketMQ与Kafka架构上的巨大差异之1 -- 为什么RocketMQ要去除ZK依赖?
- 分布式消息队列RocketMQ与Kafka架构上的巨大差异之1 -- 为什么RocketMQ要去除ZK依赖?
- 分布式消息队列RocketMQ部署与监控
- 分布式消息队列RocketMQ部署与监控
- 分布式消息队列RocketMQ部署与监控
- 分布式消息队列RocketMQ部署与监控
- 分布式消息队列RocketMQ部署与监控
- 分布式消息队列RocketMQ部署与监控
- 分布式消息队列RocketMQ源码分析之1 -- Topic路由数据结构解析 -- topicRoute与topicPublishInfo与queueId
- 分布式消息队列RocketMQ源码分析之1 -- Topic路由数据结构解析 -- topicRoute与topicPublishInfo与queueId
- 分布式消息队列RocketMQ源码分析之1 -- Topic路由数据结构解析 -- topicRoute与topicPublishInfo与queueId
- 分布式消息队列RocketMQ与Kafka的18项差异之“拨乱反正“之2
- 分布式消息队列RocketMQ与Kafka的18项差异之“拨乱反正“之2
- Error:Execution failed for task ':app:processDebugResources'. > com.android.ide.common.process.Proce
- 算法把rootview中所有的button改变背景
- Linux常用命令
- Oracle---Tip for SQL Database tuning and performance
- mysql获取各种时间段
- 分布式消息队列RocketMQ之Netty -- 1+N+M1+M2模型
- 《TP5.0学习笔记---请求和响应篇》
- IP地址异形
- linux转移/home目录分区与磁盘配额的配置
- CSS背景、尺寸、盒子模型
- 微信服务号开发时获取授权遇到的问题
- 图论题目
- eclipse项目导入到AndroidStudioc报错
- 理解HTTP协议