内存调优核心点:
- 保证应用程序的热点数据放到内存中;
- 尽量减少换页和交换。
1 缓存基础
1.1 内存中的Buffer和Cache
Buffer
和 Cache
的设计目的,是为了提升系统的 I/O 性能。它们利用内存,充当起慢速磁盘与快速 CPU 之间的桥梁,可以加速 I/O 的访问速度。可以使用 vmstat
命令查看这两个值的大小。
Buffer
是对磁盘数据的缓存,而 Cache
是文件数据的缓存,它们既会用在读请求中,也会用在写请求中。具体的说:
Buffer
既可以用作「将要写入磁盘数据的缓存」,也可以用作「从磁盘读取数据的缓存」。Cache
既可以用作「从文件读取数据的页缓存」,也可以用作「写文件的页缓存」。
「读文件」和「读磁盘」的区别
磁盘是一个块设备,可以划分为不同的分区,在分区之上再创建文件系统,挂载到某个目录,之后才可以在这个目录中读写文件。
在读写普通文件时,会经过文件系统,由文件系统负责与磁盘交互;而读写磁盘或者分区时,就会跳过文件系统,也就是所谓的「裸I/O」。这两种读写方式所使用的缓存是不同的,也就是Cache
和Buffer
区别
理论上,一个文件读首先到
Block Buffer
, 然后到Page Cache
。有了文件系统才有了Page Cache
。在老的 Linux 上这两个 Cache 是分开的。这样对于文件数据,会被 Cache 两次。这种方案虽然简单,但低效。后期Linux
把这两个Cache
统一了。对于文件,Page Cache
指向Block Buffer
,对于非文件则是 Block Buffer。文件操作,只影响Page Cache
,Raw 操作,则只影响Buffer
。比如 VM 虚拟机,则会越过文件系统,直接操作磁盘, 就是常说的直接内存访问.
2 缓存性能
我们用缓存命中率衡量缓存使用的好坏。缓存命中率是指直接通过缓存获取数据的请求次数,占所有数据请求次数的百分比。命中率越高,表示使用缓存带来的收益越高,应用程序的性能也就越好。
可以使用 cachestat
和 cachetop
这两个工具,观察系统和进程的缓存命中情况。其中:
cachestat
提供了整个系统缓存的读写命中情况;cachetop
提供了每个进程的缓存命中情况。
可以使用 pcstat
(需要 Go 语言支持)查看文件在内存中的缓存大小以及缓存比例。
1 | pcstat /bin/ls |
3 内存泄漏
memleak
是 一个专门用来检测内存泄漏的工具,位于 bcc 软件包中,它可以跟踪系统或指定进程的内存分配、释放请求,然后定期输出一个未释放内存和相应调用栈的汇总情况(默认 5 秒)。
如果已经完成了开发任务,也可以用 memleak
工具,检查应用程序的运行中,内存是否泄漏。如果发现了内存泄漏情况,再根据 memleak
输出的应用程序调用栈,定位内存的分配位置,从而释放不再访问的内存。
4 Swap
Swap 是什么
在内存资源紧张时,Linux 通过直接内存回收和定期扫描的方…
极客时间版权所有: https://time.geekbang.org/column/article/75797
Swap 实践
Q: 为什么 Hadoop 集群建议关 swap ?
A:事实上不仅 Hadoop,包括 ES 在内绝大部分 Java 的应用都建议关 swap
,这个和 JVM 的 GC 有关,它在 GC 的时候会遍历所有用到的堆的内存,如果这部分内存是被 swap
出去了,遍历的时候就会有磁盘 IO。参考链接:
- https://www.elastic.co/guide/en/elasticsearch/reference/current/setup-configuration-memory.html
- https://dzone.com/articles/just-say-no-swapping
Q: 为什么 Kubernetes 要关闭 swap 呢?
A:一个是性能问题,开启 swap
会严重影响性能(包括内存和I/O);另一个是管理问题,开启 swap
后通过 cgroups
设置的内存上限就会失效。
5 性能问题分析套路
5.1 内存指标概要
下图是我们进行内存分析时主要考虑的一些内存指标。
系统内存使用情况
- 已用内存和剩余内存;
- 共享内存是通过
tmpfs
实现的,其实也是一种特殊的缓存; - 可用内存是新进程可以使用的最大内存,它包括剩余内存和可回收缓存。
- 缓存包括两部分,一部分是磁盘读取文件的页缓存,用来缓存从磁盘读取的数据,可以加快以后再次访问的速度。另一部分,则是
Slab
分配器中的可回收内存; - 缓冲区是对原始磁盘块的临时存储,用来缓存将要写入磁盘的数据;
进程内存使用情况
- 虚拟内存,包括了进程代码段、数据段、共享内存、已经申请的堆内存和已经换出的内存等;
- 常驻内存是进程实际使用的物理内存,不过,它不包括
Swap
和共享内存; - 共享内存,既包括与其他进程共同使用的真实的共享内存,还包括了加载的动态链接库以及程序的代码段等;
Swap
内存,是指通过Swap
换出到磁盘的内存。
Swap 的使用情况
- 已用空间和剩余空间很;
- 换入和换出速度,则表示每秒钟换入和换出内存的大小。
5.2 内存优化工具
5.3 内存优化思路
分析思路:
- 先用
free
和top
,查看系统整体的内存使用情况; - 再用
vmstat
和pidstat
,查看一段时间的趋势,从而判断出内存问题的类型; - 最后进行详细分析,比如内存分配分析、缓存 / 缓冲区分析、具体进程的内存使用分析等。
优化思路:
- 最好禁止 Swap。如果必须开启
Swap
,降低swappiness
的值,减少内存回收时Swap
的使用倾向; - 减少内存的动态分配。比如,可以使用内存池、大页(HugePage)等;
- 尽量使用缓存和缓冲区来访问数据。比如,可以使用堆栈明确声明内存空间,来存储需要缓存的数据;或者用 Redis 这类的外部缓存组件,优化数据的访问;
- 使用
cgroups
等方式限制进程的内存使用情况。这样,可以确保系统内存不会被异常进程耗尽; - **通过 /
proc
/pid
/oom_adj
,调整核心应用的oom_score
**。这样,可以保证即使内存紧张,核心应用也不会被 OOM 杀死。