学习网络系统的心得体会

网络系统

零拷贝

磁盘是计算机系统中读写速度最慢的的硬件之一,而零拷贝技术是用于提高文件传输性能的,通过减少上下文切换次数与数据拷贝的次数从而提高传输性能。

操作系统中IO的流程
大体流程

收到IO请求由用户态切换到内核态,CPU发送指令给磁盘控制器,磁盘控制器收到指令以后开始准备数据,数据被放入到磁盘控制器的内部缓冲区中,然后产生中断。CPU收到中断信息以后,从内部缓冲区中一个字节一个字节的读取到PageCache中,然后再从PageCache写入到用户态缓冲区中,最后再从内核态切换到用户态。

DMA技术

为了提高效率,提高CPU的使用性能,于是有了DMA技术(直接内存访问技术),数据运输工作全部交给DMA进行解决,而此时CPU就可以去做别的事情。于是流程就变成了这样:

改进以后的流程

收到IO请求由用户态切换到内核态,操作系统接收到IO请求,将请求分发给DMA,让CPU去做别的事情。DMA进一步将IO请求发送给磁盘,磁盘收到请求将数据放入到缓冲区,当缓冲区放满以后向DMA发送中断,DMA收到中断以后将缓冲区的数据读取到PageCache中,读取完毕以后再向CPU发送中断请求,最后CPU收到中断请求,将内核态的PageCache中的数据拷贝到用户态缓冲区中,再从内核态切换到用户态。

零拷贝技术

如果服务端想要对外提供文件传输的功能,那么就大体的流程就是将磁盘里面的内容读取出来然后通过网络协议发送到客户端。这期间由于传输性能太低所以就有了零拷贝技术。

没有零拷贝技术之前的流程

没有使用零拷贝需要进行四次数据拷贝以及两次上下文切换

  • 收到传输请求,从用户态切换到内核态,从磁盘中读取数据DMA拷贝到PageCache中,然后CPU再从PageCache将数据拷贝到用户态缓冲区中,再从内核态切换到用户态。
  • 再从用户态切换到内核态,将CPU用户态缓冲区中的数据拷贝到socket的缓冲区中,然后DMA再从socket的缓冲区中拷贝到网卡的缓冲区中
使用零拷贝技术之后的流程

零拷贝的实现有两种方式一种是使用mmap+write,还有一种是使用sendfile

  • mmap+write
    • 调用mmap函数以后会将磁盘缓冲区里面的数据拷贝到内核态缓冲区中,此时用户态和内核态一起共享内核态缓冲区中的磁盘数据,CPU无需再从内核态拷贝数据到用户态。用户态再调用write方法,从用户态切换到内核态以后直接将内核态缓冲区中的磁盘数据拷贝到socket中。
    • 这样的好处就是减少了一次调用CPU进行数据拷贝。
  • sendfile
    • DMA直接将磁盘缓冲区里面的数据拷贝到内核态缓冲区中,然后将缓冲区里面的描述符和数据长度传入到socket的缓冲区中,最后网卡中就可以根据socket缓冲区中的内容直接从内核态缓冲区拷贝到网卡中。
    • 这样的好处就是减少了两次拷贝过程以及两次内核态与用户态的上下文切换。
什么是PageCache

PageCache实际上就是内核缓冲区,作用有两个,一个是缓存最近被访问的数据另一个是预读功能。

  • 读取磁盘的时候优先从PageCache里面找,有就直接返回数据,没有就从磁盘中读取然后缓存到PageCache中。
  • 举个例子,假如read方法每次只能够读取100k,虽然read刚开始只会读0100k的数据,但是内核会把后面的101200k的数据都给写入到PageCache中,这样就减少了与磁盘交互的次数。
读取大文件应该怎么办

如果读取大文件的话,由于PageCache的预读功能,会把PageCache吃满导致热点小文件无法使用到PageCache的优点。为了防止这种情况的出现,应该不使用零拷贝的技术而是使用异步IO和直接IO的方式绕开PageCache,流程是:进程发起异步IO请求,然后去处理其他事情,操作系统向内核发送IO请求,磁盘将数据存储到磁盘缓冲区以后,向CPU发送中断,CPU直接将数据从磁盘缓冲区拷贝到用户态缓冲区中。

IO多路复用

网络IO的流程

在进行网络通信之前双方都需要建立一个socket,双方在读取或者传输数据的时候都通过这个socket进行数据的传输。服务端调用socket方法创建socket然后再调用bind方法给这个socket绑定ip和端口。绑定完ip和端口之后调用listen函数进行监听状态,最后通过调用accept函数从内核获取客户端连接。客户端再调用调用socket方法创建socket以后调用conect方法与服务端进行连接,接着就可以进行网络间的通信了。

TCP的最大连接数

Tcp的最大连接数限制于两个,一个是文件操作符一个是系统内存。

  • socket实际上就是一个文件,也就对应这一个文件操作符,在linux环境下文件操作符的打开数量是有限的,一般是1024。
  • 每个连接在内核中都有对饮的内存,意味着每个连接占用一定的内存。
    如果请求量很大,那么就肯定是无法满足的,为了解决这个问题就有了IO多路复用。
IO多路复用

如果为每一个请求都分配一个进程或者线程,假如说来了一万个请求就需要维护一万个进程或者线程,操作系统肯定是扛不住的。所以IO多路复用就是用一个进程来维护多个Socket,虽然说一个进程只能处理一个请求,但是如果把每个请求的时间降低,这样1秒内处理上万个请求了。

select/poll

select和poll的方式是用户态将已经连接的Socket存储在集合中,用户态将集合拷贝到内核态以后内核遍历一遍集合,查看有没有网络事件发生,有就将其进行标记。然后再将其从内核态拷贝到用户态,用户态再遍历一遍集合对标记的socket进行处理。

两者间的区别

select使用bitsmap,是一个固定长度的集合,默认的最大值为1024只能监听0~1023的文件。poll不再使用bitsmap而是使用动态的数组,突破了文件数量的限制。

epoll

epoll使用红黑树来维护待检测的socket和链表来维护就绪的socket,同时是在内核态进行维护的,减少了上下文切换的次数。红黑树用于来维护待检测的socket,当有socket就绪以后通过回调函数将其加入到链表中,用户只需要调用epoll_wait()方法就可以从链表中获取到就绪的socket而不需要遍历。

边缘触发和水平触发

边缘触发:服务端是从epoll_wait()苏醒一次,所以必须一次性读完。
水平触发:服务端会一直从epoll_wait()苏醒,直到客户端read完所有的就绪事件。

网络模式:Reactor模型和Proactor模型

Reactor模型

Reactor模型对多路IO模型的封装,由两部分组成一个是Reactor一个是处理资源池。

  • Reactor用于监听响应事件
  • 处理资源池负责处理事件
    同时分Reactor模型常见的模型又分为单Reactor单线程、单Reactor多线程、多Reactor多线程模型
单Reactor单线程

不需要考虑进程之间通信的问题,实现起来比较简单,但是没有办法充分利用多核CPU,所以处理业务逻辑的事件不能太长,否则其他连接的事务响应会有延迟。

单Reactor多线程

相比较于单Reactor单线程,多线程解决了单线程的缺陷,可以利用多核CPU,但是也带来了数据竞争的关系,但是如果并发量高的话单个Reactor承担了所有的事件监听和响应,而在在主线程运行容易成为性能瓶颈。

多Reactor多线程

相较于单Reactor,多Reactor做到了主Reactor用于监听事件,而从Reactor用于分发事件给资源处理池用于处理事件。

Proactor模型

采用异步 I/O 实现的异步网络模型,感知的是已完成的读写事件,而不需要像 Reactor 感知到事件后,还需要调用 read 来从内核中获取数据。

一致性哈希算法

现在的服务器大都是分布式部署的,一个应用部署在多台服务器上,然后通过网关将请求转发到其中的一台服务器上。为了提高系统的数据容量,会把数据水平的分到不同的节点上,比如一个分布式缓存系统,某一个key就应该到某一个节点上进行获取而不是所有的节点都能够获取。为了解决这个问题,可以使用哈希算法。比如有三台服务器,那么就将key转换成数值取模3获取到响应的服务器然后去获取数据,但是这样有个问题就是如果服务器进行扩容了,那么哈希算法也应该进行改变,数据也应该根据哈希算法的改变重新水平分发到不同的服务器上,十分麻烦。

一致性哈希

一致性哈希也是取模,只不过是对232进行取模得到一个固定值,同时将0=232使其形成一个圆。使用一致性哈希算法获取到相应的服务器分为两步,第一步:将服务器的ip进行一致性哈希处理,得到一个固定值,第二步:将获取数据的key进行一致性哈希处理,也得到一个固定值。这样两个哈希值就会被映射到一个首尾相接的圆上,然后只需要从key的位置顺时针找到第一台服务器就是存储key数据的服务器。
但是一致性哈希不是万能的,他只能减少数据迁移量,并不保证节点能够在哈希环上分布均匀,这样就会带来一个问题,会有大量的请求集中在一个节点上。假设访问请求主要集中的节点 A 上,如果节点 A 被移除了,当节点 A 宕机后,根据一致性哈希算法的规则,其上数据应该全部迁移到相邻的节点 B 上,这样,节点 B 的数据量、访问量都会迅速增加很多倍,一旦新增的压力超过了节点 B 的处理能力上限,就会导致节点 B 崩溃,进而形成雪崩式的连锁反应。

虚拟节点

为了解决节点在哈希环上分配不均的问题,可以引入虚拟节点。比如现在还是有三台服务器ABC,哈希环上只有三个节点,但是现在不再将真实节点映射到哈希环上而是将虚拟节点映射到哈希环上,然后虚拟节点再映射到真实的服务器上,这个时候就能解决哈希环上分配不均的问题,也就是负载均衡的问题。

比如对每个节点分别设置 3 个虚拟节点:

对节点 A 加上编号来作为虚拟节点:A-01、A-02、A-03
对节点 B 加上编号来作为虚拟节点:B-01、B-02、B-03
对节点 C 加上编号来作为虚拟节点:C-01、C-02、C-03
引入虚拟节点后,原本哈希环上只有 3 个节点的情况,就会变成有 9 个虚拟节点映射到哈希环上,哈希环上的节点数量多了 3 倍。

参考:小林coding - 图解系统

unix 的网络操作系统实训 包含: 一、 实验目的 1. 掌握UNIX系统的目录和文件管理命令。 2. 掌握shell的输入输出重定向操作符。 3. 编写shell脚本文件,并调试、执行它。 二、 实验要求 1. 要求每人能独立完成实验。能独立搭建UNIX操作系统,掌握OpenSolaris的安装、运行和使用。 2. 使用自己的账号登录UNIX 系统, 用户名为:学号和姓名汉语拼音全拼。在用户主目录下,新建子目录,子目录名为:专业和班级(可以是拼音)。 3. 在新建的子目录下完成全部练习,所有的操作练习均要截图显示。 4. 所有的实验内容必须在命令行方式下进行操作。 5. 纸制版的封面单面打印,其他页面必须双面打印。全班刻一张光盘。 三、 实验内容 1. 用uname -a命令显示操作系统的版本。 2. 用pwd命令显示用户主目录的路径名。 3. 用date命令查看当前日期和时间。分别比较%a和%w,%D和%d。 4. 用who命令查看当前登录在系统中的用户列表。比较$who –H与$who –s显示的结果区别。用hostid命令和id命令查看主机信息和用户信息。 5. 用vi编辑器,先在子目录中创建名为one的文件,编辑one文件,再把one文件中2-6行的内容写到文件two中。给出复制3行和删除10个符的操作。(说明one文件内容不能以数和简单的母组成,必须是一段有内容的英文,至少是10行以上的描述) 6. 用重定向符和cat命令创建一个电话簿telephone文件。假定收集你班上10位同学的姓名、学号、email和电话号码存在这个文件中。使用sort命令对这个文件进行排序,按名、按姓、按email、按电话号码及反序排序等。使用grep命令及其选项在你的电话簿中查找一个名。 7. 用重定向符和cat命令创建一个ums脚本文件完成如下功能。并运行它。 a. 显示当前日期和时间。 b. 显示当前用户名。 c. 输入若干用户名作为参数,判断用户是:(1)教师或博士后;(2)博士研究生;(3)硕士研究生;(4)本科生。 d. 用户名规则:教师用户名以j开头,博士后用户名以bh开头,博士研究生用户名以yb 开头,硕士研究生用户名以ys开头,本科生用户名以x开头。 8. 编写C程序,编译和运行程序。给出年、月、日,计算该日是该年的第几天。 9. 编写Java程序,编译和运行程序。将给定的一个符串中的所有符逆序输出。 7、8和9题说明:要求有源程序清单和目标文件的截图,还要有运行结果的截屏。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值