@@ -307,17 +307,6 @@ perf report
307
307
当你在你的系统中使用top发现CPU使用率很高,但是每个进程的CPU使用率有很小的情况下,一般是因为有短时运行进程导致的,可以使用 ` perf record` 工具或者 bcc的 ` execsnoop` 工具来确认是否有短时进程
308
308
309
309
310
-
311
-
312
-
313
-
314
-
315
-
316
-
317
-
318
-
319
-
320
-
321
310
# ### 上下文切换
322
311
进程在竞争CPU的时候,并没有真正运行,为什么还会导致系统的负载升高?聪明的你一定想到了-CPU上下文切换
323
312
Linux 是一个多任务操作系统,它支持远大于 CPU 数量的任务同时运行。当然,这些任务实际上并不是真的在同时运行,而是因为系统在很短的时间内,将 CPU 轮流分配给它们,造成多任务同时运行的错觉。
@@ -621,6 +610,7 @@ CPU 使用率描述了非空闲时间占总 CPU 时间的百分比,根据 CPU
621
610
622
611
# # 内存
623
612
613
+ ! [[Pasted image 20250626171804.png]]
624
614
同 CPU 管理一样,内存管理也是操作系统最核心的功能之一。内存主要用来存储系统和应用程序的指令、数据、缓存等。
625
615
626
616
# ## 内存原理
@@ -703,42 +693,212 @@ MiB Swap: 0.0/15968.0 [ ]
703
693
- SHR 是共享内存的大小,比如与其他进程共同使用的共享内存、加载的动态链接库以及程序的代码段等。
704
694
- %MEM 是进程使用物理内存占系统总内存的百分比。
705
695
696
+ > 其中缓存是 Buffer 和 Cache 两部分的总和 。
697
+
706
698
在查看 top 输出时,你还要注意两点。
707
699
- 第一,虚拟内存通常并不会全部分配物理内存。从上面的输出,你可以发现每个进程的虚拟内存都比常驻内存大得多。
708
700
- 第二,共享内存 SHR 并不一定是共享的,比方说,程序的代码段、非共享的动态链接库,也都算在 SHR 里。当然,SHR 也包括了进程间真正共享的内存。所以在计算多个进程的内存使用时,不要把所有进程的 SHR 直接相加得出结果
709
701
710
702
711
- # ### 怎么理解内存中的Buffer和Cache?
703
+ # #### 怎么理解内存中的Buffer和Cache?
704
+ Buffer 和 Cache 可能不太好区分。从字面上来说, Buffer 是缓冲区,而 Cache 是缓存,两者都是数据在内存中的临时存储。那么,你知道这两种“临时存储”有什么区别吗?
712
705
706
+ > 注:今天内容接下来的部分,Buffer 和 Cache 我会都用英文来表示,避免跟文中的“缓存”一词混淆。而文中的“缓存”,则通指内存中的临时存储
713
707
714
- # ### 虚拟内存
715
- # ### 内存分配与回收
716
- # ### 缓存与缓冲区
717
- # ### SWAP
708
+ ` ` ` bash
709
+ buffers
710
+ Memory used by kernel buffers (Buffers in /proc/meminfo)
711
+ cache
712
+ Memory used by the page cache and slabs (Cached and SReclaimable in /proc/meminfo)
713
+ buff/cache
714
+ Sum of buffers and cache
715
+ ` ` `
716
+ - Buffers 是内核缓冲区用到的内存,对应的是 /proc/meminfo 中的 Buffers 值
717
+ - Cache 是内核页缓存和 Slab 用到的内存,对应的是 /proc/meminfo 中的 Cached 与SReclaimable 之和
718
718
719
+
720
+ Buffer 既可以用作“将要写入磁盘数据的缓存”,也可以用作“从磁盘读取数据的缓存”。
721
+ Cache 既可以用作“从文件读取数据的页缓存”,也可以用作“写文件的页缓存”
722
+
723
+ 简单来说,Buffer 是对磁盘数据的缓存,而 Cache 是文件数据的缓存,它们既会用在读请求中,也会用在写请求中。
724
+
725
+
726
+ # ### SWAP
727
+ 除了系统内存和进程内存,第三类重要指标就是 Swap 的使用情况,比如 Swap 的已用空间、剩余空间、换入速度和换出速度等。
728
+ 已用空间和剩余空间很好理解,就是字面上的意思,已经使用和没有使用的内存空间。换入和换出速度,则表示每秒钟换入和换出内存的大小。
719
729
# ## 性能指标
720
- # ### 系统内存使用量
721
- # ### 进程内存使用量
722
- # ### 缓存与缓冲区命中率
723
- # ### SWAP使用量
730
+ # ### 根据指标找工具
731
+
732
+ ! [[Pasted image 20250626172055.png]]
733
+
734
+
735
+ # ### 根据工具找指标
736
+
737
+ ! [[Pasted image 20250626172120.png]]
738
+
724
739
725
740
# ## 性能剖析
726
741
727
- # ### top
728
- # ### sar
742
+ # ### 快速定位性能问题
743
+ 1. 先用 free 和 top,查看系统整体的内存使用情况。
744
+ 2. 再用 vmstat 和 pidstat,查看一段时间的趋势,从而判断出内存问题的类型。
745
+ 3. 最后进行详细分析,比如内存分配分析、缓存 / 缓冲区分析、具体进程的内存使用分析等
746
+
747
+ ! [[Pasted image 20250626172857.png]]
748
+
749
+ # ### proc文件系统
750
+
751
+ # ## 调优方法
752
+ # ### 如何利用系统缓存优化程序的运行效率?
753
+ Buffer 和Cache 的设计目的,是为了提升系统的 I/O 性能。它们利用内存,充当起慢速磁盘与快速CPU 之间的桥梁,可以加速 I/O 的访问速度。
754
+
755
+ Buffer 和 Cache 分别缓存的是对磁盘和文件系统的读写数据。
756
+ 从写的角度来说,不仅可以优化磁盘和文件的写入,对应用程序也有好处,应用程序可以在数据真正落盘前,就返回去做其他工作。
757
+ 从读的角度来说,不仅可以提高那些频繁访问数据的读取速度,也降低了频繁 I/O 对磁盘的压力。
758
+
759
+
760
+ # #### 利用缓存与缓冲区
761
+ 我们想利用缓存来提升程序的运行效率,应该怎么评估这个效果呢?换句话说,有没有哪个指标可以衡量缓存使用的好坏呢?
762
+
763
+ 聪明的你肯定想到了-缓存的命中率。所谓缓存命中率,是指直接通过缓存获取数据的请求次数,占所有数据请求次数的百分比
764
+
765
+ 命中率越高,表示使用缓存带来的收益越高,应用程序的性能也就越好。
766
+
767
+ 实际上,缓存是现在所有高并发系统必需的核心模块,主要作用就是把经常访问的数据(也就是热点数据),提前读入到内存中。这样,下次访问时就可以直接从内存读取数据,而不需要经过硬盘,从而加快应用程序的响应速度。
768
+
769
+ 这些独立的缓存模块通常会提供查询接口,方便我们随时查看缓存的命中情况。不过 Linux系统中并没有直接提供这些接口,所以这里我要介绍一下,cachestat 和 cachetop ,它们正是查看系统缓存命中情况的工具。
770
+
771
+ - cachestat 提供了整个操作系统缓存的读写命中情况
772
+ - cachetop 提供了每个进程的缓存命中情况。
773
+
774
+ # #### 指定文件的缓存大小
775
+ 指定文件在内存中的缓存大小和缓存比例,可以使用pcstat工具进行获取
776
+
777
+ pcstat使用go语言编写,可以在这里下载 [https://github.com/tobert/pcstat](https://github.com/tobert/pcstat)
778
+
779
+ dd读取文件,首次慢,但是第二次快,可以通过以上命令查看,第二次快因为缓存命中率高了,首次读取的时候文件都缓存到缓存了
780
+
781
+
782
+ # ### 缺页异常
783
+ 系统调用内存分配之后,并不会立刻为其分配物理内存,而是请求首次访问时通过缺页异常来分配,缺页异常又分为一下两种场景:
784
+ - 可以直接从物理内存中分配,被称为次缺页内异常
785
+ - 需要磁盘I/O介入(比如swap)时,被称为主缺页异常
786
+ ** 显然,主缺页异常升高,就意味着需要磁盘 I/O,那么内存访问也会慢很多。**
787
+
788
+
789
+
790
+ # # 文件系统
791
+ 磁盘为系统提供了最基本的持久化存储。
792
+ 文件系统则在磁盘的基础上,提供了一个用来管理文件的树状结构
793
+ # ## 文件系统原理
794
+ 文件系统,本身是对存储设备上的文件,进行组织管理的机制。组织方式不同,就会形成不同的文件系统。
795
+ 你要记住最重要的一点,在 Linux 中一切皆文件。不仅普通的文件和目录,就连块设备、套接字、管道等,也都要通过统一的文件系统来管理
796
+
797
+ 为了方便管理,Linux 文件系统为每个文件都分配两个数据结构,索引节点(index node)和目录项(directory entry)。它们主要用来记录文件的元信息和目录结构。
798
+
799
+ 索引节点,简称为 inode,用来记录文件的元数据,比如 inode 编号、文件大小、访问权限、修改日期、数据的位置等。索引节点和文件一一对应,它跟文件内容一样,都会被持久化存储到磁盘中。所以记住,索引节点同样占用磁盘空间。
800
+
801
+ 目录项,简称为 dentry,用来记录文件的名字、索引节点指针以及与其他目录项的关联关系。多个关联的目录项,就构成了文件系统的目录结构。不过,不同于索引节点,目录项是由内核维护的一个内存数据结构,所以通常也被叫做目录项缓存。
802
+
803
+ 换句话说,索引节点是每个文件的唯一标志,而目录项维护的正是文件系统的树状结构。目录项和索引节点的关系是多对一,你可以简单理解为,一个文件可以有多个别名。
804
+ ! [[Pasted image 20250626192701.png]]
805
+ # ### 虚拟文件系统
806
+ 目录项、索引节点、逻辑块以及超级块,构成了 Linux 文件系统的四大基本要素。不过,为了支持各种不同的文件系统,Linux 内核在用户进程和文件系统
7802
的中间,又引入了一个抽象层,也就是虚拟文件系统 VFS(Virtual File System)
807
+ VFS 定义了一组所有文件系统都支持的数据结构和标准接口。这样,用户进程和内核中的其他子系统,只需要跟 VFS 提供的统一接口进行交互就可以了,而不需要再关心底层各种文件系统的实现细节
808
+
809
+ ! [[Pasted image 20250626192801.png]]
810
+ 通过这张图,你可以看到,在 VFS 的下方,Linux 支持各种各样的文件系统,如 Ext4、XFS、NFS 等等。按照存储位置的不同,这些文件系统可以分为三类。
811
+
812
+ - 第一类是基于磁盘的文件系统,也就是把数据直接存储在计算机本地挂载的磁盘中。常见的 Ext4、XFS、OverlayFS 等,都是这类文件系统。
813
+
814
+ - 第二类是基于内存的文件系统,也就是我们常说的虚拟文件系统。这类文件系统,不需要任何磁盘分配存储空间,但会占用内存。我们经常用到的 /proc 文件系统,其实就是一种最常见的虚拟文件系统。此外,/sys 文件系统也属于这一类,主要向用户空间导出层次化的内核对象。
815
+
816
+ - 第三类是网络文件系统,也就是用来访问其他计算机数据的文件系统,比如 NFS、SMB、iSCSI 等。
817
+ 这些文件系统,要先挂载到 VFS 目录树中的某个子目录(称为挂载点),然后才能访问其中的文件。拿第一类,也就是基于磁盘的文件系统为例,在安装系统时,要先挂载一个根目录(/),在根目录下再把其他文件系统(比如其他的磁盘分区、/proc 文件系统、/sys 文件系统、NFS 等)挂载进来。
818
+ # ### 文件系统I/O栈
819
+ 把文件系统挂载到挂载点后,你就能通过挂载点,再去访问它管理的文件了。VFS 提供了一组标准的文件访问接口。这些接口以系统调用的方式,提供给应用程序使用。
820
+
821
+ 文件读写方式的各种差异,导致 I/O 的分类多种多样。最常见的有,缓冲与非缓冲 I/O、直接与非直接 I/O、阻塞与非阻塞 I/O、同步与异步 I/O 等。 接下来,我们就详细看这四种分类
822
+
823
+ 1. 第一种,根据是否利用标准库缓存,可以把文件 I/O 分为缓冲 I/O 与非缓冲 I/O。
824
+ - 缓冲 I/O,是指利用标准库缓存来加速文件的访问,而标准库内部再通过系统调度访问文件。
825
+ - 非缓冲 I/O,是指直接通过系统调用来访问文件,不再经过标准库缓存。
826
+ > 注意,这里所说的“缓冲”,是指标准库内部实现的缓存。比方说,你可能见到过,很多程序遇到换行时才真正输出,而换行前的内容,其实就是被标准库暂时缓存了起来。
827
+ > 无论缓冲 I/O 还是非缓冲 I/O,它们最终还是要经过系统调用来访问文件。而根据上一节内容,我们知道,系统调用后,还会通过页缓存,来减少磁盘的 I/O 操作。
828
+ 2. 第二,根据是否利用操作系统的页缓存,可以把文件 I/O 分为直接 I/O 与非直接 I/O
829
+ - 直接 I/O,是指跳过操作系统的页缓存,直接跟文件系统交互来访问文件。
830
+ - 非直接 I/O 正好相反,文件读写时,先要经过系统的页缓存,然后再由内核或额外的系统调用,真正写入磁盘
831
+ > 想要实现直接 I/O,需要你在系统调用中,指定 O_DIRECT 标志。如果没有设置过,默认的是非直接 I/O。
832
+ > 不过要注意,直接 I/O、非直接 I/O,本质上还是和文件系统交互。如果是在数据库等场景中,你还会看到,跳过文件系统读写磁盘的情况,也就是我们通常所说的裸 I/O。
833
+ 3. 第三,根据应用程序是否阻塞自身运行,可以把文件 I/O 分为阻塞 I/O 和非阻塞 I/O:
834
+ - 所谓阻塞 I/O,是指应用程序执行 I/O 操作后,如果没有获得响应,就会阻塞当前线程,自然就不能执行其他任务
835
+ - 所谓非阻塞 I/O,是指应用程序执行 I/O 操作后,不会阻塞当前的线程,可以继续执行其他的任务,随后再通过轮询或者事件通知的形式,获取调用的结果
836
+ > 比方说,访问管道或者网络套接字时,设置 O_NONBLOCK 标志,就表示用非阻塞方式访问;而如果不做任何设置,默认的就是阻塞访问
837
+ 4. 第四,根据是否等待响应结果,可以把文件 I/O 分为同步和异步 I/O:
838
+ - 所谓同步 I/O,是指应用程序执行 I/O 操作后,要一直等到整个 I/O 完成后,才能获得I/O 响应。
839
+ - 所谓异步 I/O,是指应用程序执行 I/O 操作后,不用等待完成和完成后的响应,而是继续执行就可以。等到这次 I/O 完成后,响应会用事件通知的方式,告诉应用程序
840
+ > 举个例子,在操作文件时,如果你设置了 O_SYNC 或者 O_DSYNC 标志,就代表同步I/O。如果设置了 O_DSYNC,就要等文件数据写入磁盘后,才能返回;而 O_SYNC,则是在 O_DSYNC 基础上,要求文件元数据也要写入磁盘后,才能返回。
841
+ > 再比如,在访问管道或者网络套接字时,设置了 O_ASYNC 选项后,相应的 I/O 就是异步I/O。这样,内核会再通过 SIGIO 或者 SIGPOLL,来通知进程文件是否可读写。
842
+
843
+ # ### 文件系统缓存
844
+ # ### 文件系统种类
845
+ # ## 性能指标
846
+ # ### 容量
847
+ ` ` ` bash
848
+ # -h 人类可读形式展示
849
+ df -h /dev/sda1
850
+ # -it 索引节点占用情况也展示出来
851
+ df -i /dev/sfa1
852
+ ` ` `
853
+ 索引节点的容量,(也就是 Inode 个数)是在格式化磁盘时设定好的,一般由格式化工具自动生成。当你发现索引节点空间不足,但磁盘空间充足时,很可能就是过多小文件导致的。
854
+ 所以,一般来说,删除这些小文件,或者把它们移动到索引节点充足的其他磁盘中,就可以解决这个问题。
855
+ # ### IOPS
856
+ # ### 缓存命中率
857
+ # ## 性能剖析
858
+ # ### df
859
+ # ### strace
729
860
# ### vmstat
730
- # ### cachestat
731
- # ### cachetop
732
- # ### memleak
861
+ # ### sar
862
+ # ### perf
733
863
# ### proc文件系统
864
+ # ## 调优方法
865
+ # ### 文件系统选型
866
+ # ### 利用文件系统缓存
867
+ # ### I/O隔离
868
+
869
+
870
+ # # 磁盘I/O
871
+
872
+
873
+
874
+ # ## 磁盘IO原理
875
+ # ### 磁盘管理
876
+ # ### 磁盘类型
877
+ # ### 磁盘接口
878
+ # ### 磁盘I/O栈
879
+ # ## 性能指标
880
+ # ### 使用率
881
+ # ### IOPS
882
+ # ### 吞吐量
883
+ # ### IOWAIT
884
+ # ## 性能剖析
885
+ # ### dstat
886
+ # ### sar
887
+ # ### iostat
888
+ # ### pidstat
889
+ # ### iotop
890
+ # ### iolatency
891
+ # ### blktrace
892
+ # ### fio
893
+ # ### perf
734
894
735
895
# ## 调优方法
736
- # ### 利用缓存与缓冲区
737
- # ### 减少SWAP使用
738
- # ### 减少动态内存分配
739
- # ### 优化NUMA
740
- # ### 限制进程资源
741
- # ### 使用HugePage
896
+ # ### 系统调用
897
+ # ### I/O资源控制
898
+ # ### 充分利用缓存
899
+ # ### RAID
900
+ # ### I/O隔离
901
+
742
902
743
903
# # 网络
744
904
# ## 网络原理
@@ -791,56 +951,6 @@ MiB Swap: 0.0/15968.0 [ ]
791
951
# #### 负载均衡
792
952
# #### DPDK
793
953
794
- # # 磁盘I/O
795
- # ## 磁盘IO原理
796
- # ### 磁盘管理
797
- # ### 磁盘类型
798
- # ### 磁盘接口
799
- # ### 磁盘I/O栈
800
- # ## 性能指标
801
- # ### 使用率
802
- # ### IOPS
803
- # ### 吞吐量
804
- # ### IOWAIT
805
- # ## 性能剖析
806
- # ### dstat
807
- # ### sar
808
- # ### iostat
809
- # ### pidstat
810
- # ### iotop
811
- # ### iolatency
812
- # ### blktrace
813
- # ### fio
814
- # ### perf
815
-
816
- # ## 调优方法
817
- # ### 系统调用
818
- # ### I/O资源控制
819
- # ### 充分利用缓存
820
- # ### RAID
821
- # ### I/O隔离
822
-
823
- # # 文件系统
824
- # ## 文件系统原理
825
- # ### 虚拟文件系统
826
- # ### 文件系统I/O栈
827
- # ### 文件系统缓存
828
- # ### 文件系统种类
829
- # ## 性能指标
830
- # ### 容量
831
- # ### IOPS
832
- # ### 缓存命中率
833
- # ## 性能剖析
834
- # ### df
835
- # ### strace
836
- # ### vmstat
837
- # ### sar
838
- # ### perf
839
- # ### proc文件系统
840
- # ## 调优方法
841
- # ### 文件系统选型
842
- # ### 利用文件系统缓存
843
- # ### I/O隔离
844
954
845
955
# # linux内核
846
956
# ## 内核原理
0 commit comments