【Performance】Linux 性能问题调优 - 内存

Posted by 西维蜀黍 on 2020-11-15, Last Modified on 2022-04-06

Background

物理内存就是系统硬件提供的内存大小,是真正的内存,相对于物理内存,在linux下还有一个虚拟内存的概念,虚拟内存就是为了满足物理内存的不足而提出的策略,它是利用磁盘空间虚拟出的一块逻辑内存,用作虚拟内存的磁盘空间被称为交换空间(Swap Space)。

作为物理内存的扩展,linux会在物理内存不足时,使用交换分区的虚拟内存,更详细的说,就是内核会将暂时不用的内存块信息写到交换空间,这样以来,物理内存得到了释放,这块内存就可以用于其它目的,当需要用到原始的内容时,这些信息会被重新从交换空间读入物理内存。

linux的内存管理采取的是分页存取机制,为了保证物理内存能得到充分的利用,内核会在适当的时候将物理内存中不经常使用的数据块自动交换到虚拟内存中,而将经常使用的信息保留到物理内存。

在Linux内存管理中,主要是通过“调页Paging”和“交换Swapping”来完成上述的内存调度。调页算法是将内存中最近不常使用的页面换到磁盘上,把活动页面保留在内存中供进程使用。交换技术是将整个进程,而不是部分页面,全部交换到磁盘上。

分页(Page)写入磁盘的过程被称作Page-Out,分页(Page)从磁盘重新回到内存的过程被称作Page-In。当内核需要一个分页时,但发现此分页不在物理内存中(因为已经被Page-Out了),此时就发生了分页错误(Page Fault)。

dmesg - OOM 问题

$ dmesg -T

可以查看是否有进程因为 OOM(out-of memory)被OOM killer kill 掉。

找到使用内存最多的进程

This will show you top 10 process that using the most memory:

ps aux --sort=-%mem | head

# or
ps -o pid,user,%mem,command ax | sort -b -k3 -r

# or 
ps aux | sort -rnk 4 | head -5

Or

Use htop, hit F6 and choose Sort by M_SIZE

free

$ free -h -w -t
              total        used        free      shared     buffers       cache   available
Mem:           8.0G        3.1G        3.2G          0B          0B        1.6G        4.9G
Swap:            0B          0B          0B
Total:         8.0G        3.1G        3.2G
  • total: Total
    • installed memory (MemTotal and SwapTotal in /proc/meminfo)
  • used: Used memory (calculated as total - free - buffers - cache)
  • b: Unused memory (MemFree and SwapFree in /proc/meminfo)
  • shared: Memory used (mostly) by tmpfs (Shmem in /proc/meminfo)
  • buffers: Memory used by kernel buffers (Buffers in /proc/meminfo)
  • cache: Memory used by the page cache and slabs (Cached and SReclaimable in /proc/meminfo)
  • buff/cache: Sum of buffers and cache
  • available: Estimation of how much memory is available for starting new applications, without swapping. Unlike the data provided by the cache or free fields, this field takes into account page cache and also that not all reclaimable memory slabs will be reclaimed due to items being in use (MemAvailable in /proc/meminfo, available on kernels 3.14, emulated on kernels 2.6.27+, otherwise the same as free)

Parameters

Usage:
 free [options]

Options:
 -b, --bytes         show output in bytes
 -k, --kilo          show output in kilobytes
 -m, --mega          show output in megabytes
 -g, --giga          show output in gigabytes
     --tera          show output in terabytes
 -h, --human         show human-readable output
     --si            use powers of 1000 not 1024
 -l, --lohi          show detailed low and high memory statistics
 -t, --total         show total for RAM + swap
 -s N, --seconds N   repeat printing every N seconds
 -c N, --count N     repeat printing N times, then exit
 -w, --wide          wide output

     --help     display this help and exit
 -V, --version  output version information and exit

vmstat - 查看内存及虚拟内存使用

vmstat reports information about processes, memory, paging, block IO, traps, disks and cpu activity.

Usage:
 vmstat [options] [delay [count]]

Options:
 -a, --active           active/inactive memory
 -f, --forks            number of forks since boot
 -m, --slabs            slabinfo
 -n, --one-header       do not redisplay header
 -s, --stats            event counter statistics
 -d, --disk             disk statistics
 -D, --disk-sum         summarize disk statistics
 -p, --partition <dev>  partition specific statistics
 -S, --unit <char>      define display unit, options: k, K, m or M
 -w, --wide             wide output
 -t, --timestamp        show timestamp

 -h, --help     display this help and exit
 -V, --version  output version information and exit

vmstat -S M -w 1 - Common Usage

加宽输出,1s更新一次,单位为MB:

$ vmstat -S M -w 1
procs -----------------------memory---------------------- ---swap-- -----io---- -system-- --------cpu--------
 r  b         swpd         free         buff        cache   si   so    bi    bo   in   cs  us  sy  id  wa  st
 0  1            0         4106          116         3086    0    0     0     1    1    0   0   0 100   0   0
 0  0            0         4107          116         3086    0    0     0     4  111  123   0   0 100   0   0
 0  0            0         4107          116         3086    0    0     0    16   41   68   0   0 100   0   0
 0  0            0         4107          116         3086    0    0     0     0   43   71   0   0 100   0   0
 0  0            0         4107          116         3086    0    0     0     0   56   92   0   0 100   0   0
 0  0            0         4107          116         3086    0    0     0     0   31   53   0   0 100   0   0
 0  0            0         4107          116         3086    0    0     0    16   39   71   0   0 100   0   0
 0  0            0         4107          116         3086    0    0     0     8   58   94   0   0 100   0   0
 0  0            0         4106          116         3086    0    0     0     0   84  122   0   0 100   0   0
 0  0            0         4106          116         3086    0    0     0     0   33   51   0   0 100   0   0
 0  0            0         4106          116         3086    0    0     0     0   53   95   0   0 100   0   0
 0  0            0         4106          116         3086    0    0     0     0   33   59   0   0 100   0   0
 0  0            0         4106          116         3086    0    0     0     0   41   78   0   0 100   0   0
 0  0            0         4106          116         3086    0    0     0     0   47   68   0   0 100   0   0
 0  0            0         4106          116         3086    0    0     0     0   31   58   0   0 100   0   0
 0  0            0         4106          116         3086    0    0     0     0  273  406   0   0 100   0   0
 0  0            0         4106          116         3086    0    0     0     0   58   97   0   0 100   0   0
 0  0            0         4106          116         3086    0    0     0     0   40   68   0   0 100   0   0

Procs(进程):

  • r: 运行队列中进程数量(The number of processes waiting for run time)
  • b: 等待IO的进程数量(The number of processes in uninterruptible sleep)

Memory(内存):

  • swpd: 使用虚拟内存大小(the amount of virtual memory used)
  • free: 可用内存大小(the amount of idle memory)
  • buff: 用作缓冲的内存大小(the amount of memory used as buffers)
  • cache: 用作缓存的内存大小(the amount of memory used as cache)

Swap:

  • si: 每秒从交换区写到内存的大小(Amount of memory swapped in from disk (/s))
  • so: 每秒写入交换区的内存大小(Amount of memory swapped to disk (/s))

IO:

(现在的Linux版本块的大小为1024bytes)

  • bi: 每秒读取的块数(Blocks received from a block device (blocks/s))
  • bo: 每秒写入的块数(Blocks sent to a block device (blocks/s))

system:

  • in: 每秒中断数,包括时钟中断(The number of interrupts per second, including the clock)
  • cs: 每秒上下文切换数(The number of context switches per second)

CPU(以百分比表示)

  • us: 用户进程执行时间(user time)- Time spent running non-kernel code
  • sy: 系统进程执行时间(system time)- Time spent running kernel code
  • id: 空闲时间(包括IO等待时间)- Time spent idle. Prior to Linux 2.5.41, this includes IO-wait time
  • wa: 等待IO时间 - Time spent waiting for IO. Prior to Linux 2.5.41, included in idle
  • st: Time stolen from a virtual machine. Prior to Linux 2.6.11, unknown

Analysis

注意:如果r(运行队列中进程数量)经常大于4 ,且id(CPU 空闲时间)经常少于40%,表示 CPU 的负荷很重。如果bi(每秒从磁盘交换区写到内存的块的数量),bo (每秒写入磁盘交换区的块的数量)长期不等于0,表示内存不足。

通过 vmstat 识别CPU瓶颈:

  • r(运行队列)展示了正在执行和等待CPU资源的任务个数。当这个值超过了CPU数目,就会出现CPU瓶颈了。

Linux下查看CPU核心数的命令:

$ cat /proc/cpuinfo|grep processor|wc -l

当r值超过了CPU个数,就会出现CPU瓶颈,解决办法大体几种:

  1. 最简单的就是增加CPU个数和核数
  2. 通过调整任务执行时间,如大任务放到系统不繁忙的情况下进行执行,进而平衡系统任务
  3. 调整已有任务的优先级

通过 vmstat 识别CPU满负荷:

首先需要声明一点的是,vmstat中CPU的度量是百分比的。当us+sy(用户进程执行时间 + 系统进程执行时间)的值接近100的时候,表示CPU正在接近满负荷工作。但要注意的是,CPU 满负荷工作并不能说明什么,Linux总是试图要CPU尽可能的繁忙,使得任务的吞吐量最大化。唯一能够确定CPU瓶颈的还是r(运行队列)的值。

通过 vmstat 识别RAM瓶颈:

首先用free查看RAM的数量:

$ free -h
              total        used        free      shared  buff/cache   available
Mem:           7.3G        153M        4.0G         89M        3.1G        6.7G
Swap:            0B          0B          0B
  • 当内存的需求大于RAM的数量,服务器启动了虚拟内存机制,通过虚拟内存,可以将RAM段移到SWAP DISK的特殊磁盘段上,这样会出现虚拟内存的页导出(Page-out)和页导入(Page-in)现象;
  • 页导出并不能说明RAM瓶颈,虚拟内存系统经常会对内存段进行页导出,但页导入操作就表明了服务器需要更多的内存了, 页导入需要从SWAP DISK上将内存段复制回RAM,导致服务器速度变慢。

vmstat -s - 查看内存使用的详细信息

$ vmstat -s
      7642844 K total memory
       157644 K used memory
       724120 K active memory
      2332472 K inactive memory
      4205700 K free memory
       119140 K buffer memory
      3160360 K swap cache
            0 K total swap
            0 K used swap
            0 K free swap
       407491 non-nice user cpu ticks
          121 nice user cpu ticks
       388531 system cpu ticks
   2132614502 idle cpu ticks
        67627 IO-wait cpu ticks
            0 IRQ cpu ticks
        10148 softirq cpu ticks
       155999 stolen cpu ticks
       713412 pages paged in
     20725480 pages paged out
            0 pages swapped in
            0 pages swapped out
    157302182 interrupts
    260885596 CPU context switches
   1603299411 boot time
       603894 forks

vmstat -d -S M - 查看磁盘的读/写

$ vmstat -d -S M
disk- ------------reads------------ ------------writes----------- -----IO------
       total merged sectors      ms  total merged sectors      ms    cur    sec
loop0     10      0      32       0      0      0       0       0      0      0
loop1      0      0       0       0      0      0       0       0      0      0
loop2      0      0       0       0      0      0       0       0      0      0
loop3      0      0       0       0      0      0       0       0      0      0
loop4      0      0       0       0      0      0       0       0      0      0
loop5      0      0       0       0      0      0       0       0      0      0
loop6      0      0       0       0      0      0       0       0      0      0
loop7      0      0       0       0      0      0       0       0      0      0
sr0        0      0       0       0      0      0       0       0      0      0
vda    24507    157 1426792    9652 2125511 2428541 41451976  864024      0     79

merged:表示一次来自于合并的写/读请求,一般系统会把多个连接/邻近的读/写请求合并到一起来操作.

Reads

  • total: Total reads completed successfully
  • merged: grouped reads (resulting in one I/O)
  • sectors: Sectors read successfully
  • ms: milliseconds spent reading

Writes

  • total: Total writes completed successfully
  • merged: grouped
  • writes (resulting in one I/O)
  • sectors: Sectors written successfully
  • ms: milliseconds spent writing

IO

  • cur: I/O in progress
  • s: seconds spent for I/O

sar

sar -r - 查看 Memory 使用

sar -r: 指定-r之后,可查看物理内存使用状况:

$ sar -r 1 3
... 	05/07/2020 	_x86_64_	(1 CPU)

08:16:42 AM kbmemfree kbmemused  %memused kbbuffers  kbcached  kbcommit   %commit  kbactive   kbinact   kbdirty
08:16:43 AM    260984    730648     73.68     28252    179944   2226192    177.56    407532    153884         0
08:16:44 AM    260792    730840     73.70     28252    179944   2226192    177.56    407536    153884         0
08:16:45 AM    260792    730840     73.70     28252    179944   2226192    177.56    407544    153884         0
Average:       260856    730776     73.69     28252    179944   2226192    177.56    407537    153884         0
$ free
              total        used        free      shared  buff/cache   available
Mem:         991632      433948      260872        9736      296812      360060
Swap:        262140      118760      143380
  • kbmemfree:这个值和free命令中的free值基本一致,所以它不包括buffer和cache的空间
  • kbmemused:这个值和free命令中的used值基本一致,所以它包括buffer和cache的空间
  • %memused:物理内存使用率,这个值是kbmemused和内存总量(不包括swap)的一个百分比
  • kbbuffers和kbcached:这两个值就是free命令中的buffer和cache
  • kbcommit:保证当前系统所需要的内存,,即为了确保不溢出而需要的内存(RAM+swap)
  • %commit:这个值是kbcommit与内存总量(包括swap)的一个百分比

sar -W - 查看页面交换发生状况

页面发生交换时,服务器的吞吐量会大幅下降;服务器状况不良时,如果怀疑因为内存不足而导致了页面交换的发生,可以使用这个命令来确认是否发生了大量的交换;

$ sar -W
08:00:01 AM  pswpin/s pswpout/s
08:10:01 AM      0.00      0.00
08:20:01 AM      0.00      0.00
Average:         0.00      0.00
  • pswpin/s:每秒系统换入的交换页面(swap page)数量
  • pswpout/s:每秒系统换出的交换页面(swap page)数量

Reference