Netty
库昊天
这个作者很懒,什么都没留下…
展开
-
Netty内存管理
PoolChunk作用: 8K - 16M范围的内存分配,分配容量为PageSize的整数倍,PageSize默认为8K;基本概念maxOrder:二叉树的最大深度;chunkSize:PoolChunk的容量,默认为16M,即根节点的可分配容量;chunkSize = PageSize * 2^maxOrder内存管理 Page是PoolChunk内存管理的基本单元,PoolChunk通过完全二叉树的方式管理内存,如下图所示,每个节点的可分配内存为其包含的叶子节点内存之和,内存分配分为两原创 2020-07-20 11:21:26 · 332 阅读 · 0 评论 -
Netty编解码框架
Netty逻辑架构Netty解码器类体系 解码器的基类为ByteToMessageDecoder,如果通过继承ByteToMessageDecoder来自定义解码器则需要自己处理“粘包与拆包”的问题,因此一般建议继承更高级的解码器,如下图所示: LineBasedFrameDecoder解码器 LineBasedFrameDecoder是回车换行解码器,如果用户发送的...原创 2018-05-02 20:12:29 · 479 阅读 · 0 评论 -
TCP粘包和拆包
概念粘包:TCP层将应用层多个小的数据包封装成一个大的数据包发送出去;拆包:TCP层将应用层一个大的数据包拆分成多个小的数据包发送出去;原因 TCP层并不感知应用层数据包的具体含义,它会根据TCP缓冲区实际情况进行包的划分,所以对于应用层来说,一个完整的数据包可能会被TCP拆分成多个包进行发送,也可能被合并装成一个大的数据包发送。 解决方案 由于TCP不感知应用...原创 2018-05-02 19:18:42 · 211 阅读 · 0 评论 -
服务端启动流程
一、创建线程池 服务端启动时,首先创建两个线程池:boss线程池和worker线程池。boss线程池用于监听客户端的连接请求;worker线程池即IO线程池,用于处理IO读写操作,及一些定时任务等。二、ServerSocketChannel的创建、初始化和注册2.1创建触发时机:调用ServerBootstrap的端口绑定接口doBind()时; 2.2...原创 2018-04-24 10:40:20 · 472 阅读 · 1 评论 -
为什么Netty使用NIO而不是AIO?
NIO VS AIO理论上,AIO是真正的异步IO,IO吞吐量是要高于NIO的。两种IO模式的概念如下:NIO:IO复用模型,仍是阻塞IO,通过复用IO线程提升吞吐量;AIO:线程A执行IO操作时,注册回调函数,当IO操作执行完成后,内核通知应用层,由线程B执行回调逻辑;为什么Netty使用NIO而不是AIO?原因:在Linux系统上,AIO的底层实现仍使用EPOLL,与...原创 2018-04-23 17:39:14 · 7924 阅读 · 4 评论 -
Netty之close()过程
关闭流程pipeline.close() –> TailContext.close –> handler.close() –> HeadContext.close() –> AbstractUnsafe.close() –> pipeline.fireChannelInactive(); 如下图所示,如果channel执行close前是存活的,那么会触发fireChannelInactive()方原创 2018-02-06 19:32:47 · 3939 阅读 · 0 评论 -
Netty学习资料
李林峰InfoQ系列:http://www.infoq.com/cn/profile/%E6%9D%8E%E6%9E%97%E9%94%8B#占小狼系列:https://www.jianshu.com/u/90ab66c248e6江南白衣系列:http://calvin1978.blogcn.com/articles/netty-info.htmlNetty主创个人主页:http://norm原创 2018-02-04 17:37:09 · 420 阅读 · 0 评论 -
Netty之TCP参数设置
TCP_NODELAY 解释:是否启用Nagle算法,改算法将小的碎片数据连接成更大的报文来最小化所发送的报文的数量。 使用建议:如果需要发送一些较小的报文,则需要禁用该算法,从而最小化报文传输延时。只有在网络通信非常大时(通常指已经到100k+/秒了),设置为false会有些许优势,因此建议大部分情况下均应设置为true。SO_LINGER 解释: Socket参数,关原创 2018-01-28 12:13:24 · 12294 阅读 · 0 评论 -
OP_ACCEP、OP_READ和OP_WRITE的注册
OP_ACCEP注册 首先,ServerSocketChannel创建时就指定感兴趣事件OP_ACCEPT;然后,在注册阶段,直接向Selector注册OP_ACCEPT; public NioServerSocketChannel(ServerSocketChannel channel) { super(null, channel, SelectionKey.OP_ACCE原创 2018-05-03 15:33:46 · 2161 阅读 · 0 评论 -
ChannelPipeline特性
创建时机每个Channel对应一个ChannelPipeline,在Channel被创建时生成; protected AbstractChannel(Channel parent) { this.parent = parent; unsafe = newUnsafe(); pipeline = new DefaultChannelP...原创 2018-05-03 11:18:11 · 449 阅读 · 0 评论 -
ChannelHandler
类体系线程安全 ChannelHandler的线程安全性取决于具体的实现,如果线程安全则不同的ChannelPipeline间可以共享,避免每个Channel创建一个ChannelHandler实例;如果线程不安全,则需要为每个Channel创建一个ChannelHandler实例,避免锁竞争带来的损耗;原创 2018-05-03 14:11:36 · 291 阅读 · 0 评论 -
PoolArena
数据结构分配过程首先,对要请求的容量进行规整化;如果是tiny\small\normal类型的容量,优先使用线程中缓存的空间,若无法分配再从PoolArena分配;如果是huge类型的容量,PoolArena不再支持,需要从JVM中申请空间;参考:https://gsmtoday.github.io/2017/09/03/netty-memory-pool-md/...原创 2018-08-08 16:12:15 · 220 阅读 · 0 评论 -
PoolChunk
转载:https://gsmtoday.github.io/2017/08/27/poolchunk/数据结构 PoolChunk逻辑上是一颗完全平衡二叉树,代码实现上用数组表示,如下所示: 初始化逻辑 数组下标表示二叉树中各节点的编号id,数组元素内容表示当前节点可分配内存的子节点(即未分配)在二叉树中的深度,如下所示: memoryMap = new...转载 2018-08-08 12:02:31 · 176 阅读 · 0 评论 -
PooledByteBufAllocator
作用 池化的ByteBuf分配器,提供统一的ByteBuf分配服务;内存分配算法:jemallocPooledByteBufAllocator采用了jemalloc内存分配算法,大致思想如下:为了降低锁竞争,将池化空间划分为多个PoolArena,每个线程按照负载均衡算法绑定到特定的PoolArena;为了进一步降低同一个PoolArena不同线程间的锁竞争,每个线程内部增加...原创 2018-08-07 19:30:49 · 1449 阅读 · 0 评论 -
PoolThreadCache
缓存构成 PoolThreadCache的缓存由三部分构成:tiny、small 和 normal。tiny 缓存数据大小区间为[16B, 496B]数据,数组长度为32,根据数据大小计算索引的办法:数据大小除以16,如下代码所示:static int tinyIdx(int normCapacity) { return normCapacity >>...原创 2018-08-07 17:18:09 · 365 阅读 · 0 评论 -
Netty资源泄露检测ResourceLeakDetector
资源泄露 ByteBuf不再使用后(没有引用),没有调用release,导致ByteBuf资源一直被占用无法回收。检测原理原理:每次创建ByteBuf时,创建一个虚引用对象A指向该ByteBuf对象,如果正常调用release()操作,则虚引用对象A和ByteBuf对象均被回收;如果ByteBuf对象不再使用(没有其他引用)但没有调用release()操作,则GC时虚引用对象A被加入Referen原创 2018-04-28 19:38:30 · 3567 阅读 · 0 评论 -
AdaptiveRecvByteBufAllocator
作用 分配一个具有合理初始容量的ByetBuf对象,避免初始容量不合理(过小导致的频繁扩容,过大导致的空间浪费)导致的GC频率加快。 原理原理:根据之前Channel接收到的数据报文大小进行计算,如果之前ByteBuf被填满,则扩展当前容量;如果连续2次接收到的数据报都小于指定值,则收缩当前的容量,以节约内存。下图为ByteBuf的容量随index的变化曲线,当实际占用的容量超过之前预分配的容量原创 2018-04-26 19:13:36 · 1496 阅读 · 0 评论 -
ChannelOutboundBuffer
创建时机 Unsafe实例被创建,即创建Channel时,ChannelOutboundBuffer被创建,每个Channel实例对应一个ChannelOutboundBuffer实例。 数据结构 ChannelOutboundBuffer实质上是无界的单向链表,如下图所示: write&flushwrite本质:将待发送数据写入ChannelOutb...原创 2018-05-04 12:05:00 · 1126 阅读 · 0 评论 -
ChannelConfig
类体系Channel通用参数CONNECT_TIMEOUT_MILLIS:连接超时时间,默认30s;ALLOCATOR:ByteBuf分配器,默认为PooledByteBufAllocator;RCVBUF_ALLOCATOR:接受缓冲区分配器,默认为AdaptiveRecvByteBufAllocator;AUTO_READ:当Channel的接受缓冲区有数据时,是否自动产生OP_READ原创 2018-05-03 17:20:44 · 917 阅读 · 0 评论 -
FastThreadLocal
ThreadLocalThreadLocal读写过程: 1. 获取当前线程的ThreadLocalMap,即Entry数组; 2. 根据ThreadLocal变量的哈希值确定槽位slot; 3. 若发生哈冲突则依次向后遍历数组直至不再冲突; 优点:节省空间,数组空间利用率高; 缺点:发生冲突时会线性遍历数组,导致性能下降,不适用于一个线程存在多个ThreadL原创 2018-01-26 19:19:37 · 368 阅读 · 0 评论 -
堆外内存
堆外内存定义 创建Java.nio.DirectByteBuffer时分配的内存。堆外内存优缺点 优点: 提升了IO效率(避免了数据从用户态向内核态的拷贝);减少了GC次数(节约了大量的堆内内存)。 缺点:分配和回收堆外内存比分配和回收堆内存耗时;(解决方案:通过对象池避免频繁地创建和销毁堆外内存)为什么堆外内存能够提升IO效率? 堆内内存由JVM管理,...原创 2017-09-06 20:06:51 · 6327 阅读 · 1 评论 -
基于Netty的长连接客户端
客户端工厂import java.util.List;/** * 接口描述:长连接客户端工厂类 * * @author ruipeng.lrp * @since 2017/11/26 * **/public interface ClientFactory { // ------------ 查询和新增 ------------ Client get(final Re原创 2017-11-27 15:50:21 · 8983 阅读 · 1 评论 -
Java NIO之SelectorProvider
Selector工厂方法SelectorProvider创建规则如下图所示: 1. 首先尝试加载系统属性java.nio.channels.spi.SelectorProvider指定的实现类,并实例化,如下图所示: 2. 其次使用SPI机制进行服务发现,如下图所示: 3. 最后使用JDK默认实现DefaultSelectorProvider;DefaultSelecto原创 2017-12-11 11:23:40 · 1250 阅读 · 0 评论 -
Netty之轻量级对象池Recycler
为什么说Recycler是“轻量级”的对象池? 功能简单:对象池只提供了创建和回收的基本接口,没有复杂的诸如有效性检测、空闲回收和拒绝策略等一些复杂功能。 逻辑简单:实现逻辑清晰简单,没有复杂的算法逻辑。Recycler核心方法get(): 获取一个对象;recycle(T, Handle): 回收一个对象,T为对象泛型;newObject(Handle): 当没有可用对象时创建对象的实现原创 2017-09-12 20:37:02 · 795 阅读 · 0 评论 -
Netty基础之新集合
ConcurrentSet: 并发的set集合,本质利用ConcurrentMap实现,所有的key指向同一value; MpscLinkedQueue:无锁的并发队列,适用于多生产者单消费者的场景,新的版本已经采用JCTools的并发队列实现了;原创 2017-09-11 10:19:57 · 501 阅读 · 0 评论 -
Netty之writeAndFlush()流程
Netty之writeAndFlush()流程整体步骤:先write再flushwrite流程ctx.writeAndFlush() –> TailHandler –> Handler … —> HeadHandler –> Unsafe.write() write方法实际上并没有将消息写出去, 而是将消息msg和此次操作的promise放入到当前连接的输出缓冲区OutboundBuffer中了;原创 2017-09-06 17:57:29 · 5153 阅读 · 0 评论 -
Netty之ByteBuf的创建和释放
ByteBuf的创建时机OP_READ事件产生后,IO线程会在AbstractNioByteChannel.NioByteUnsafe.read() 处调用ByteBufAllocator创建ByteBuf,将TCP缓冲区的数据读取到Bytebuf中,并调用 pipeline.fireChannelRead(byteBuf) 进入Handler处理链。 ByteBuf的释放原则由最后使用ByteB原创 2017-09-06 16:34:39 · 5921 阅读 · 0 评论 -
EventExecutor筛选策略
背景:一个EventExecutorGroup由多个EventExecutor组成,每次从EventExecutorGroup中获取EventExecutor的逻辑由EventExecutorChooser决定,主要有两种策略。实现逻辑 首先判断数组容量是否为2的幂次方,若是,通过位运算提高计算效率。编程技巧:2的幂次方的判断;取余时,整数溢出时的考虑与处理;import java.util原创 2018-01-02 15:23:29 · 638 阅读 · 1 评论 -
writeAndFlush之发送速率不匹配
背景知识如果业务线程调用writeAndFlush()发送消息,会生成WriteAndFlushTask,交由IO线程处理,write操作将消息写入ChannelOutboundBuffer,flush操作将ChannelOutboundBuffer写入socket的发送缓冲区;ChannelOutboundBuffer是单向链表,没有容量限制;速率不匹配造成的问题 如下图所示,当业务线程产原创 2018-01-21 17:48:22 · 3662 阅读 · 3 评论 -
Netty网络处理之客户端主动关闭
TCP状态变化 应用层及时关闭连接:ESTABLISHED –> CLOSE_WAIT –> LAST_ACK –> CLOSED; 应用层未在指定时间内关闭连接:ESTABLISHED –> CLOSE_WAIT –> CLOSED; Netty处理过程 TCP状态进入CLOSE_WAIT时会产生OP_READ事件通知应用层,Netty从socket读取数据时返回-1,close被设为原创 2018-01-18 09:54:43 · 23830 阅读 · 2 评论 -
Native transports
介绍 Netty Native用C++编写JNI调用的Socket Transport,与JDK的NIO相比,GC更少,性能更高。Netty Native高性能Netty的 epoll transport使用 edge-triggered 而 JDK NIO 使用 level-triggered;更少GC,更少synchronized;暴露了更多的Socket配置参数,见E原创 2018-01-31 20:29:49 · 684 阅读 · 0 评论 -
Netty之更高效的计数器
import java.util.concurrent.atomic.AtomicLongFieldUpdater;/** * 类说明:内存节约型计数器 * * @author ruipeng.lrp * @since 2018/1/31 **/public class MemoryEffectiveCounter { private static final AtomicLo原创 2018-01-31 18:50:29 · 362 阅读 · 0 评论 -
Netty之引用计数器
转载:http://calvin1978.blogcn.com/articles/netty-leak.html引用计数器的必要性 在内存池的场景中,ByteBuf不再使用时需要主动归还给内存池;引用计数器相关知识ByteBuf被创建时,引用计数的初始值为1;调用release(),计数器减1,当计数器等于零时, deallocate()被调用,回收资源;调用release()或者retai转载 2018-01-31 16:59:16 · 464 阅读 · 1 评论 -
Netty的Future机制
Future与Promise类继承关系 如下图所示,Netty Future在JDK Future基础上,新增监听器功能;Netty Promise在Netty Future基础上新增设置成功和失败的功能。 Future的本质get():利用Object的wait()方法阻塞;cancel():利用Object的notifyAll(0方法唤醒线程;原创 2018-01-31 14:09:30 · 1365 阅读 · 0 评论 -
Netty网络处理之客户端宕机
客户端宕机时的网络处理流程客户端的应用进程挂掉时,其所在操作系统会清理进程绑定的资源,关闭连接时产生RST信号,通知对端;服务端接受到信号后,IO复用模型如Epoll产生读事件;应用进程通过Selector多路复用器感知到读事件,产生OP_READ;IO线程从对应的连接中读取数据,抛出IOException;首先,触发exceptionCaught方法,处理异常;其次,触发ch原创 2018-01-16 11:25:09 · 1427 阅读 · 0 评论 -
业务线程与IO线程的隔离
线程模型 隔离的好处:职责明确化。IO线程只负责IO的读写、编解码和心跳等简单功能,以便及时高效处理IO事件;业务线程负责复杂的业务处理;降低客户端间的相互影响。对于同一IO线程,避免了由于执行客户端A的请求阻塞而无法接受客户端B的请求等现象;原创 2018-01-23 21:05:18 · 3689 阅读 · 3 评论 -
自适应流控方案
入口流控自适应方案问题:在Netty中引入业务线程池带来的问题就是速率不匹配,如果IO线程接受数据的速度超过业务线程的处理速度,就会出现缓冲队列溢出,此时需要能够对客户端的发送速率进行控制。 如下图所示,提供了一种基于TCP Flow-Control机制的自适应流控方案。当缓冲区溢出时,服务端会按一定的规则选取出最消耗业务线程资源的客户端,然后将客户端对应连接的auoread属性设置为f原创 2018-01-23 14:28:40 · 904 阅读 · 0 评论 -
Netty之定时任务
基于Netty添加定时任务时,不要使用JDK的ScheduledExecutorService,直接向连接所属的IO线程添加:ctx.executor().schedule(new TimeoutTask(p), 30, TimeUnit.SECONDS)。原因如下:首先,JDK的ScheduledExecutorService是一个大池子,多线程争抢并发锁。而上面的写法,TimeoutT原创 2017-09-06 17:03:33 · 6992 阅读 · 0 评论