头图

image
转自@twt社区,作者陈炽卉

1 CPU 监控

本演示场景,主要是通过 ncpu 模拟应用对 DLPAR 分区的 CPU 加压;然后通过 nmon 观察消耗 CPU 最高的进程。

1.1 查看 CPU 消耗最高的进程以及其 CPU 占用情况

登录 AIX,运行 nmon,输入“t”然后输入“2”:

输出结果为占用 CPU 最高的各进程排序,可以看到 CPU 主要由 rtsdb 进程消耗。

1.2 使用 truss 命令跟踪系统调用情况

如果 nmon 显示某些进程的系统 CPU 消耗很高,可以使用 truss 对特定进程进行跟踪分析。

跟踪共享库或者用户library调用。

示例:取得进程系统调用的统计情况,truss -c -p <pid> 一段时间之后,然后Ctrl+C:

truss跟踪进程的执行,默认truss将跟踪到进程结束运行,可以Ctrl + C手工终止:

用-t选项根据具体的系统调用,如下:

用-u跟踪共享库,例如libc.a:

1.3 使用 procstack 命令跟踪进程的执行栈信息

procstack 可以提供类似 dbx 打印执行栈的功能,但不会阻塞应用执行。这可以用来辅助分 析应用 hang,或者锁冲突很高等等问题。

例如系统显示锁冲突很高,且主要系统 CPU 消耗在某进程,与此同时,如果多次 procstack 观察到该进程出现相同的锁调用模式,则这很可能就是触发问题的原因:

1.4 使用 tprof 命令观察系统整体 CPU 使用分解情况

运行 tprof 命令,其中 -E 参数指示 tprof 使用基于 Power7 Performance Monitor Unit (PMU)的采样方式生成剖析报 告。相比默认的基于时钟的方式,基于 PMU 的采样方式可以提供更精确的剖析报告,尤其 在某些 kernel 代码区域中断被关闭的情况下。

-u 表示 user profiling;

-s 表示 shared library profiling;

-k 表示 kernel profiling;

-e 表示 kernel extension profiling;

-j 表示 java profiling;

-l 指示 tprof 报告显示函数名称时不进行截断,显示长名字;

-L 用于指定应用程序的路径,例如本处 rtsdb 的路径为/tmp/nstress;

-t 指示 tprof 报告按线程进行分解;

-r 指示生成的报告名称;

-x 指示 tprof 运行的程序; tprof 的数据收集为该程序运行的整个生命周期;

Tip: 有时 tprof 可能出现不显示函数名称而只看到函数地址的现象,这主要有如下几种原因:

  1. 未指定相关二进制程序或共享库路径,可以在 tprof 选项中加上:-S <应用程序所在 路径:应用共享库路径>
  2. 二进制程序被 strip 过,去除了符号调试信息;建议检查去除编译脚本中的 strip 命 令,或去除编译命令中的-s 选项;

或者直接按符号地址,通过 dbx 查询其对于函数名称:通过 gencore 生成相关进程的内存镜像文件, 并通过 dbx 进行解析,如下:

PS:直接通过 dbx 进入程序也可以直接查看函数地址,但如果需要同时查看相关数据结构的 话,就需要 gencore 生成一份进程内存镜像了。

据此,可以看到CPU主要消耗在rtsdb 进程上;而 rtsdb 进程的 CPU消耗主要在 User和 Shared 两部分,这两部分都对应 CPU 统计的 usr%部分。

对 tprof 报告的输出部分进一步追踪可以看到,USER 部分 CPU 主要消耗在 ncpu.c 的 work 函 数:

而 SHARED 部分 CPU 主要消耗在 libc 库的除法调用(divu64)函数:

至此,我们就可以得到 CPU 占用率优化的方向,重点分析上述几个 CPU 占用率高的函数调 用及其来源。注意一般而言,上述部分可能存在对应关系,例如很可能是 USER 部分的 work 函数调用了 SHARED 部分的__divu64 函数。

2 内存监控

2.1 AIX 内存分配回收策略介绍

AIX 系统为每个业务进程维护一个独立的空闲内存列表;同时采取相应的策略,使得对于该 进程的内存申请/释放尽量在此空闲列表中进行。这样可以提高分配效率,不需要每次内存 分配都经过系统内核。进程退出后,系统会回收该进程占用的全部内存。详情参考:

http://publib.boulder.ibm.com/infocenter/aix/v6r1/index.jsp?topic=/com.ibm.aix.genp rogc/doc/genprogc/sys_mem_alloc.htm

注:选择不同的分配策略时 , 对空闲内存空间的管理策略会有所差异。例如默认的管理结构是 cartesian 树;而采用 watson 分配算法时,使用的管理结构是红黑树。

2.2 内存分配观察示例—递增分配

进程的详细内存分配情况可以使用svmon来观察,参考如下示例。需要注意,为方便svmon观察,示例代码需要在malloc之后调用memset进行初始化;因为操作系统实际上并不会立即对已申请但尚未访问到的内容分配实际存储空间,而是推迟到第一次访问时 才会实际分配---这即是缺页机制的工作原理。

如下是一个申请空间递增的应用,分配/释放大小为2MB->4MB->8MB->16MB, 则通过各阶段的 svmon可以看到,内存页面会持续增长,从2MB一直增加到16MB(注意不是2MB+4MB+..+16MB=30MB)。

Malloc分配2MB,未初始化时:

Addr Range: 65534..65535 Address Range为0~512页,即代表512×4096=2MB虚拟地址空间。Virtual取值为2,表示该空间 尚未实际分配。

初始化后:

Virtual取值为513,表明虚存空间已经实际分配。

释放之前申请的2MB,重新申请4MB并初始化后

Addr Range: 0..1024 1024×4096=4MB,此前释放的512页虚拟地址空间被重复利用。

释放之前申请的4MB,重新申请8MB并初始化后

Addr Range: 0..2048 此前释放的1024页虚拟地址空间被重复利用。

释放之前申请的8MB,重新申请16MB并初始化后

2.3 内存分配观察示例—递减分配

如示例,如果是一个申请空间递减的应用,分配/释放大小为16MB->8MB->4MB->2MB, 通过各阶段的svmon(svmon -nrP <pid>)可以看到,内存页面始终维持在16MB。

Malloc分配16MB,未初始化时:

Address Range为0~4096页,即代表4096×4096=16MB虚拟地址空间。Inuse/Virtual取值为2, 表示该空间尚未实际分配。

初始化后:

Virtual=4097页, 虚拟内存已经实际分配。

释放之前申请的16MB,重新申请8MB并初始化后

释放之前申请的8MB,重新申请4MB并初始化后

释放之前申请的4MB,重新申请2MB并初始化后

可以看到svmon输出结果没有变化;原因是虽然应用调用了free释放了16MB内存,但系统的处理 策略是将该内存置于进程自身的空间块树中管理。下一个8MB分配,实际上是直接从进程已有的 16MB空闲块中获取的。但对系统而言,进程管理的空闲块树也对应为该进程的内存消耗,所以 其内存占用没有变化。

测试代码:

2.4 观察系统中内存占用最高的进程(svmon 方法)

后台运行 3 个 nmem64 进程:

./nmem64 -m 2048 -s 3000 -z 80 &

按进程使用的虚拟内存进行排序,显示占用最高的前三项:

显示虚拟内存占用最高的 3 个进程的详细的内存段分布信息,如下:

可以看到,消耗最多虚拟内存的段都是 nmem64 进程的数据段。

2.5 观察系统中内存占用最高的进程(nmon 方法)

登录 AIX,运行 nmon,输入“t”然后输入“4”:

输出结果为按内存使用由高到低的进程排序。

2.6 寻找内存持续增长的进程

可以使用 ps vg 记录当前系统中各进程的内存消耗情况,然后通过比较多次 ps vg 的结果来 判断是否存在一些进程有持续的内存增长。说明:进程存在持续内存增长并不一定意味着出现了内存泄漏。由于 AIX 内存分配采用了访问时分 配的策略,进程申请大量内存时系统并不会第一时间分配内存,而是在进程使用过程中实际 访问时才进行分配。由于这种分配策略,进程在启动初期可能存在内存持续增长的可能(例 如数据库缓存需要一定时间才能完全填充);但其增长曲线应该是收敛到具体值的。

测试脚本如下:

2.7 如何通过共享内存 ID 对应关联到该共享内存的进程

在 AIX 系统层面,只要给定共享内存 id,就可以获取 attach 该共享内存的进程列表,方法如 下:

可以根据其共享段 SID,获得相应的关联进程 pid,如下。注意 ipcs 上看 NATTACH=53,即有 53 个进程 attach 到该共享内存,因此 svmon 结果中,进程列表部分对应列出了 53 个进程 pid。

根据相应的 pid 可以获取进程的具体信息:

2.8 如何获取 AIX Kernel 的内存使用率

kernel大部分内存占用采用跟普通进程一样的内存段方式组织,比如kernel heap(这部分内存消 耗包含文件系统的元数据、内核扩展、第三方驱动等等), 网络buffer,磁盘管理LVM buffer占 用,以及一些RAS特性的buffer占用,例如light-weight memory trace buffers, component trace buffers等等。这部分都可以通过svmon -Ss 查询出(注意这条命令阻塞时间较长)。少部分采用非段方式组织的主要是AIX内存管理的元数据如页表之类。

可以通过perfpmr.sh -x memdetails.sh 获取kernel内存占用的整体情况,内存分布将输出在 http://perfpmr.int中。

也可以通过如下方法直接观察 AIX Kernel 内存使用情况:

  1. 观察AIX内存使用的命令(基于kdb,建议仅在测试环境验证)

  1. 建议

从我们目前实验的几个系统看,超过100G的大分区,一般内核的内存占用实际都在5%以下。如果 客户环境中采用了较多第三方驱动或组件,比例可能偏高一些,建议搭建环境验证一下。

此外,如果系统中存在超大的JFS2文件系统,包含大量的巨型文件(比如单个文件数十、数百GB), 或者有数以十万、百万计的小文件;则可能观察到较高的JFS2 元数据缓存占用,或者inode缓存 占用。这部分内存消耗也会计入AIX kernel,可以通过 cat /proc/sys/fs/jfs2/memory_usage 观察到:

另,文件系统的元数据缓存和inode缓存可以通过如下ioo参数控制

这两个参数是比例系数,设置为400时(AIX6.1默认值),元数据和inode缓存最多能占据系统内存的16%左右。一般而言,如果分区内存不大或者元数据相关操作不多,使用默认值(AIX7.1为200)通常是可 行的。但如果分区内存足够大(比如100GB以上),元数据操作较多(可以通过观察上面的命令 输出确认),则可以考虑将这两个参数设置为100,可以使得元数据和inode缓存最多占用系统内 存的比例下调至4%左右。

2.9 如何判断系统是否存在内存不足

预期的内存需求是 virtual 页面数加上文件页面数(包括 pers 和 clnt),如果这两者之和大 于实际配置的内存页面数,即可认为存在内存不足,如下示例:


同创永益
15 声望3 粉丝

同创永益,面向未来的组织韧性服务提供商


引用和评论

0 条评论