RTFSC
有的时候RTFM已经不够了, 手册包括工具本身的更新没对上内核的节奏, 我们回到上面页面回收的例子, 估计有的同学之前就有疑问, 没有scan哪里来的steal。
#sar -B 1 11:00:16 AM pgscank/s pgscand/s pgsteal/s %vmeff 11:00:17 AM 0.00 0.00 3591.00 0.00 11:00:18 AM 0.00 0.00 10313.00 0.00 11:00:19 AM 0.00 0.00 8452.00 0.00
先看sysstat (sar) 里面的实现, 主要是读取分析/proc/vmstat:
- pgscand: 对应到pgscan_direct域
- pgscank: 对应到pgscan_kswapd域
- pgsteal: 对应到pgsteal_开头的
#gdb --args ./sar -B 1 (gdb) b read_vmstat_paging (gdb) set follow-fork-mode child (gdb) r Breakpoint 1, read_vmstat_paging (st_paging=0x424f40) at rd_stats.c:751 751 if ((fp = fopen(VMSTAT, "r")) == NULL) (gdb) n 754 st_paging->pgsteal = 0; (gdb) 757 while (fgets(line, sizeof(line), fp) != NULL) { (gdb) 759 if (!strncmp(line, "pgpgin ", 7)) { (gdb) 763 else if (!strncmp(line, "pgpgout ", 8)) { (gdb) 767 else if (!strncmp(line, "pgfault ", 8)) { (gdb) 771 else if (!strncmp(line, "pgmajfault ", 11)) { (gdb) 775 else if (!strncmp(line, "pgfree ", 7)) { (gdb) 779 else if (!strncmp(line, "pgsteal_", 8)) { (gdb) 784 else if (!strncmp(line, "pgscan_kswapd", 13)) { (gdb) 789 else if (!strncmp(line, "pgscan_direct", 13)) { (gdb) 757 while (fgets(line, sizeof(line), fp) != NULL) { (gdb)
看下/proc/vmstat都有什么:
#grep pgsteal_ /proc/vmstat pgsteal_kswapd 168563 pgsteal_direct 0 pgsteal_anon 0 pgsteal_file 978205 #grep pgscan_ /proc/vmstat pgscan_kswapd 204242 pgscan_direct 0 pgscan_direct_throttle 0 pgscan_anon 0 pgscan_file 50583828
最后看看内核的实现, pgsteal和pgscan的逻辑是一样, 除了nr_scanned换成了nr_reclaimed:
if (current_is_kswapd()) { if (!cgroup_reclaim(sc)) __count_vm_events(PGSCAN_KSWAPD, nr_scanned); count_memcg_events(lruvec_memcg(lruvec), PGSCAN_KSWAPD, nr_scanned); } else { if (!cgroup_reclaim(sc)) __count_vm_events(PGSCAN_DIRECT, nr_scanned); count_memcg_events(lruvec_memcg(lruvec), PGSCAN_DIRECT, nr_scanned); } __count_vm_events(PGSCAN_ANON + file, nr_scanned);
现在问题很清晰了:
- 这里sar取得是系统的/proc/vmstat, 而cgroup里面pgscan_kswapd和pgscan_direct只会加到cgroup的统计, 不会加到系统级的统计
- cgroup里面pgsteal_kswapd和pgsteal_direct同样只会加到cgroup自己的统计
- 但是主要pgscan_anon, pgscan_file和pgsteal_anon, pgsteal_file都只加到系统级的统计
- sar读取了pgscan_kswapd, pgscan_direct, 以及pgsteal_*, 这里*还包括了pgsteal_anon和pgsteal_file
这整个逻辑都乱了, 我们有必要解决这个bug让sar的输出变得更加有意义. 那么在cgroup内是不是没问题?
#df -h . Filesystem Size Used Avail Use% Mounted on cgroup 0 0 0 - /sys/fs/cgroup/memory #grep -c 'pgscan\|pgsteal' memory.stat 0
这些统计信息在cgroup v1上完全没有输出, 而只在v2版本有输出. 在以前内核没有专门LRU_UNEVICTABLE的时候, 如果有很多比如mlock page的时候, 碰到过不停扫描却不能回收内存的情况, 这个统计会非常有用, 即使是现在我相信这个统计还是有用的, 只是大部分时候还不用看到这么细。
07
多上手
纸上得来终觉浅, 自己动手去做带来很多好处:
- 回答预设问题. 调试分析就是不断提出问题和验证的过程, 没有上手的话就会一直停留在第一个问题上. 比如我想了解某平台上物理内存是怎么编址的, 没有文档的话只能自己去实验
- 提出新的问题. 调试分析中不怕有问题, 怕的是提不出问题
- 会有意外收获. 很多时候并不是有意为之, 比如准备的是分析cpu调频能否降功耗, 上去却发现系统一直运行在最低频率
- 熟练. 熟练就是效率
- 改进产品. 可以试想下在整个云环境所有机器上扫描 (类似全面体检) 会发现多少潜在问题