《Linux性能优化实战》学习笔记 Day03

news2024/9/23 11:18:26

04 | 零拷贝:如何高效地传输文件?

原文摘抄

文件拷贝

在这里插入图片描述

上下文切换的成本并不小,虽然一次切换仅消耗几十纳秒到几微秒,但高并发服务会放大这类时间的消耗。

每周期中的 4 次内存拷贝,其中与物理设备相关的 2 次拷贝是必不可少的,包括:把磁盘内容拷贝到内存,以及把内存拷贝到网卡。但另外 2 次与用户缓冲区相关的拷贝动作都不是必需的,因为在把磁盘文件发到网络的场景中,用户缓冲区没有必须存在的理由。

如果内核在读取文件后,直接把 PageCache 中的内容拷贝到 Socket 缓冲区,待到网卡发送完毕后,再通知进程,这样就只有 2 次上下文切换,和 3 次内存拷贝。
在这里插入图片描述

你可以回忆下,没用零拷贝时,为了传输 320MB 的文件,在用户缓冲区分配了 32KB 的内存,把文件分成 1 万份传送,然而,这 32KB 是怎么来的?为什么不是 32MB 或者 32 字节呢?这是因为,在没有零拷贝的情况下,我们希望内存的利用率最高。如果用户缓冲区过大,它就无法一次性把消息全拷贝给 socket 缓冲区;如果用户缓冲区过小,则会导致过多的 read/write 系统调用。那用户缓冲区为什么不与 socket 缓冲区大小一致呢?这是因为,socket 缓冲区的可用空间是动态变化的,它既用于 TCP 滑动窗口,也用于应用缓冲区,还受到整个系统内存的影响(我在《Web 协议详解与抓包实战》第 5 部分课程对此有详细介绍,这里不再赘述)。尤其在长肥网络中,它的变化范围特别大。

零拷贝使我们不必关心 socket 缓冲区的大小。

PageCache,磁盘高速缓存

PageCache 使用了预读功能。也就是说,虽然 read 方法只读取了 0-32KB 的字节,但内核会把其后的 32-64KB 也读取到 PageCache,这后 32KB 读取的成本很低。

这两点可以看到 PageCache 的优点,它在 90% 以上场景下都会提升磁盘性能,但在某些情况下,PageCache 会不起作用,甚至由于多做了一次内存拷贝,造成性能的降低。在这些场景中,使用了 PageCache 的零拷贝也会损失性能。就是在传输大文件的时候。由于文件太大,文件中某一部分内容被再次访问到的概率其实非常低。

高并发场景下,为了防止 PageCache 被大文件占满后不再对小文件产生作用,大文件不应使用 PageCache,进而也不应使用零拷贝技术处理。

在这里插入图片描述

异步 IO + 直接 IO

在这里插入图片描述

绕过 PageCache 的 IO 是个新物种,我们把它称为直接 IO。对于磁盘,异步 IO 只支持直接 IO。

直接 IO 的应用场景并不多,主要有两种:第一,应用程序已经实现了磁盘文件的缓存,不需要 PageCache 再次缓存,引发额外的性能消耗。比如 MySQL 等数据库就使用直接 IO;第二,高并发下传输大文件,我们上文提到过,大文件难以命中 PageCache 缓存,又带来额外的内存拷贝,同时还挤占了小文件使用 PageCache 时需要的内存,因此,这时应该使用直接 IO。

当然,直接 IO 也有一定的缺点。除了缓存外,内核(IO 调度算法)会试图缓存尽量多的连续 IO 在 PageCache 中,最后合并成一个更大的 IO 再发给磁盘,这样可以减少磁盘的寻址操作;另外,内核也会预读后续的 IO 放在 PageCache 中,减少磁盘操作。直接 IO 绕过了 PageCache,所以无法享受这些性能提升。

我们通常会设定一个文件大小阈值,大文件由异步 IO 和直接 IO 处理,小文件则交由零拷贝处理

事实上 PageCache 对写操作也有很大的性能提升,因为 write 方法在写入内存中的 PageCache 后就会返回,速度非常快,由内核负责异步地把 PageCache 刷新到磁盘中。

心得体会

  1. 内核态和用户态的频繁切换会导致耗时增加。
  2. PageCache,会顺序的多读一些数据,期待下次获取数据在其中。但是对大文件来说,作用很小,甚至是负面影响。
  3. 说实话,对于“write 方法在写入内存中的 PageCache 后就会返回”,“由内核负责异步地把 PageCache 刷新到磁盘中”存在疑惑,如果此时断电宕机,写操作不就失败了吗?如何保证可靠性呢?

工作体验

  1. netty框架是使用零拷贝技术进行传输的,零拷贝技术用的内存是堆外内存。需要设置JVM最大堆外内存使用量,避免占用过高内存。

05 | 协程:如何快速地实现高并发服务?

原文摘抄

为了达到高并发,你可能会选择一个异步框架,用非阻塞 API 把业务逻辑打乱到多个回调函数,通过多路复用实现高并发,然而,由于业务代码过度关注并发细节,需要维护很多中间状态,不但 Bug 率会很高,项目的开发速度也上不去,产品及时上线存在风险。

如果想兼顾开发效率,又能保证高并发,协程就是最好的选择。它可以在保持异步化运行机制的同时,用同步方式写代码,这在实现高并发的同时,缩短了开发周期,是高性能服务未来的发展方向。

事实上,无论基于多进程还是多线程,都难以实现高并发,这由两个原因所致。

首先,单个线程消耗的内存过多,比如,64 位的 Linux 为每个线程的栈分配了 8MB 的内存,还预分配了 64MB 的内存作为堆内存池(你可以从[第 2 讲] 中找到 Linux 系统为什么这么做)。所以,我们没有足够的内存去开启几万个线程实现并发。

其次,切换请求是内核通过切换线程实现的,什么时候会切换线程呢?不只时间片用尽,当调用阻塞方法时,内核为了让 CPU 充分工作,也会切换到其他线程执行。一次上下文切换的成本在几十纳秒到几微秒间,当线程繁忙且数量众多时,这些切换会消耗绝大部分的 CPU 运算能力。

本来由内核实现的请求切换工作,交由用户态的代码来完成就可以了,异步化编程通过应用层代码实现了请求切换,降低了切换成本和内存占用空间。
在这里插入图片描述

有没有办法既享受到异步化带来的高并发,又可以使用阻塞函数写同步化代码呢?协程可以做到,它在异步化之上包了一层外衣,兼顾了开发效率与运行效率
在这里插入图片描述

用户态的代码切换协程,与内核切换线程的原理是一样的。
在这里插入图片描述

创建协程时,会从进程的堆中(参见[第 2 讲])分配一段内存作为协程的栈。线程的栈有 8MB,而协程栈的大小通常只有几十 KB。当然,栈缩小后,就尽量不要使用递归函数,也不能在栈中申请过多的内存,这是实现高并发必须付出的代价。

**所以,协程的高性能,建立在切换必须由用户态代码完成之上,这要求协程生态是完整的,要尽量覆盖常见的组件。**使用协程实现服务器端的高并发服务时,并不只是选择协程库,还要从其生态中找到结合 IO 多路复用的协程框架,这样可以加快开发速度。

为了让协程获得更多的 CPU 时间,还可以设置所在线程的优先级,比如 Linux 下把线程的优先级设置到 -20,就可以每次获得更长的时间片。

还可以把线程绑定到某个 CPU 上,增加协程执行时命中 CPU 缓存的机率。

小结

在协程中调用的所有 API,都需要做非阻塞的协程化改造。优秀的协程生态下,常用服务都有对应的协程 SDK,方便业务代码使用。开发高并发服务时,与 IO 多路复用结合的协程框架可以与这些 SDK 配合,自动挂起、切换协程,进一步提升开发效率。

心得体会

  1. 内核态和用户态的存在,如果我没记错,主要用途是把危险的底层操作,由操作系统来执行,屏蔽了风险。随之带来的就是切换内核态的时间消耗。
  2. 协程框架的存在,即代替了操作系统进行线程的切换。即在用户态,对一个线程的执行换成了多携程,是一个更细的力度,将调度权限收到用户态手上,这是对“用户”的信任,也需要“用户“承担责任。正如文中提到的:“计算太密集从而长时间占用 CPU 的任务,还是要放在独立的线程中执行,以防止它影响所有协程的执行。”

工作体验

  1. 工作中并没有使用到协程,甚至异步回调的方式,使用的人都不多,甚至有人找我说看不懂这么写是什么意思。

    评论区“忆水寒”也提到了:“大家不知道协程(接收度比较低,觉得没用过可能会遇到很多坑,万一影响产品稳定性怎么办),而且产品里面已经充斥着大量的回调,没法大规模切换了。”

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

再学C语言37:函数、数组和指针

编写一个对数组进行操作的函数,并进行调用 一般形式举例: int sum(int * arr, int n); // 函数原型// 第一个参数把数组地址和类型信息传递给函数// 第二个参数把数组中元素的个数传递给函数int main(void) {...int total;total sum(array_t, 10);...…

分分钟你也能写一个自己需要的 Chrome 扩展程序

废话 对于chrome浏览器想必大家大不陌生了,里面的扩展程序(本文后面称插件),多多少少也都用过吧,毕竟可以辅助自己的日常工作,娱乐等等,添加完之后呢,就会多出一些操作按钮&#xf…

年度总结-你觉得什么叫生活?

陈老老老板🦸👨‍💻本文专栏:生活(主要讲一下自己生活相关的内容)👨‍💻本文简述:生活就像海洋,只有意志坚强的人,才能到达彼岸。👨‍💻上一篇文章…

Linux常用命令——tr命令

在线Linux命令查询工具(http://www.lzltool.com/LinuxCommand) tr 将字符进行替换压缩和删除 补充说明 tr命令可以对来自标准输入的字符进行替换、压缩和删除。它可以将一组字符变成另一组字符,经常用来编写优美的单行命令,作用很强大。 语法 tr(选…

云逗猫——直播弹幕控制机械臂逗猫棒

这个东西思路是很简单的。简单来说在直播画面用文字跟观看者约定一些弹幕指令,然后用爬虫爬取直播弹幕,当爬到弹幕是约定的指令时,通过串口给舵机控制板发送信号,控制板控制舵机转动,机械臂就会做相应的动作。 猫 两…

Lesson2无头单向非循环链表(中)

1.链表 1.1链表的概念及结构 概念:链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的 。 1.2链表的分类 实际中链表的结构非常多样,以下情况组合起来就有8种链表结构: 1.…

【SAP Hana】X档案:SAP HANA 数据库基础知识

SAP HANA 数据库基础知识1、基本规则(1)注释(2)标识符(3)引号(4)保留字2、数据类型(1)日期时间类型(2)数字类型(3&#xf…

SNMP简单网络管理协议

随着网络的规模越来越庞大,网络中的设备种类繁多,如何对越来越复杂的网络进行有效的管理,从而提供高质量的网络服务,已成为网络管理所面临的巨大挑战。网络的管理和运维手段多样,下面将对几种常见的网管与运维手段展开…

[leetcode.29]两数相除,位运算虽好,不要满眼是她

题目如下 不允许用乘除法,但是我们可以用加减法和位运算。。。不过这里不要用位运算,比如说你要是想用补码交替除法,你根本无法获得移动几位(移动31位?太鬼畜了吧) 所以说单纯的除法部分,我们可…

测试开发 | 实战演练基于加密接口测试测试用例设计

image1080594 76.4 KB 如果接口测试仅仅只是掌握一些requests或者其他一些功能强大的库的用法,是远远不够的,还需要具有根据公司的业务以及需求去定制化一个接口自动化测试框架能力。所以在这个部分,会主要介绍接口测试用例分析以及通用的流程…

从零开始 verilog 以太网交换机(二)MAC接收控制器的设计与实现

从零开始 verilog 以太网交换机(二)MAC接收控制器的设计与实现 🔈声明: 😃博主主页:王_嘻嘻的CSDN主页 🧨 从零开始 verilog 以太网交换机系列专栏:点击这里 🔑未经作者允…

plt绘制点线图 点(marker)过密的解决办法

设置 markevery10 plt.plot(x, y, markero, markevery10) import matplotlib.pyplot as plt import numpy as npxnp.arange(0,2*np.pi,0.01) ynp.sin(x)fig, ax plt.subplots(constrained_layoutTrue)plt.title(markevery10)ax.plot(x, y, markero, markevery50, mfcr,mecr)…

(小甲鱼python)函数笔记合集四 函数(IV)总结 函数中参数的作用域 局部作用域 全局作用域 global语句 嵌套函数 nonlocal语句等详解

一、基础复习 函数的基本用法 创建和调用函数 函数的形参与实参等等函数的几种参数 位置参数、关键字参数、默认参数等函数的收集参数*args **args 解包参数详解 二、函数中参数的作用域 作用域:一个变量可以被访问的范围,一个变量的作用域总是由它在代…

jQuery学习-01jQuery下载安装

1 jQuery的介绍 jQuery就是js函数库,里面有大量的js函数库,使用这些函数操作dom对象,做事件,动画,ajax处理; 地址:https://jquery.com/ 2下载 地址:https://jquery.com/download/…

Apache Solr 9.1-(一)初体验单机模式运行

Apache Solr 9.1-(一)初体验单机模式运行 Solr是一个基于Apache Lucene的搜索服务器,Apache Lucene是开源的、基于Java的信息检索库,Solr能为用户提供无论在任何时候都可以根据用户的查询请求返回结果,它被设计为一个强…

day12-继承

1. 继承 1.1 继承的实现(掌握) 继承的概念 继承是面向对象三大特征之一,可以使得子类具有父类的属性和方法,还可以在子类中重新定义,以及追加属性和方法 实现继承的格式 继承通过extends实现格式:class 子…

【算法题】1318. 或运算的最小翻转次数

插: 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。 坚持不懈,越努力越幸运,大家一起学习鸭~~~ 题目: 给你三个正整数 a、b 和 c。 你可…

Webpack:HTML Webpack Plugin插件

HTML Webpack Plugin插件,在Webpack构建的前端项目中,用于简化index.html文件的创建,以免除项目打包之后手动创建/拷贝index.html到打包目录下的繁琐步骤。以下,从一个已构建好的Vue项目中的一个现象谈起,逐步深入了解…

vs code中的platformIO插件,完成Arduino的程序编写,导入,安装开发板管理库

准备工作 vs code已经安装好,扩展插件plateformIO也安装好。(下图是platformIO安装方式) platformIO界面功能介绍和简单使用 新建Arduino项目 选择正确的开发板型号,和自己习惯的编译框架。打开后有一个.ini的配置文件&#x…

MySQL表的增删改查(初级)

MySQL数据库最核心的内容就是增删改查(即CURD),看了这篇初级增删改查的博客之后可以解决以后工作中百分之80-90的内容,这部分的知识并不是很难,但是需要一定的熟练程度;C:create--新增U:update-…