Netty-2

  • Netty 核心的几个概念
    1. 一个EventLoopGroup当中包含一个或多个EventLoop
    2. 一个EventLoop在它的整个生命周期当中都只会与唯一一个Thread进行绑定
    3. 所有由EventLoop所处理的各种I/O事件都将在它所关联的那个Thread上进行处理
    4. 一个Channel在它的整个生命周期中只会注册在一个EventLoop上
    5. 一个EventLoop在运行过程当中,会被分配到多个Channel
    - 结论:
    1. 在Netty中,Channel的实现一定是线程安全的,基于此,我们可以存储一个Channel的引用,并且在需要向远端发送数据时,通过整个引用来调用Channel的相应方法;即便当时有很多线程都在使用它也不会出现线程问题;而且消息一定会按照顺序发送出去。
    2. 我们在业务开发中,不要将长时间执行的耗时任务放入到EventLoop的执行队列中,因为它将会一直阻塞该线程所对应的所有Channel上的其他执行任务,如果我们需要进行阻塞调用或是耗时的操作,那么我们就需要使用一个专门的EventExecutor(业务线程池)
    3. JDK所提供的Future只能通过手工的方式检查执行结果,而这个操作是会阻塞的;Netty则对ChannelFuture进行了增强,通过ChannelFutureListener以回调的方式获取结果,去除了手工检查的操作(观察者模式);值得注意的是:ChannelFutureListener的operationComplete方法是由I/O线程执行的,因此要注意的是不要在这里执行耗时的操作,否则需要通过另外的线程或线程池来执行。
    4. 在Netty中有两种发送消息的方式,可以直接写到Channel中,也可以写到ChannelHandler所关联的那个ChannelHandlerContext中。对于前一种方式来说,消息会从ChannelPipline的末尾开始流动;对于后一种方式来说,消息将从ChannelPipline中的下一个ChannelHandler开始流动。
    5. ChannelHandlerContext与ChannelHandler之间的关联绑定关系是永远都不会发生改变的,因此对其进行缓存是没有任何问题的。
    6. 对于Channel的同名方法来说,ChannelHandlerContext的方法将会产生更短的事件流,所以我们应该在可能的情况下利用这个特性来提升应用的性能。
    7. 在实际的开发中我们经常会遇到一个服务端可能会去要调用另外一个客户端,这时这个服务端的角色就相当于即作为服务端也作为客户端。这时我们需要注意在我们作为客户端时我们应该将对服务端和客户端的channel绑定在同一个eventLoop上;
    - Netty 提供的三种缓冲区类型
    1. heap buffer 堆缓冲区
    - 优点:由于数据是存储在JVM的堆中,因此可以快速的创建于快速的释放,并且他提供了直接访问内部字节数组的方法
    - 缺点:每次的读写操作,都需要先将数据复制到直接缓冲区中在进行网络传输
    2. direct buffer 直接缓冲区(在堆之外直接分配内存空间,直接缓冲区不会占用堆的容量空间,因为他是由操作系统在本地内存进行的数据分配)
    - 优点:在使用Sockte进行数据传递时,性能非常好,因为数据直接位于操作系统的本地内存中,所以不需要从JVM将数据复制到直接缓冲区,性能很好。
    - 缺点:因为Direct Buffer是直接在操作系统内存中,所以内存空间的分配与释放要比堆空间更加复杂,而且速度慢一些。(Netty通过提供内存池来解决这个问题)
    - 注意:直接缓冲区不支持通过字节数组的方式来直接访问数据(对于后端的业务消息的编解码来说,推荐使用HeapByteBuf;对于I/O通信线程在读写缓冲区时,推荐使用DirectByteBuf)
    3. composite buffer 复合缓冲区
    - JDK的ByteBuffer和Netty的ByteBuf的差异比对
    1. Netty的ByteBuf采用读写索引分离的策略(readerIndex与writerIndex),一个初始化(里面尚未有任何数据)的ByteBuf的readerIndex与witerIndex值都为0
    2. 当读索引和写索引处于同一个位置时,如果我们继续读取,那么就会抛出IndexOutofBoundsException
    3. 对于ByteBuf的任何读写操作都会分别单独维护读索引与写索引。maxCapacity最大的容量默认是 Integer.MAX_VALUE。

         - JDK的ByteBuffer的缺点
            1. final byte[] hb;这是JDK的ByteBuffer对象中用于存储数据的对象声明;可以看到,其字节数组是被声明为final的,也就是长度是固定不变的。一旦分配好就不能动态扩容与收缩。而且当待存储的数据字节很大时就很有可能出现 IndexOutofBoundsException 。如果需要预防这个异常,那就需要在存储之前完全确定好待存储的字节大小。如果ByteBuffer的空间不足,我们只有一种解决方案;创建一个全新的ByteBuffer对象,然后将之间的ByteBuffer中的数据复制过去,这一切的操作都需要开发者自己手动完成。
            2. ByteBuffer只使用一个position指针来标识位置信息,在进行读写切换时就需要调用flip方法或是rewind方法,使用起来不方便。
    
         - Netty的ByteBuf的优点
            1. 存储的字节数组是动态的,其最大值的默认是Integer.MAX_VALUE。这里的动态性体现在write方法中的。write方法在执行时会判断buffer的容量,如果不足则自动扩容。
            2. ByteBuf的读写索引是完全分开的,使用起来就很方便。
    
      - 引用计数
         1. netty采用自旋锁的方式来进行操作(io.netty.util.AbstractReferenceCounted)
            ```java
               // 更新特定的字段
               private static final AtomicIntegerFieldUpdater<AbstractReferenceCounted> refCntUpdater =
                     AtomicIntegerFieldUpdater.newUpdater(AbstractReferenceCounted.class, "refCnt");
    
               private volatile int refCnt = 1;
               ...
    
               private ReferenceCounted retain0(int increment) {
                  for (;;) {
                        int refCnt = this.refCnt;
                        final int nextCnt = refCnt + increment;
    
                        // Ensure we not resurrect (which means the refCnt was 0) and also that we encountered an overflow.
                        // 这里的判断有两个意义 
                        // nextCnt==increment 表示refCnt=0 这在netty中对于引用计数的定义是:如果一个对象的引用计数为0则这个引用对象不能使用
                        // nextCnt < increment 成立则表示 nextCnt是负数 说明已经超过最大的整数值了
                        if (nextCnt <= increment) {
                           throw new IllegalReferenceCountException(refCnt, increment);
                        }
                        if (refCntUpdater.compareAndSet(this, refCnt, nextCnt)) {
                           break;
                        }
                  }
                  return this;
                }
    
            ```  
    
    1. AtomicIntegerFieldUpdater 要点总结
      1. 更新器更新的必须是int类型变量,不能是其包装类型
      2. 更新器更新的必须是 volatile类型变量,确保线程之间共享变量时的立即可见性。
      3. 变量不能是static的,必须是实例变量。因为Unsafe.objectFiledOffset()方法不支持静态变量(CAS操作本质上是通过对象实例的偏移量来直接进行赋值)
      4. 更新器只能修改它可见范围的变量,因为更新器是通过反射来得到这个变量,如果变量不可见就会报错。
      5. 如果需要更新的变量时包装类型或者是其他类型,可以使用 AtomicReferenceFieldUpdater来进行更新
      3. Netty内存泄漏检测
      4. Netty的处理器和编解码器
      1. Netty的处理器分为两类 入站处理器、出站处理器
      2. 入站处理器的顶层是 ChannelInboundHandler,出站处理器的顶层是ChannelOutboundHandler
      3. 数据处理时常用的各种编解码器本质上都是处理器。
      4. 编解码器:编码器,解码器。无论我们想网络中写入的数据是什么类型(int,char,String,二进制等),数据在网络中传递时,其都是以字节流的形式呈现的;将数据由原来的形式转换为字节流的操作称为编码(encode),将数据由字节转换成它原本的格式或是其他格式的操作称为解码(decode),编解码统一称为codec。
      5. 编码:本质上是一种出站处理器。因此,编码一定是 ChannelOutboundHandler。
      6. 解码:本质上是一种入站处理器,因此解码一定是 ChannelInboundHandler。
      7. 在Netty中,编码器通常以 XXXEncoder命名,解码器通常以XXXDecoder命名。
      8. TCP粘包与拆包
      5. 结论:
      1. 无论是编码器还是解码器,其所接收的消息类型必须要与待处理的参数类型一致,否则该编码器或解码器并不会被执行。
      2. 在解码器进行数据解码时,一定要记得判断缓冲(ByteBuf)中的数据是否足够,否则将会产生一些问题。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,377评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,390评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,967评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,344评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,441评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,492评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,497评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,274评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,732评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,008评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,184评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,837评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,520评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,156评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,407评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,056评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,074评论 2 352

推荐阅读更多精彩内容

  • 作者:李林锋 原文:http://www.infoq.com/cn/articles/netty-high-per...
    杨鑫科阅读 3,969评论 0 64
  • 原文地址:http://netty.io/wiki/reference-counted-objects.html ...
    linkinparkzlz阅读 1,530评论 0 0
  • 前言 本篇文章主要分析Netty的系统结构以及其如何实现其对外宣称的特色,如果还未了解Netty的基础知识,最好先...
    简xiaoyao阅读 4,896评论 0 13
  • 10月26号星期六今天是上中周末的第二天,我们集体被下课。刚还沉浸在今天练习的收获中,全体下课来的这么突然,先是有...
    王巍巍阅读 219评论 5 1
  • 妻发现夫有段时间里不对劲,有时在下班点接她电话不慌不忙,没多久便回到家。有时却随便应付一句半句挂断电话,让她一头雾...
    尔东木易阅读 579评论 2 3