没有合适的资源?快使用搜索试试~ 我知道了~
聊聊Netty那些事儿之从内核角度看IO模型.doc
1.该资源内容由用户上传,如若侵权请联系客服进行举报
2.虚拟产品一经售出概不退款(资源遇到问题,请及时私信上传者)
2.虚拟产品一经售出概不退款(资源遇到问题,请及时私信上传者)
版权申诉
0 下载量 4 浏览量
2022-07-08
15:41:42
上传
评论
收藏 23.06MB DOC 举报
温馨提示
试读
55页
聊聊Netty那些事儿之从内核角度看IO模型.doc
资源推荐
资源详情
资源评论
聊聊 Netty 那些事儿之从内核角度看 IO 模型
从内核角度介绍了经常容易混淆的阻塞与非阻塞,同步与异步的概念。以这个作
为铺垫,我们通过一个 C10K 的问题,引出了五种 IO 模型,随后在 IO 多路复用中以技术演
进的形式介绍了 select,poll,epoll 的原理和它们综合的对比。最后我们介绍了两种 IO 线程模
型以及 netty 中的 Reactor 模型。
从今天开始我们来聊聊 Netty 的那些事儿,我们都知道 Netty 是一个高性能异步事件驱动
的网络框架。
它的设计异常优雅简洁,扩展性高,稳定性强。拥有非常详细完整的用户文档。
同时内置了很多非常有用的模块基本上做到了开箱即用,用户只需要编写短短几行代码,
就可以快速构建出一个具有高吞吐,低延时,更少的资源消耗,高性能(非必要的内存拷贝
最小化)等特征的高并发网络应用程序。
本文我们来探讨下支持 Netty 具有高吞吐,低延时特征的基石----netty 的网络 IO 模型。
由 Netty 的网络 IO 模型开始,我们来正式揭开本系列 Netty 源码解析的序幕:
网络包接收流程
当网络数据帧通过网络传输到达网卡时,网卡会将网络数据帧通过 DMA 的方式放到环形
缓冲区 RingBuffer 中。
RingBuffer 是网卡在启动的时候分配和初始化的环形缓冲队列。当 RingBuffer 满的时候,
新来的数据包就会被丢弃。我们可以通过 ifconfig 命令查看网卡收发数据包的情况。其中
overruns 数据项表示当 RingBuffer 满时,被丢弃的数据包。如果发现出现丢包情况,可以通
过 ethtool 命令来增大 RingBuffer 长度。
当 DMA 操作完成时,网卡会向 CPU 发起一个硬中断,告诉 CPU 有网络数据到达。CPU
调用网卡驱动注册的硬中断响应程序。网卡硬中断响应程序会为网络数据帧创建内核数据结
构 sk_buffer,并将网络数据帧拷贝到 sk_buffer 中。然后发起软中断请求,通知内核有新的
网络数据帧到达。
sk_buff 缓冲区,是一个维护网络帧结构的双向链表,链表中的每一个元素都是一个网络
帧。虽然 TCP/IP 协议栈分了好几层,但上下不同层之间的传递,实际上只需要操作这个数
据结构中的指针,而无需进行数据复制。
内核线程 ksoftirqd 发现有软中断请求到来,随后调用网卡驱动注册的 poll 函数,poll 函数
将 sk_buffer 中的网络数据包送到内核协议栈中注册的 ip_rcv 函数中。
每个 CPU 会绑定一个 ksoftirqd 内核线程专门用来处理软中断响应。2 个 CPU 时,就会
有 ksoftirqd/0 和 ksoftirqd/1 这两个内核线程。
这里有个事情需要注意下: 网卡接收到数据后,当 DMA 拷贝完成时,向 CPU 发出硬中
断,这时哪个 CPU 上响应了这个硬中断,那么在网卡硬中断响应程序中发出的软中断请求
也会在这个 CPU 绑定的 ksoftirqd 线程中响应。所以如果发现 Linux 软中断,CPU 消耗都集
中在一个核上的话,那么就需要调整硬中断的 CPU 亲和性,来将硬中断打散到不通的 CPU
核上去。
在 ip_rcv 函数中也就是上图中的网络层,取出数据包的 IP 头,判断该数据包下一跳的走
向,如果数据包是发送给本机的,则取出传输层的协议类型(TCP 或者 UDP),并去掉数据
包的 IP 头,将数据包交给上图中得传输层处理。
传输层的处理函数:TCP 协议对应内核协议栈中注册的 tcp_rcv 函数,UDP 协议对应内核
协议栈中注册的 udp_rcv 函数。
当我们采用的是 TCP 协议时,数据包到达传输层时,会在内核协议栈中的 tcp_rcv 函数处
理,在 tcp_rcv 函数中去掉 TCP 头,根据四元组(源 IP,源端口,目的 IP,目的端口)查
找对应的 Socket,如果找到对应的 Socket 则将网络数据包中的传输数据拷贝到 Socket 中的
接收缓冲区中。如果没有找到,则发送一个目标不可达的 icmp 包。
内核在接收网络数据包时所做的工作我们就介绍完了,现在我们把视角放到应用层,当我
们程序通过系统调用 read 读取 Socket 接收缓冲区中的数据时,如果接收缓冲区中没有数据,
那么应用程序就会在系统调用上阻塞,直到 Socket 接收缓冲区有数据,然后 CPU 将内核空
间(Socket 接收缓冲区)的数据拷贝到用户空间,最后系统调用 read 返回,应用程序读取
数据。
性能开销
从内核处理网络数据包接收的整个过程来看,内核帮我们做了非常之多的工作,最终我们
的应用程序才能读取到网络数据。
随着而来的也带来了很多的性能开销,结合前面介绍的网络数据包接收过程我们来看下网
络数据包接收的过程中都有哪些性能开销:
应用程序通过系统调用从用户态转为内核态的开销以及系统调用返回时从内核态转为用
户态的开销。
网络数据从内核空间通过 CPU 拷贝到用户空间的开销。
内核线程 ksoftirqd 响应软中断的开销。
CPU 响应硬中断的开销。
DMA 拷贝网络数据包到内存中的开销。
网络包发送流程
当我们在应用程序中调用 send 系统调用发送数据时,由于是系统调用所以线程会发生一
次用户态到内核态的转换,在内核中首先根据 fd 将真正的 Socket 找出,这个 Socket 对象中
记录着各种协议栈的函数地址,然后构造 struct msghdr 对象,将用户需要发送的数据全部封
装在这个 struct msghdr 结构体中。
调用内核协议栈函数 inet_sendmsg ,发送流程进入内核协议栈处理。在进入到内核协议
栈之后,内核会找到 Socket 上的具体协议的发送函数。
剩余54页未读,继续阅读
资源评论
书博教育
- 粉丝: 1
- 资源: 2836
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功