操作系统学习笔记 ---- 网络系统

1 DMA技术

直接内存访问(Direct Memory Access) 技术。

在进行 I/O 设备和内存的数据传输的时候,数据搬运的工作全部交给 DMA 控制器,而 CPU 不再参与任何与数据搬运相关的事情,这样 CPU 就可以去处理别的事务。

DMA将磁盘控制器缓冲区的数据拷贝到内存缓冲区(该过程不占用CPU)

传统的文件传输:
数据读取和写入是从用户空间到内核空间来回复制,而内核空间的数据是通过操作系统层面的 I/O 接口从磁盘读取或写入。
在这里插入图片描述
期间共发生了 4 次用户态与内核态的上下文切换,还发生了 4 次数据拷贝

要想提高文件传输的性能,就需要减少「用户态与内核态的上下文切换」和「内存拷贝」的次数。

2 零拷贝

零拷贝技术实现的方式通常有 2 种:

  • mmap + write
  • sendfile

mmap + write

用 mmap() 替换 read() 系统调用函数

mmap() 系统调用函数会直接把内核缓冲区里的数据「映射」到用户空间,这样,操作系统内核与用户空间就不需要再进行任何的数据拷贝操作。

在这里插入图片描述
减少一次数据拷贝但仍然需要 4 次上下文切换,因为系统调用还是 2 次

sendfile

可以替代前面的 read() 和 write() 这两个系统调用,这样就可以减少一次系统调用
直接把内核缓冲区里的数据拷贝到 socket 缓冲区里,不再拷贝到用户态
在这里插入图片描述
只有2 次上下文切换,和 3 次数据拷贝

网卡支持 SG-DMA(The Scatter-Gather Direct Memory Access)技术(和普通的 DMA 有所不同)
Linux 系统通过下面这个命令,查看网卡是否支持 scatter-gather 特性:
在这里插入图片描述
对于支持网卡支持 SG-DMA 技术的情况下,sendfile() 系统调用的过程发生变化
在这里插入图片描述
只进行了 2 次数据拷贝。即这就是零拷贝(Zero-copy)技术,因为我们没有在内存层面去拷贝数据,也就是说全程没有通过 CPU 来搬运数据,所有的数据都是通过 DMA 来进行传输的。

只需要 2 次上下文切换和数据拷贝次数,就可以完成文件的传输,
而且 2 次的数据拷贝过程,都不需要通过 CPU,2 次都是由 DMA 来搬运。

零拷贝技术可以把文件传输的性能提高至少一倍以上

大文件传输用什么方式实现?

绕开 PageCache 的 I/O 叫直接 I/O,使用 PageCache 的 I/O 则叫缓存 I/O。通常,对于磁盘,异步 I/O 只支持直接 I/O。
在高并发的场景下,针对大文件的传输的方式,应该使用「异步 I/O + 直接 I/O」来替代零拷贝技术。

直接 I/O 应用场景常见的两种:

应用程序已经实现了磁盘数据的缓存,那么可以不需要 PageCache 再次缓存,减少额外的性能损耗。在 MySQL 数据库中,可以通过参数设置开启直接 I/O,默认是不开启;
传输大文件的时候,由于大文件难以命中 PageCache 缓存,而且会占满 PageCache 导致「热点」文件无法充分利用缓存,从而增大了性能开销,因此,这时应该使用直接 I/O。

由于直接 I/O 绕过了 PageCache,就无法享受内核的这两点的优化:

内核的 I/O 调度算法会缓存尽可能多的 I/O 请求在 PageCache 中,最后「合并」成一个更大的 I/O 请求再发给磁盘,这样做是为了减少磁盘的寻址操作;
内核也会「预读」后续的 I/O 请求放在 PageCache 中,一样是为了减少对磁盘的操作;

传输文件的时候,我们要根据文件的大小来使用不同的方式:

· 传输大文件的时候,使用「异步 I/O + 直接 I/O」;
· 传输小文件的时候,则使用「零拷贝技术」;

3 I/O 多路复用

一个进程虽然任一时刻只能处理一个请求,但是处理每个请求的事件时,耗时控制在 1 毫秒以内,这样 1 秒内就可以处理上千个请求,把时间拉长来看,多个请求复用了一个进程(思想类似一个CPU并发多个进程)

select/poll/epoll 这是三个多路复用接口

3.1 select/poll

select实现多路复用的方式是

将已连接的 Socket 都放到一个文件描述符集合,
调用 select 函数将文件描述符集合拷贝到内核里,
内核通过遍历文件描述符集合的方式检查是否有网络事件产生,
当检查到有事件产生后,将此 Socket 标记为可读或可写,
再把整个文件描述符集合拷贝回用户态里,
用户态再遍历找到可读或可写的 Socket,然后再对其处理。

该方式需要 2 次遍历文件描述符集合(一次内核态、一次用户态),发生 2 次拷贝文件描述符集合(从用户态到内核态,内核修改,再从内核态到用户态)

select 使用固定长度的 BitsMap,表示文件描述符集合 ,所支持的文件描述符个数是有限制的

poll
使用动态数组,以链表形式来组织,突破了 select 的文件描述符个数限制(还会受到系统文件描述符限制)

poll 和 select 并没有太大的本质区别,都是使用「线性结构」存储进程关注的 Socket 集合,因此都需要遍历文件描述符集合来找到可读或可写的 Socket,时间复杂度为 O(n),而且也需要在用户态与内核态之间拷贝文件描述符集合

3.2 epoll

1、在内核使用红黑树跟踪进程所有待检测的文件描述字,将需要监控的socket通过 epoll_ctl() 函数传入内核红黑树。因内核维护了红黑树,可保存所有待检测的socket,所以只需传一个待检测的socket

2、使用事件驱动的机制,内核维护一个链表来记录就绪事件,当某个socket有事件发生时,通过回调函数,内核将其加入到就绪事件链表,当用户调用 epoll_wait() 函数时,只返回有事件发生的文件描述符个数。

在这里插入图片描述
epoll_wait 实现的内核代码中调用了 __put_user 函数,这个函数就是将数据从内核拷贝到用户空间。

epoll 支持两种事件触发模式,分别是边缘触发(edge-triggered,ET)水平触发(level-triggered,LT)

  • 使用边缘触发模式时,当被监控的 Socket 描述符上有可读事件发生时,服务器端只会从 epoll_wait 中苏醒一次,即使进程没有调用 read 函数从内核读取数据,也依然只苏醒一次,因此我们程序要保证一次性将内核缓冲区的数据读取完;

  • 使用水平触发模式时,当被监控的 Socket 上有可读事件发生时,服务器端不断地从 epoll_wait 中苏醒,直到内核缓冲区数据被 read 函数读完才结束,目的是告诉我们有数据需要读取;

两者区别:

水平触发的意思是只要满足事件的条件,比如内核中有数据需要读,就一直不断地把这个事件传递给用户;
而边缘触发的意思是只有第一次满足条件的时候才触发,之后就不会再传递同样的事件了。

边缘触发模式一般和非阻塞 I/O 搭配使用

边缘触发的效率比水平触发的效率要高,因为边缘触发可以减少 epoll_wait 的系统调用次数,系统调用也是有一定的开销的的,毕竟也存在上下文的切换。

select/poll 只有水平触发模式,epoll 默认的触发模式是水平触发,但是可以根据应用场景设置为边缘触发模式。

4 高性能网络模式

4.1 Reactor

Reactor 模式也叫 Dispatcher 模式,I/O 多路复用监听事件,收到事件后,根据事件类型分配(Dispatch)给某个进程 / 线程。

Reactor 模式主要由 Reactor 和处理资源池这两个核心部分组成,它俩负责的事情如下:

Reactor 负责监听和分发事件,事件类型包含连接事件、读写事件;
处理资源池负责处理事件,如 read -> 业务逻辑 -> send;

4.1.1 单 Reactor 单进程 / 线程

C语言实现的是单Reactor 单进程;JAVA语言实现的是单Reactor 单线程
「单 Reactor 单进程」的方案示意图:
在这里插入图片描述
「单 Reactor 单进程」方案:

Reactor 对象通过 select (IO 多路复用接口) 监听事件,收到事件后通过 dispatch 进行分发,具体分发给 Acceptor 对象还是 Handler 对象,还要看收到的事件类型;
如果是连接建立的事件,则交由 Acceptor 对象进行处理,Acceptor 对象会通过 accept 方法 获取连接,并创建一个 Handler 对象来处理后续的响应事件;
如果不是连接建立事件, 则交由当前连接对应的 Handler 对象来进行响应;
Handler 对象通过 read -> 业务处理 -> send 的流程来完成完整的业务流程。

缺点:

1、无法充分利用多核CPU性能
2、Handler对象处理业务时,整个进程无法处理其它连接事件,如果处理时间过长,会造成响应的延迟

单 Reactor 单进程的方案不适用计算机密集型的场景,只适用于业务处理非常快速的场景

4.1.2 单 Reactor 多线程 / 多进程

「单 Reactor 多线程」方案的示意图如下:
在这里插入图片描述
「单 Reactor 多线程」方案:

Reactor 对象通过 select (IO 多路复用接口) 监听事件,收到事件后通过 dispatch 进行分发,具体分发给 Acceptor 对象还是 Handler 对象,还要看收到的事件类型;
如果是连接建立的事件,则交由 Acceptor 对象进行处理,Acceptor 对象会通过 accept 方法 获取连接,并创建一个 Handler 对象来处理后续的响应事件;
如果不是连接建立事件, 则交由当前连接对应的 Handler 对象来进行响应;
Handler 对象不再负责业务处理,只负责数据的接收和发送,Handler 对象通过 read 读取到数据后,会将数据发给子线程里的 Processor 对象进行业务处理;
子线程里的 Processor 对象就进行业务处理,处理完后,将结果发给主线程中的 Handler 对象,接着由 Handler 通过 send 方法将响应结果发送给 client;

一个 Reactor 对象承担所有事件的监听和响应,而且只在主线程中运行,在面对瞬间高并发的场景时,容易成为性能的瓶颈的地方

4.1.3 多 Reactor 多进程 / 线程

「多 Reactor 多线程」方案示例图:
在这里插入图片描述
方案详细说明如下:

主线程中的 MainReactor 对象通过 select 监控连接建立事件,收到事件后通过 Acceptor 对象中的 accept 获取连接,将新的连接分配给某个子线程;
子线程中的 SubReactor 对象将 MainReactor 对象分配的连接加入 select 继续进行监听,并创建一个 Handler 用于处理连接的响应事件。
如果有新的事件发生时,SubReactor 对象会调用当前连接对应的 Handler 对象来进行响应。
Handler 对象通过 read -> 业务处理 -> send 的流程来完成完整的业务流程。

多 Reactor 多线程的方案虽然看起来复杂的,但是实际实现时比单 Reactor 多线程的方案要简单的多,原因如下:

  • 主线程和子线程分工明确,主线程只负责接收新连接,子线程负责完成后续的业务处理。

  • 主线程和子线程的交互很简单,主线程只需要把新连接传给子线程,子线程无须返回数据,直接就可以在子线程将处理结果发送给客户端。

4.2 Proactor

Reactor 是非阻塞同步网络模式,而 Proactor 是异步网络模式

  • Reactor 是非阻塞同步网络模式,感知的是就绪可读写事件。在每次感知到有事件发生(比如可读就绪事件)后,就需要应用进程主动调用 read 方法来完成数据的读取,也就是要应用进程主动将 socket 接收缓存中的数据读到应用进程内存中,这个过程是同步的,读取完数据后应用进程才能处理数据。

  • Proactor 是异步网络模式, 感知的是已完成的读写事件。在发起异步读写请求时,需要传入数据缓冲区的地址(用来存放结果数据)等信息,这样系统内核才可以自动帮我们把数据的读写工作完成,这里的读写工作全程由操作系统来做,并不需要像 Reactor 那样还需要应用进程主动发起 read/write 来读写数据,操作系统完成读写工作后,就会通知应用进程直接处理数据。

Proactor 模式的示意图:
在这里插入图片描述
工作流程:

Proactor Initiator 负责创建 Proactor 和 Handler 对象,并将 Proactor 和 Handler 都通过 Asynchronous Operation Processor 注册到内核;
Asynchronous Operation Processor 负责处理注册请求,并处理 I/O 操作;
Asynchronous Operation Processor 完成 I/O 操作后通知 Proactor;
Proactor 根据不同的事件类型回调不同的 Handler 进行业务处理;
Handler 完成业务处理;

5 一致性哈希

负载均衡问题,不同分配策略应对不同场景:如加权轮询,让性能更好的服务器承担更多的请求,但前提是每个服务器上数据是一致的(面对分布式存储,无法应对)

哈希算法,针对同一关键字计算出的哈希值是相同的,可将某一个key确定到一个服务器上,满足分布式系统的负载均衡。

最简单的做法即取模运算,但问题在于如果节点数量发生变化(系统扩容或缩容),必须迁移改变了映射关系的数据

一致性哈希算法

不同于普通的哈希算法,一致哈希算法是对 2^32 进行取模运算,是一个固定的值

对 2^32 进行取模运算的结果值组织成一个圆环
在这里插入图片描述
一致性哈希要进行两步哈希:

  • 第一步:对存储节点进行哈希计算,也就是对存储节点做哈希映射,比如根据节点的 IP 地址进行哈希;
  • 第二步:当对数据进行存储或访问时,对数据进行哈希映射;

一致性哈希是指将「存储节点」和「数据」都映射到一个首尾相连的哈希环上。

  • 首先计算要查询的key的哈希,确定此key在哈希环上映射的位置
  • 然后从该位置顺时针找到第一个节点,即存储该key数据的节点

在一致性哈希算法中,如果增加或删除一个节点,只会影响到该节点在哈希环上顺时针相邻的后继节点

在这里插入图片描述
但一致性哈希算法并不保证节点能够在哈希环上分布均匀

在这里插入图片描述

当节点数量足够大时,哈希环上的节点分布就越均匀

如何通过虚拟节点提高均衡度?

不再将真实节点映射到哈希环上,而是将虚拟节点映射到哈希环上,并将虚拟节点映射到实际节点,所以这里有「两层」映射关系。

在这里插入图片描述
如果有访问请求寻址到「A-01」这个虚拟节点,接着再通过「A-01」虚拟节点找到真实节点 A,这样请求就能访问到真实节点 A 了。

虚拟节点除了会提高节点的均衡度,还会提高系统的稳定性。当节点变化时,会有不同的节点共同分担系统的变化,因此稳定性更高

带虚拟节点的一致性哈希方法不仅适合硬件配置不同的节点的场景,而且适合节点规模会发生变化的场景

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/1000.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

js逆向学习、安卓逆向

JS基础 提示信息 - 吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn 安卓逆向 1.模拟器环境搭建 Magisk 是一套用于定制 Android 的开源软件,支持高于 Android 5.0 的设备。 以下是一些功能亮点: MagiskSU:为应用程序提供 root 访…

什么是 .com 域名?含义和用途又是什么?

随着网络的发展,网络上出现了各种不同后缀的域名,这些域名的后缀各有不同的含义,也有不同的用途。今天,我们就一起来探讨一下 .com 后缀的域名知识。 .com 域名是一种最常见的顶级域名,它是由美国国家网络信息中心&…

第3章 多层感知器

这章节我们来解决的问题是:如何使用神经网络实现逻辑电路中的“异或门”模型?如下图:根据第2章我们知道,单层感知器是能够解决“与门”、“或门”、“非门”这些简单的线性问题,但是不能解决“异或门”这类非线性问题。…

内存函数的简单实用

本篇要分享的是常见的内存函数 前面分享的函数都是和字符串相关,但是当我们在操作数据的时候不仅仅要操作字符数据 接下来分享几个与内存相关的函数 目录 本篇要分享的是常见的内存函数 1.memcpy 2.memmove 自定函数模拟实现memmove函数 3.memcmp 4.memset …

【算法经典题集】DP和枚举(持续更新~~~)

😽PREFACE🎁欢迎各位→点赞👍 收藏⭐ 评论📝📢系列专栏:算法经典题集🔊本专栏涉及到的知识点或者题目是算法专栏的补充与应用💪种一棵树最好是十年前其次是现在DPDP就是动态规划&a…

Web前端 JS WebAPI

1、操作DOM 1.1、什么DOM? DOM(Document Object Model——文档对象模型):DOM是浏览器提供的一套专门用来操作网页内容的功能 DOM作用:开发网页内容特效和实现用户交互 DOM树是什么? 将 HTML 文档以树状…

手把手教你使用vue创建第一个vis.js

先看一下实现效果吧 ,如下图 : 为什么要写这篇文章呢?因为之前有浅浅的了解一下vis.js,后期开发中没有使用vis,所以太深奥的也不懂,但是当时是用js写的。这两天有人问我用vue怎么写,然后说看到…

减治法实现插入排序,减治法实现二叉查找树(二叉搜索数,二叉排序数)的创建、插入与查找(含解析与代码实现)

🎊【数据结构与算法】专题正在持续更新中,各种数据结构的创建原理与运用✨,经典算法的解析✨都在这儿,欢迎大家前往订阅本专题,获取更多详细信息哦🎏🎏🎏 🪔本系列专栏 -…

嵌入式软件开发之Linux下C编程

目录 前沿 Hello World! 编写代码 编译代码 GCC编译器 gcc 命令 编译错误警告 编译流程 Makefile 基础 何为 Makefile Makefile 的引入 前沿 在 Windows 下我们可以使用各种各样的 IDE 进行编程,比如强大的 Visual Studio。但是在Ubuntu 下如何进…

【Java版oj】day10 井字棋、密码强度等级

目录 一、井字棋 (1)原题再现 (2)问题分析 (3)完整代码 二、密码强度等级 (1)原题再现 (2)问题分析 (3)完整代码 一、井字棋 &a…

CAT8网线测试仪使用中:线缆的抗干扰参数解读以及线缆工艺改进注意事项

FLUKE Agent platform -深圳维信,带你更深入的了解铜缆测试,详细为您讲解什么是TCL/ELTCL,他们对数据的传输到底有什么影响呢? 前情分析:为什么用双绞线传输信号?(一图就懂) TCL&a…

【深度解刨C语言】符号篇(全)

文章目录一.注释二.续行符与转义符1.续行符2.转义符三.回车与换行四.逻辑操作符五.位操作符和移位操作符六.前置与后置七.字符与字符串八./和%1.四种取整方式2.取模与取余的区别和联系3./两边异号的情况1.左正右负2.左负右正九.运算符的优先级一.注释 注释的两种符号&#xff…

Sentinel

SentinelSentinel介绍什么是Sentinel?为什么需要流量控制?为什么需要熔断降级?一些普遍的使用场景本文介绍参考:Sentinel官网《Spring Cloud Alibaba 从入门到实战.pdf》Sentinel下载/安装项目演示构建项目控制台概览演示之前需先明确&#…

【webrtc】ICE 到VCMPacket的视频内存分配

ice的数据会在DataPacket 构造是进行内存分配和拷贝而后DataPacket 会传递给rtc模块处理rtc模块使用DataPacket 构造rtp包最终会给到OnReceivedPayloadData 进行rtp组帧。吊炸天的是DataPacket 竟然没有声明析构方法。RtpVideoStreamReceiver::OnReceivedPayloadData 的内存是外…

3.网络爬虫——Requests模块get请求与实战

Requests模块get请求与实战requests简介:检查数据请求数据保存数据前言: 前两章我们介绍了爬虫和HTML的组成,方便我们后续爬虫学习,今天就教大家怎么去爬取一个网站的源代码(后面学习中就能从源码中找到我们想要的数据…

普通Java工程师 VS 优秀架构师

1 核心能力 1.1 要成为一名优秀的Java架构师 只懂技术还远远不够,懂技术/懂业务/懂管理的综合型人才,才是技术团队中的绝对核心。 不仅仅是架构师,所有的技术高端岗位,对人才的综合能力都有较高的标准。 架构路线的总设计师 规…

安卓渐变的背景框实现

安卓渐变的背景框实现1.背景实现方法1.利用PorterDuffXfermode进行图层的混合,这是最推荐的方法,也是最有效的。2.利用canvas裁剪实现,这个方法有个缺陷,就是圆角会出现毛边,也就是锯齿。3.利用layer绘制边框1.背景 万…

多线程案例——阻塞队列

目录 一、阻塞队列 1. 生产者消费者模型 (1)解耦合 (2)“削峰填谷” 2. 标准库中的阻塞队列 3. 自己实现一个阻塞队列(代码) 4. 自己实现生产者消费者模型(代码) 一、阻塞队列…

【Pytorch】 理解张量Tensor

本文参加新星计划人工智能(Pytorch)赛道:https://bbs.csdn.net/topics/613989052 这是目录张量Tensor是什么?张量的创建为什么要用张量Tensor呢?总结张量Tensor是什么? 在深度学习中,我们经常会遇到一个概念&#xff…

更改Hive元数据发生的生产事故

今天同事想在hive里用中文做为分区字段。如果用中文做分区字段的话,就需要更改Hive元 数据库。结果发生了生产事故。导致无法删除表和删除分区。记一下。 修改hive元数据库的编码方式为utf后可以支持中文,执行以下语句: alter table PARTITI…