性能瓶颈--MEM(swap)

内存的性能瓶颈主要集中在两点,一个是内存不足,一个是没有充分的利用buffer/cache 。
这里先介绍内存资源不足吧,毕竟应用程序不在 buffer/cache 里读写的可能性不大,除非程序员自己设置直接I/O。否则至少也用的是缓存I/O。当然一些动态链接库也有自己的缓存。

内存回收

当有内存资源不足的时候,就会导致内存回收,也就是释放掉回收的内存,比如buffer/cache 就属于可回收内存,他们在内存管理中叫做文件页(File-backend Page)。大部分的文件页都可以直接回收,以后有需要的时候,再从磁盘重新读取,而那些已经被应用程序改过的,暂时还没有写入磁盘的数据,在内存管理中就叫脏页。需要先写到磁盘中,内存才能得到释放。
当然这些脏页一般通过2种方式写入磁盘,

  • 应用程序中的fsync
  • 内核线程pdflush

除了文件页之外,另一种就是匿名页(Anonymous Page),这些可以是应用程序动态分配的堆内存,这些可以被回收么?当然不能直接回收,要不程序再次访问自己申请的内存时,内存资源突然不见,这可怎么整。但这些内存很少被访问,所以会被放到磁盘中。当再次访问时,会发生主缺页异常(major page faults),再重新加载进内存中。这就是linux中的swap机制。

swap原理

swap说白了就是把一块磁盘空间或者一个本地文件当成内存使用。他包含了换入和换出的两个过程。

  • 换出:就是把进程暂时不用的内存数据存储到磁盘上,并释放这些数据占用的内存。
  • 换入:进程再次访问内存时,从磁盘重新读入内存中。

也就是linux在内存回收方面,做了两件事。

  • 直接内存回收:回收一部分缓存,进而满足新内存的申请请求。
  • 定期内存回收:内核通过kswapd0定期回收内存。

什么时候会定期内存回收

定期回收内存是由内核进程kswapd0来进行的。为了衡量内存的使用情况,kswapd0定义了三个阈值。

 

内存使用阈值

 

kswapd0是根据三个阈值进行内存的回收操作的。

  • 当剩余内存小于页最小阈值时,只有内核才可以分配新的内存。
  • 当剩余内存大于页最小阈值并小于页底阈值时,说明此时内存压力巨大,此时wswapd0会一直回收内存,直到内存大于高阈值。
  • 当剩余内存大于页底阈值并小于页高阈值,说明内存存在一定的压力,但还算满足新的内存申请。
  • 当剩余内存大于页高阈值时,说明内存无压力。

当剩余内存小于页底阈值就会触发内存回收,这个页底阈值一般是通过内核选项 /proc/sys/vm/min_free_kbytes 设置。

 

$ cat /proc/sys/vm/min_free_kbytes 
67584

而剩余的两个阈值是由页底阈值计算生成的。

 

pages_low = pages_min*5/4
pages_high = pages_min*3/2

在 /proc/zoneinfo中可以看到当前的三个阈值

 

$ cat /proc/zoneinfo 
Node 0, zone      DMA
  pages free     3840
        min      69
        low      86
        high     103
        scanned  0
        spanned  4095
        present  3997
        managed  3976
    nr_free_pages 3840
    nr_alloc_batch 17
    nr_inactive_anon 21
    nr_active_anon 8
    nr_inactive_file 13
    nr_active_file 0

这里的 min、low、high是内存页数的阈值。free是剩余内存页数。
nr_zone_active_anon 和 nr_zone_inactive_anon ,分别是活跃和非活跃的匿名页数。
nr_zone_active_file 和 nr_zone_inactive_file ,分别是活跃和非活跃的文件页数。

swap的回收偏向

上面只是说了什么时候会回收内存,但刚才也说到了,内存不够了,一种方式是释放文件页。另一种方式就是将匿名页写入到磁盘(swap)。
两种方式,linux更倾向于哪一种呢?
内核参数 /proc/sys/vm/swappiness 。是用来调整swap的积极性的,也就是说这个参数越高,内存的回收更倾向于swap机制,反则倾向于释放buffer/cache 。但这个参数设置为0 并不代表就不会使用swap了

swap好吗?

实则根据业务场景,大部分应用都不需要开启swap的。在hadoop,es等java应用其实都是应该关闭swap的,因为java代码在gc时,会遍历所有用到的堆内存,如果这部分内存是在swap上,遍历操作可能就变成磁盘io了。
swap是针对小内存的一种优化,现在的线上服务器动辄128G内存,所以没必要开启swap。如果要开启的话,也是建议将 /proc/swappiness 设置一个较小的值,如10。
另一种场景下,kubernets集群一般会关闭swap。因为开启swap后,通过cgroups设置的内存上限会失效。
响应延迟敏感性的应用如果在开启swap的服务器上运行的话,可以使用库函数 mlock() 或者 mlockall() 锁定内存,阻止内存的换出和换进。
另一个就是numa架构,非一致性内存访问。这个最好也关掉,跨node访问也会造成严重的性能问题。

我的应用开始使用swap了?

既然swap会造成应用程序的性能问题,那么怎么知道我的某个具体的程序开始使用swap了?

 

$ pidstat -r 1
Linux 3.10.0-957.el7.x86_64 (vm1.centos7.com)   2019年04月05日     _x86_64_    (2 CPU)

09时21分41秒   UID       PID  minflt/s  majflt/s     VSZ    RSS   %MEM  Command
09时21分42秒     0     10445    353.85      0.00  108380   1168   0.03  pidstat

pidstat -r 表示的就是单个应用程序的内存使用情况。

  • minflt/s : 每秒次缺页错误次数(minor page faults),次缺页错误次数意即虚拟内存地址映射成物理内存地址产生的page fault次数。
  • majflt/s : 每秒主缺页错误次数(major page faults),当虚拟内存地址映射成物理内存地址时,相应的page在swap中,这样的page fault为major page fault,一般在内存使用紧张时产生。
    也就是说如果某个应用程序有majflt/s 了,表示其开始使用swap了。其性能当然也会下降。



作者:OOM_Killer
链接:https://www.jianshu.com/p/24550b83f390
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值