4.通信层
来源:互联网 发布:windows phone 8.1 编辑:程序博客网 时间:2024/05/30 04:27
- 概述
- rocketmq通信层采用netty来实现,netty是nio socket的一个框架
- nio vs io
区别
io nio nio优势 nio缺点 面向流面向缓冲面向缓冲区的编程方式流式处理数据直观,优雅,nio不具备这些优点阻塞非阻塞数据不可获取时不进行等待,节省线程获取数据可能只获取到一部分,达不到处理标准,编程不直观
- nio socket vs io
- 阻塞io:适用于连接少,发送大量数据
- 非阻塞io:适用于连接多,发送少量数据
- 阻塞io:适用于连接少,发送大量数据
- nio selector
- 用于监听多个通道的事件,比如连接打开,数据到达等
- 一个线程即可监听各个通道的状态,然后再结合nio的非阻塞特性,可以大大减少服务器的线程资源消耗。
- 用于监听多个通道的事件,比如连接打开,数据到达等
- rocketmq中netty的使用与参数设置
broker端 com.alibaba.rocketmq.remoting.netty.NettyRemotingServer.start
ServerBootstrap childHandler = this.serverBootstrap.group(this.eventLoopGroupBoss, this.eventLoopGroupWorker)//前者为1个线程的线程池,用于处理客户端连接建立事件,后者为3个线程的线程池,用于处理已经建立连接的io事件 .channel(NioServerSocketChannel.class)//为客户端连接事件创建连接 .option(ChannelOption.SO_BACKLOG, 1024)//最大连接数 参见java.net.ServerSocket.ServerSocket(int port, int backlog) .option(ChannelOption.SO_REUSEADDR, true)//之前的连接处于timeout状态,新可以使用该地址 参见java.net.ServerSocket.setReuseAddress(boolean on) .option(ChannelOption.SO_KEEPALIVE, false)//不开启长连,参见java.net.SocketOptions.SO_KEEPALIVE .childOption(ChannelOption.TCP_NODELAY, true)//对此连接禁用 Nagle算法,参见java.net.SocketOptions.TCP_NODELAY .option(ChannelOption.SO_SNDBUF, nettyServerConfig.getServerSocketSndBufSize())//网络发送基础缓冲区建议大小,值为65535,参见java.net.SocketOptions.SO_SNDBUF .option(ChannelOption.SO_RCVBUF, nettyServerConfig.getServerSocketRcvBufSize())//网络接收基础缓冲区建议大小,值为65535,参见java.net.SocketOptions.SO_RCVBUF .localAddress(new InetSocketAddress(this.nettyServerConfig.getListenPort()))//设置监听端口 .childHandler(new ChannelInitializer<SocketChannel>() {@Overridepublic void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(//为当前channel的pipeline添加自定义处理器defaultEventExecutorGroup, //默认为8个线程的线程池new NettyEncoder(), //输出数据时进行编码new NettyDecoder(), //输入数据时进行解码new IdleStateHandler(0, 0, nettyServerConfig .getServerChannelMaxIdleTimeSeconds()),//默认120秒检测一次连接是否空闲new NettyConnetManageHandler(), // 处理连接事件,建立,断开等等new NettyServerHandler()); //处理请求,根据请求码(com.alibaba.rocketmq.common.protocol.RequestCode)来查找相应的处理器,处理请求,处理器注册参考类com.alibaba.rocketmq.broker.BrokerController.registerProcessor} });try { ChannelFuture sync = this.serverBootstrap.bind().sync();//创建channel,绑定端口,等待返回 InetSocketAddress addr = (InetSocketAddress) sync.channel().localAddress(); this.port = addr.getPort();}catch (InterruptedException e1) { throw new RuntimeException("this.serverBootstrap.bind().sync() InterruptedException", e1);}
几个tcp参数释义:http://www.open-open.com/lib/view/open1412994697952.html
client端 com.alibaba.rocketmq.remoting.netty.NettyRemotingClient.start
Bootstrap handler = this.bootstrap.group(this.eventLoopGroupWorker)//默认为1个线程的线程池,处理channel中的io事件 .channel(NioSocketChannel.class)//与ServerBootstrap一致 .option(ChannelOption.TCP_NODELAY, true)//与ServerBootstrap一致 .option(ChannelOption.SO_KEEPALIVE, false)//与ServerBootstrap一致 .option(ChannelOption.SO_SNDBUF, nettyClientConfig.getClientSocketSndBufSize())//与ServerBootstrap一致 .option(ChannelOption.SO_RCVBUF, nettyClientConfig.getClientSocketRcvBufSize())//与ServerBootstrap一致 .handler(new ChannelInitializer<SocketChannel>() {public void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(//defaultEventExecutorGroup, //默认为4个线程的线程池new NettyEncoder(), //与ServerBootstrap一致new NettyDecoder(), //与ServerBootstrap一致new IdleStateHandler(0, 0, nettyClientConfig.getClientChannelMaxIdleTimeSeconds()),//与ServerBootstrap一致new NettyConnetManageHandler(), //与ServerBootstrap类似new NettyClientHandler());//处理请求,根据请求码(com.alibaba.rocketmq.common.protocol.RequestCode)来查找相应的处理器,处理请求,处理器注册参考类com.alibaba.rocketmq.client.impl.MQClientAPIImpl的初始化方法,处理器为com.alibaba.rocketmq.client.impl.ClientRemotingProcessor} });
- com.alibaba.rocketmq.remoting.netty.NettyDecoder继承自LengthFieldBasedFrameDecoder
即根据长度来解析数据,此类关键的几个属性如下:int maxFrameLength//最大数据长度,超出抛异常,默认为8M
int lengthFieldOffset//数据长度起始偏移量,默认为0
int lengthFieldLength//数据长度长度,默认为4
int lengthAdjustment//数据长度调节量,默认为0
int initialBytesToStrip//数据解码时移除的字节量,默认为4示例如下: 原始数据 解码后 + | | |+-----------v+--------------+ +------v-------+| | | | || 0x0000000C | HELLO, WORLD +-----> HELLO, WORLD || | | | |+------------+--------------+ +--------------+0x0000000C占4个字节,十进制为12解码过程如下:1 根据lengthFieldOffset,从第1个字节开始读取2 根据lengthFieldLength,读取4个字节,此时知道数据的长度为12个字节,但是不知道该数据是否包含的包头的长度3 根据lengthAdjustment,可知长度不用调整,就是12个字节都是后面数据的长度4 根据initialBytesToStrip,需要将前面的4个字节舍去,即只剩12个字节 再举个例子说明一下:lengthFieldOffset = 1lengthFieldLength = 2 lengthAdjustment = 1 initialBytesToStrip = 3BEFORE DECODE (16 bytes) AFTER DECODE (13 bytes) +------+--------+------+----------------+ +------+----------------+ | HDR1 | Length | HDR2 | Actual Content |----->| HDR2 | Actual Content | | 0xCA | 0x000C | 0xFE | HELLO, WORLD | | 0xFE | HELLO, WORLD | +------+--------+------+----------------+ +------+----------------+ 1 根据lengthFieldOffset,从第二个字节开始读取2 根据lengthFieldLength,读取两个字节,此时知道数据的长度为12,但是并不知道数据是否包含包头的长度3 根据lengthAdjustment,可知长度需要调整,即12+1为13,数据长度调整为134 根据initialBytesToStrip,需要将前面的3个字节舍去,即只剩 HDR2+实际内容的长度
- rocketmq中数据的传输方式在netty中的实现:参见com.alibaba.rocketmq.remoting.netty.NettyRemotingAbstract
netty中传输数据:
channel.writeAndFlush(request).addListener(new ChannelFutureListener() {//listener在数据返回后执行,不会阻塞当前线程public void operationComplete(ChannelFuture f) throws Exception { //处理返回的结果}});
同步
channel.writeAndFlush(request).addListener(new ChannelFutureListener() {//listener在数据返回后执行,不会阻塞当前线程public void operationComplete(ChannelFuture f) throws Exception { //处理返回的结果 countDownLatch.countDown();}});countDownLatch.await(timeoutMillis, TimeUnit.MILLISECONDS);
异步
boolean acquired = Semaphore.tryAcquire(timeoutMillis, TimeUnit.MILLISECONDS)//使用信号量限制异步方式的调用,实现超时机制和防止netty缓存请求过多channel.writeAndFlush(request).addListener(new ChannelFutureListener() {//listener在数据返回后执行,不会阻塞当前线程public void operationComplete(ChannelFuture f) throws Exception { //处理返回的结果 InvokeCallback.operationComplete(ResponseFuture responseFuture) Semaphore.release();//信号量释放}});
oneway
boolean acquired = Semaphore.tryAcquire(timeoutMillis, TimeUnit.MILLISECONDS)//使用信号量限制oneway方式的调用,实现超时机制和防止netty缓存请求过多if(acquired){channel.writeAndFlush(request).addListener(new ChannelFutureListener() {//listener在数据返回后执行,不会阻塞当前线程public void operationComplete(ChannelFuture f) throws Exception { //处理返回的结果 Semaphore.release();//信号量释放} });}
0 0
- 4.通信层
- 不同层相互通信
- 通信层代码分析
- 内核层与应用层通信详解
- 驱动层和应用层进行通信
- 应用层和内核层通信
- 应用层与驱动层通信DeviceIoControl
- Heartbeat 通信层结构分析
- Heartbeat 通信层结构分析
- android native层进程通信
- 通信的五层模型
- 网络通信层搭建+https
- Android应用层通信机制
- Android从驱动层到应用程序层的通信
- Android从驱动层到应用程序层的通信
- Android从驱动层到应用程序层的通信
- 应用层与驱动层通信---内核中的加法运算
- 驱动层与应用层通信的实现
- JVM内存区域详解(Eden Space、Survivor Space、Old Gen、Code Cache和Perm Gen)
- 调度策略
- easyUI在可编辑的datagrid中加入combogrid 实现下拉选择填充列
- join方法的理解
- Javascript定义类(class)的三种方法
- 4.通信层
- APP漏洞自动化扫描专业评测报告(下篇)
- 数字转字母顺序 JS实现
- nginx安装配置
- Python核心模块方法
- 大数据系列修炼-Scala课程35
- 使用 Date 和 SimpleDateFormat 类表示时间
- PopupWindow的使用
- 大数据系列修炼-Scala课程36