跟着彤哥学netty
2021-04-14 06:53:48 0 举报
AI智能生成
email data flow
作者其他创作
大纲/内容
BIO和NIO详解
IO Block定义
网络IO:系统调用read从socket读取一段数据
linux无法知道网路是否会发数据,只能等,block
磁盘IO:系统调用read从磁盘文件读一段数据到内存
不算block
BIO
定义
网络调用 read write connect 系统会被卡主
例子
解决方案
开启多线程
优点
提升并发能力
减少网络io阻塞
缺点
线程越多导致Context Switch 多,上下文频繁切换,浪费CPU
浪费内存
开启线程会在本线程创建线程栈,1个线程1m内存1000个占用1g内存
多线程阻塞效率低,阻塞后线程内无法做其他事
线程池?
限制了最大并发数,无法响应更多请求
NIO
定义
Non-Blocking,不阻塞
区别
BIO
调用read,数据没到,就会阻塞
NIO
调用read,数据没到,返回-1,并且errno 被设为EAGAIN
代码
原理
程序轮询,不断尝试有没有数据到达,有了就处理,没有就过一会再试
优点
程序不会卡死,可以做一些其他的事情
缺点
一次只能read一次,大量文件描述符出现,就会带来用户态和核心态频繁切换
等待时间不好确定,太短耗费cpu,等待时间太长响应时间过长
IO多路复用
机制
程序注册一组socket文件描述符给操作系统,表示我要监视这些fd是否有IO事件,有了就告诉程序处理
使用方式
NIO和IO多路复用一起使用
误解
❌多个数据流共享同一个socket
说的是多个socket,只不过是操作系统一起监听多个事件
❌IO多路复用是NIO,总是不Block的
(select,poll,epoll_wait)总是Block的
❌IO多路复用和NIO一起减少了IO
IO本身(网络数据的收发)无论用不用IO多路复用和NIO,都没有变化。请求的数据该是多少还是多少;网络上该传输多少数据还是多少数据。IO多路复用和NIO一起仅仅是解决了调度的问题,避免CPU在这个过程中的浪费,使系统的瓶颈更容易触达到网络带宽,而非CPU或者内存。要提高IO吞吐,还是提高硬件的容量(例如,用支持更大带宽的网线、网卡和交换机)和依靠并发传输(例如HDFS的数据多副本并发传输)。
调用接口
select
处理方式
缺点
长度限制
监听三个数组,复制到内核
挨个遍历fd
无状态,重复操作
poll
代码
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
优点
不再有3个数组,而是1个polldfd结构的数组了
数组的个数也没有了1024的限制
缺点
依然是无状态的,性能的问题与select差不多一样;
应用程序仍然无法很方便的拿到那些“有事件发生的fd“,还是需要遍历所有注册的fd。
epoll
epoll_create
代码
int epfd = epoll_create(10);
原理
为什么创建一个文件描述符来指向表
有状态
共享epoll数据
epoll_ctl
代码
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
传参解释
op 表示如何对文件名进行操作
EPOLL_CTL_ADD - 注册一个事件
EPOLL_CTL_DEL - 取消一个事件的注册
EPOLL_CTL_MOD - 修改一个事件的注册
EPOLL_CTL_DEL - 取消一个事件的注册
EPOLL_CTL_MOD - 修改一个事件的注册
第三个参数是要操作的fd,这里必须是支持NIO的fd(比如socket)。
第四个参数是一个epoll_event的类型的数据,表达了注册的事件的具体信息
epoll_wait
概念
使用epoll_wait来等待事件的发生。
代码
int epoll_wait(int epfd, struct epoll_event *evlist, int maxevents, int timeout);
特点
block
只返回被触发的fd
完整代码
写法
注册——监听事件——处理——再注册,无限循环下去
优势
select 和epoll 方式
每次传入fd,需要内核从头到尾扫描
返回所有事件的fd
时间复杂度 O(所有注册事件fd的数量)
epoll方式
提前在内核创建好数据,存在红黑树里,内核有事件就查找红黑树并标记
只返回有事件的fd
时间复杂度:O(发生事件fd的数量)
支持水平触发和边沿触发
水平触发
概念
关心fd中有没有没完成的数据
java的nio是水平触发
边沿触发
概念
关心有没有新的事件
为什么需要
为开发者提供灵活性
缺点
提高编程难度,容易丢失属于处理的数据
不重置fd fd永远没有新事件产生
缺点
发生事件的fd=所有注册fd的数量
epoll=poll
Block
出现block的场景
网络ioblock
磁盘io block
复杂处理 block
bug block
web proxy
瓶颈
web server
瓶颈
NIO的核心组件
Channel
定义
IO操作的连接
类型
FileChannel
DatagramChannel
SocketChannel
ServerSocketChannel
Buffer
定义
存放特定基本类型数据的容器
特点
线性的,有序的序列
属性
capacity
limit
position
为什么要和channel一起使用
火车运煤的例子
煤->数据
箱子->Buffer
火车->TCP协议
滑板车->UDP协议
铁路-> Channel
NIO和BIO传输方式的区别
传输方式
NIO:面向Channel或面向缓冲区
BIO:面向流
传输方向
NIO:双向的,可读可写
BIO:单向的,分InputStrem和OutPutStrem
类型
ByteBuffer
HeapByteBuffer
堆内存实现
DirectByteBuffer
直接内存实现
CharBuffer
ShortBuffer
IntBuffer
LongBuffer
FloatBuffer
DoubleBuffer
属性
capacity
limit
position
使用方法
allocate ()
buf.put () 或者 channel.read (buf)
buf.flip()
buf.read /channel,wiite(buf)
rewind()
buf.clear
buf.compact
Selector
定义
多路复用器
一对多
SelectableChanne
SocketChannel
ServerSocketChannel
ServerSocketChannel
方法
Selector.open()
channel.register(selector, SelectionKey.OP_READ)
selector.select()
selectNow()
select()
select(timeout)
selector.selectedKeys()
SelectionKey
读事件: SelectionKey.OP_READ
写事件: SelectionKey.OP_WRITE
连接事件: SelectionKey.OP_CONNECT
接受连接事件: SelectionKey.OP_ACCEPT
06从整体把握netty架构
netty架构
Core
事件模型
通信API
零拷贝缓冲区
Transport Service
TCP
UDP
HTTP隧道
VM管道
Protocol Support
HTTP
WebSocket
SSL
ProtoBuf
文本协议
大文件传输
模块设计
工具层
netty-common
通用的工具类, 比如 StringUtil 等
JDK 原生类的增强, 比如 Future 、 FastThreadLocal
Netty 自定义的并发包, 比如 EventExecutor 等
Netty 自定义的集合包, 主要是对 HashMap 的增强
netty-resolver
netty-buffer
池化buffer
组合buffer
传输层
netty-transport
TCP
UDP
Handler
netty-handler
ip过滤
日志
ssl
空闲检测
流量整形
netty-codec
base64、 json、 marshalling、 protobuf、 serializaion、 string、 xm
示例层
netty-example
discard
echo
wordclock
07优雅编写netty应用程序
1. 声明线程池( 必须)
bossGroup
处理 Accept 事件
workerGroup
消息的读写事件
2. 创建服务端引导类( 必须)
Bootstrap
ServerBootstrap
3. 设置线程池( 必须)
以什么样的线程模型运行
4. 设置 ServerSocketChannel 类型
以什么样的 IO 模型运行
OioServerSocketChannel
EpollServerSocketChannel
5. 设置参数( 可选)
6. 设置 Handler( 可选)
7. 编写并设置子 Handler( 必须)
Inbound
Outbound
8.绑定端口( 必须)
sync ()
9. 等待服务端端口关闭( 必须)
10. 优雅地关闭线程池( 建议)
简单群聊系统
08 Netty的核心组件有哪些
引导相关
Bootstrap
客户端引导
ServerBootstrap
服务端引导
线程相关
EventLoopGroup
java.util.concurrent
Iterable
Executor
ExecutorService
ScheduledExecutorService
netty
EventExecutorGroup
MultithreadEventLoopGroup
NioEventLoopGroup
EventLoopGroup
一是提供了 next () 方法用于获取
一个 EventLoop,
一个 EventLoop,
二是提供了注册 Channel 到事件轮询器中
EventLoop
继承体系
NioEventLoop
SingleThreadEventLoop
EventLoop
OrderedEventExecutor
EventExecutor
Buffer相关
区别 Buffer
指针
readIndex
writeIndex
分类
池化
Pooled
Unpooled
内存
Heap
Direct
安全
Safe
Unsafe
分配器
ByteBufAllocator
PooledByteBufAllocator
使用池化技术,内部会根据平台特性自行决定使用哪种 ByteBuf
UnpooledByteBufAllocator
不使用池化技术,内部会根据平台特性自行决定使用哪种 ByteBuf
PreferHeapByteBufAllocator
更偏向于使用堆内存,即除了显式地指明了使用直接内存的方法都使用堆内存
PreferDirectByteBufAllocator
更偏向于使用直接内存,即除了显式地指明了使用堆内存的方法都使用直接内
存
存
Channel相关
Channel
对 Java 原生 Channel 的进一步封装,和扩展
ChannelHandler
处理或拦截 IO 事件
设计模式
出站和入站
ChannelInboundHandler
SimpleChannelInboundHandler
处理入站事件,不建议直接使用 ChannelInboundHandlerAdapter
ChannelOutboundHandler
ChannelOutboundHandlerAdapter
处理出站事件
ChannelDuplexHandler
双向的
ChannelHandlerContext
ChannelHandlerContext 保存着 Channel 的上下文,同时关联着一个 ChannelHandler
ChannelFuture
可以查看 IO 操作是否已完成、是否成功、是否已取消
ChannelPipeline
负责处理和拦截入站和出站的事件和操作,每个 Channel 都有一个
ChannelPipeline 与之对应,会自动创建
ChannelPipeline 与之对应,会自动创建
关系
ChannelOption
参数
0 条评论
下一页