性能优化总结之内存篇

文章目录
  1. 1. 1 缓存基础
    1. 1.1. 1.1 内存中的Buffer和Cache
  2. 2. 2 缓存性能
  3. 3. 3 内存泄漏
  4. 4. 4 Swap
    1. 4.1. Swap 是什么
    2. 4.2. Swap 实践
  5. 5. 5 性能问题分析套路
    1. 5.1. 5.1 内存指标概要
    2. 5.2. 5.2 内存优化工具
    3. 5.3. 5.3 内存优化思路

内存调优核心点:

  1. 保证应用程序的热点数据放到内存中;
  2. 尽量减少换页和交换。

1 缓存基础

1.1 内存中的Buffer和Cache

BufferCache 的设计目的,是为了提升系统的 I/O 性能。它们利用内存,充当起慢速磁盘与快速 CPU 之间的桥梁,可以加速 I/O 的访问速度。可以使用 vmstat 命令查看这两个值的大小。

Buffer 是对磁盘数据的缓存,而 Cache 是文件数据的缓存,它们既会用在读请求中,也会用在写请求中。具体的说:

  1. Buffer 既可以用作「将要写入磁盘数据的缓存」,也可以用作「从磁盘读取数据的缓存」。
  2. Cache 既可以用作「从文件读取数据的页缓存」,也可以用作「写文件的页缓存」。

「读文件」和「读磁盘」的区别

磁盘是一个块设备,可以划分为不同的分区,在分区之上再创建文件系统,挂载到某个目录,之后才可以在这个目录中读写文件。
在读写普通文件时,会经过文件系统,由文件系统负责与磁盘交互;而读写磁盘或者分区时,就会跳过文件系统,也就是所谓的「裸I/O」。这两种读写方式所使用的缓存是不同的,也就是 CacheBuffer 区别

理论上,一个文件读首先到 Block Buffer, 然后到 Page Cache。有了文件系统才有了 Page Cache。在老的 Linux 上这两个 Cache 是分开的。这样对于文件数据,会被 Cache 两次。这种方案虽然简单,但低效。后期 Linux 把这两个 Cache 统一了。对于文件,Page Cache 指向 Block Buffer,对于非文件则是 Block Buffer。文件操作,只影响 Page Cache,Raw 操作,则只影响 Buffer。比如 VM 虚拟机,则会越过文件系统,直接操作磁盘, 就是常说的直接内存访问.

2 缓存性能

我们用缓存命中率衡量缓存使用的好坏。缓存命中率是指直接通过缓存获取数据的请求次数,占所有数据请求次数的百分比。命中率越高,表示使用缓存带来的收益越高,应用程序的性能也就越好。

可以使用 cachestatcachetop 这两个工具,观察系统和进程的缓存命中情况。其中:

  1. cachestat 提供了整个系统缓存的读写命中情况;
  2. cachetop 提供了每个进程的缓存命中情况。

可以使用 pcstat (需要 Go 语言支持)查看文件在内存中的缓存大小以及缓存比例。

1
2
3
4
5
6
7
pcstat /bin/ls

+---------+----------------+------------+-----------+---------+
| Name | Size (bytes) | Pages | Cached | Percent |
|---------+----------------+------------+-----------+---------|
| /bin/ls | 133792 | 33 | 0 | 000.000 |
+---------+----------------+------------+-----------+---------+

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。参考链接:

  1. https://www.elastic.co/guide/en/elasticsearch/reference/current/setup-configuration-memory.html
  2. https://dzone.com/articles/just-say-no-swapping

Q: 为什么 Kubernetes 要关闭 swap 呢?

A:一个是性能问题,开启 swap 会严重影响性能(包括内存和I/O);另一个是管理问题,开启 swap 后通过 cgroups 设置的内存上限就会失效。

5 性能问题分析套路

5.1 内存指标概要

下图是我们进行内存分析时主要考虑的一些内存指标。

系统内存使用情况

  1. 已用内存和剩余内存;
  2. 共享内存是通过 tmpfs 实现的,其实也是一种特殊的缓存;
  3. 可用内存是新进程可以使用的最大内存,它包括剩余内存和可回收缓存。
  4. 缓存包括两部分,一部分是磁盘读取文件的页缓存,用来缓存从磁盘读取的数据,可以加快以后再次访问的速度。另一部分,则是 Slab 分配器中的可回收内存;
  5. 缓冲区是对原始磁盘块的临时存储,用来缓存将要写入磁盘的数据;

进程内存使用情况

  1. 虚拟内存,包括了进程代码段、数据段、共享内存、已经申请的堆内存和已经换出的内存等;
  2. 常驻内存是进程实际使用的物理内存,不过,它不包括 Swap 和共享内存;
  3. 共享内存,既包括与其他进程共同使用的真实的共享内存,还包括了加载的动态链接库以及程序的代码段等;
  4. Swap 内存,是指通过 Swap 换出到磁盘的内存。

Swap 的使用情况

  1. 已用空间和剩余空间很;
  2. 换入和换出速度,则表示每秒钟换入和换出内存的大小。

5.2 内存优化工具

5.3 内存优化思路

分析思路:

  1. 先用 freetop查看系统整体的内存使用情况
  2. 再用 vmstatpidstat查看一段时间的趋势,从而判断出内存问题的类型;
  3. 最后进行详细分析,比如内存分配分析、缓存 / 缓冲区分析、具体进程的内存使用分析等。

优化思路:

  1. 最好禁止 Swap。如果必须开启 Swap,降低 swappiness 的值,减少内存回收时 Swap 的使用倾向;
  2. 减少内存的动态分配。比如,可以使用内存池、大页(HugePage)等;
  3. 尽量使用缓存和缓冲区来访问数据。比如,可以使用堆栈明确声明内存空间,来存储需要缓存的数据;或者用 Redis 这类的外部缓存组件,优化数据的访问;
  4. 使用 cgroups 等方式限制进程的内存使用情况。这样,可以确保系统内存不会被异常进程耗尽;
  5. **通过 /proc/pid/oom_adj ,调整核心应用的 oom_score**。这样,可以保证即使内存紧张,核心应用也不会被 OOM 杀死。