任何对 Linux IO 系统有一定经验的人的见解都会有所帮助。以下是我的故事:
最近启动了一个由六台 Dell PowerEdge rx720xds 组成的集群,通过 Ceph 提供文件服务。这些机器在两个插槽上有 24 个核心,带有两个 numa 区域和 70 多 GB 的内存。磁盘被格式化为每个磁盘的 raid(否则我们看不到直接公开它们的方法)。网络由 mellanox infiniband IP over IB 提供(IP 数据包在内核空间而不是硬件中转换为 IB)。
我们的每个 SAS 驱动器都像这样安装:
# cat /proc/mounts | grep osd
/dev/sdm1 /var/lib/ceph/osd/ceph-90 xfs rw,noatime,attr2,inode64,noquota 0 0
/dev/sdj1 /var/lib/ceph/osd/ceph-87 xfs rw,noatime,attr2,inode64,noquota 0 0
/dev/sdu1 /var/lib/ceph/osd/ceph-99 xfs rw,noatime,attr2,inode64,noquota 0 0
/dev/sdd1 /var/lib/ceph/osd/ceph-82 xfs rw,noatime,attr2,inode64,noquota 0 0
/dev/sdk1 /var/lib/ceph/osd/ceph-88 xfs rw,noatime,attr2,inode64,noquota 0 0
/dev/sdl1 /var/lib/ceph/osd/ceph-89 xfs rw,noatime,attr2,inode64,noquota 0 0
/dev/sdh1 /var/lib/ceph/osd/ceph-86 xfs rw,noatime,attr2,inode64,noquota 0 0
/dev/sdo1 /var/lib/ceph/osd/ceph-97 xfs rw,noatime,attr2,inode64,noquota 0 0
/dev/sdc1 /var/lib/ceph/osd/ceph-81 xfs rw,noatime,attr2,inode64,noquota 0 0
/dev/sdb1 /var/lib/ceph/osd/ceph-80 xfs rw,noatime,attr2,inode64,noquota 0 0
/dev/sds1 /var/lib/ceph/osd/ceph-98 xfs rw,noatime,attr2,inode64,noquota 0 0
/dev/sdn1 /var/lib/ceph/osd/ceph-91 xfs rw,noatime,attr2,inode64,noquota 0 0
/dev/sde1 /var/lib/ceph/osd/ceph-83 xfs rw,noatime,attr2,inode64,noquota 0 0
/dev/sdq1 /var/lib/ceph/osd/ceph-93 xfs rw,noatime,attr2,inode64,noquota 0 0
/dev/sdg1 /var/lib/ceph/osd/ceph-85 xfs rw,noatime,attr2,inode64,noquota 0 0
/dev/sdt1 /var/lib/ceph/osd/ceph-95 xfs rw,noatime,attr2,inode64,noquota 0 0
/dev/sdf1 /var/lib/ceph/osd/ceph-84 xfs rw,noatime,attr2,inode64,noquota 0 0
/dev/sdr1 /var/lib/ceph/osd/ceph-94 xfs rw,noatime,attr2,inode64,noquota 0 0
/dev/sdi1 /var/lib/ceph/osd/ceph-96 xfs rw,noatime,attr2,inode64,noquota 0 0
/dev/sdp1 /var/lib/ceph/osd/ceph-92 xfs rw,noatime,attr2,inode64,noquota 0 0
这些机器的 I/O 速度突发为几百 MB/s,但大多数时间都处于空闲状态,只存在许多小的“戳刺”:
# iostat -x -m
Linux 3.10.0-123.el7.x86_64 (xxx) 07/11/14 _x86_64_ (24 CPU)
avg-cpu: %user %nice %system %iowait %steal %idle
1.82 0.00 1.05 0.11 0.00 97.02
Device: rrqm/s wrqm/s r/s w/s rMB/s wMB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
sda 0.00 0.11 0.25 0.23 0.00 0.00 27.00 0.00 2.07 3.84 0.12 0.61 0.03
sdb 0.02 0.57 3.49 2.28 0.08 0.14 77.18 0.01 2.27 2.99 1.18 1.75 1.01
sdd 0.03 0.65 3.93 3.39 0.10 0.16 70.39 0.01 1.97 2.99 0.79 1.57 1.15
sdc 0.03 0.60 3.76 2.86 0.09 0.13 65.57 0.01 2.10 3.02 0.88 1.68 1.11
sdf 0.03 0.63 4.19 2.96 0.10 0.15 73.51 0.02 2.16 3.03 0.94 1.73 1.24
sdg 0.03 0.62 3.93 3.01 0.09 0.15 70.44 0.01 2.06 3.01 0.81 1.66 1.15
sde 0.03 0.56 4.35 2.61 0.10 0.14 69.53 0.02 2.26 3.00 1.02 1.82 1.26
sdj 0.02 0.73 3.67 4.74 0.10 0.37 116.06 0.02 1.84 3.01 0.93 1.31 1.10
sdh 0.03 0.62 4.31 3.04 0.10 0.15 67.83 0.02 2.15 3.04 0.89 1.75 1.29
sdi 0.02 0.59 3.82 2.47 0.09 0.13 74.35 0.01 2.20 2.96 1.03 1.76 1.10
sdl 0.03 0.59 4.75 2.46 0.11 0.14 70.19 0.02 2.33 3.02 1.00 1.93 1.39
sdk 0.02 0.57 3.66 2.41 0.09 0.13 73.57 0.01 2.20 3.00 0.97 1.76 1.07
sdm 0.03 0.66 4.03 3.17 0.09 0.14 66.13 0.01 2.02 3.00 0.78 1.64 1.18
sdn 0.03 0.62 4.70 3.00 0.11 0.16 71.63 0.02 2.25 3.01 1.05 1.79 1.38
sdo 0.02 0.62 3.75 2.48 0.10 0.13 76.01 0.01 2.16 2.94 0.99 1.70 1.06
sdp 0.03 0.62 5.03 2.50 0.11 0.15 68.65 0.02 2.39 3.08 0.99 1.99 1.50
sdq 0.03 0.53 4.46 2.08 0.09 0.12 67.74 0.02 2.42 3.04 1.09 2.01 1.32
sdr 0.03 0.57 4.21 2.31 0.09 0.14 72.05 0.02 2.35 3.00 1.16 1.89 1.23
sdt 0.03 0.66 4.78 5.13 0.10 0.20 61.78 0.02 1.90 3.10 0.79 1.49 1.47
sdu 0.03 0.55 3.93 2.42 0.09 0.13 70.77 0.01 2.17 2.97 0.85 1.79 1.14
sds 0.03 0.60 4.11 2.70 0.10 0.15 74.77 0.02 2.25 3.01 1.10 1.76 1.20
sdw 1.53 0.00 0.23 38.90 0.00 1.66 87.01 0.01 0.22 0.11 0.22 0.05 0.20
sdv 0.88 0.00 0.16 28.75 0.00 1.19 84.55 0.01 0.24 0.10 0.24 0.05 0.14
dm-0 0.00 0.00 0.00 0.00 0.00 0.00 8.00 0.00 1.84 1.84 0.00 1.15 0.00
dm-1 0.00 0.00 0.23 0.29 0.00 0.00 23.78 0.00 1.87 4.06 0.12 0.55 0.03
dm-2 0.00 0.00 0.01 0.00 0.00 0.00 8.00 0.00 0.47 0.47 0.00 0.45 0.00
问题:
大约 48 小时后,连续的页面变得非常碎片化,以至于四大 (16 页,65536 字节) 分配开始失败,并且我们开始丢弃数据包(由于 SLAB 增长时 kalloc 失败)。
这是一个相对“健康”的服务器的样子:
# cat /sys/kernel/debug/extfrag/unusable_index
Node 0, zone DMA 0.000 0.000 0.000 0.001 0.003 0.007 0.015 0.031 0.031 0.096 0.225
Node 0, zone DMA32 0.000 0.009 0.015 0.296 0.733 0.996 0.997 0.998 0.998 1.000 1.000
Node 0, zone Normal 0.000 0.000 0.019 0.212 0.454 0.667 0.804 0.903 0.986 1.000 1.000
Node 1, zone Normal 0.000 0.027 0.040 0.044 0.071 0.270 0.506 0.772 1.000 1.000 1.000
当碎片化变得相当严重时,系统似乎开始在内核空间中旋转,一切都崩溃了。此故障期间的一个异常是 xfsaild 似乎使用了大量 CPU 并陷入不可中断的睡眠状态。不过,我不想在整个系统故障期间就得出任何奇怪的结论。
迄今为止的解决方法。
为了确保这些分配即使在碎片的情况下也不会失败,我设置了:
vm.min_free_kbytes = 16777216
在 SLAB 缓存中看到数百万个 blkdev_requests 后,我尝试通过以下方式减少脏页:
vm.dirty_ratio = 1
vm.dirty_background_ratio = 1
vm.min_slab_ratio = 1
vm.zone_reclaim_mode = 3
可能一次更改了太多变量,但是为了防止 inode 和 dentry 造成碎片,我决定将它们保持在最低限度:
vm.vfs_cache_pressure = 10000
这似乎有所帮助。但是碎片率仍然很高,而 inode 和 dentry 问题的减少意味着我注意到了一些奇怪的事情,这让我想到了……
我的问题:
为什么我有这么多的 blkdev_requests(它们一直处于活动状态),而当我删除缓存时它们就会消失?
我的意思是:
# slabtop -o -s c | head -20
Active / Total Objects (% used) : 19362505 / 19431176 (99.6%)
Active / Total Slabs (% used) : 452161 / 452161 (100.0%)
Active / Total Caches (% used) : 72 / 100 (72.0%)
Active / Total Size (% used) : 5897855.81K / 5925572.61K (99.5%)
Minimum / Average / Maximum Object : 0.01K / 0.30K / 15.69K
OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME
2565024 2565017 99% 1.00K 80157 32 2565024K xfs_inode
3295194 3295194 100% 0.38K 78457 42 1255312K blkdev_requests
3428838 3399527 99% 0.19K 81639 42 653112K dentry
5681088 5680492 99% 0.06K 88767 64 355068K kmalloc-64
2901366 2897861 99% 0.10K 74394 39 297576K buffer_head
34148 34111 99% 8.00K 8537 4 273184K kmalloc-8192
334768 334711 99% 0.57K 11956 28 191296K radix_tree_node
614959 614959 100% 0.15K 11603 53 92824K xfs_ili
21263 19538 91% 2.84K 1933 11 61856K task_struct
18720 18636 99% 2.00K 1170 16 37440K kmalloc-2048
32032 25326 79% 1.00K 1001 32 32032K kmalloc-1024
10234 9202 89% 1.88K 602 17 19264K TCP
22152 19765 89% 0.81K 568 39 18176K task_xstate
# echo 2 > /proc/sys/vm/drop_caches :(
# slabtop -o -s c | head -20
Active / Total Objects (% used) : 965742 / 2593182 (37.2%)
Active / Total Slabs (% used) : 69451 / 69451 (100.0%)
Active / Total Caches (% used) : 72 / 100 (72.0%)
Active / Total Size (% used) : 551271.96K / 855029.41K (64.5%)
Minimum / Average / Maximum Object : 0.01K / 0.33K / 15.69K
OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME
34140 34115 99% 8.00K 8535 4 273120K kmalloc-8192
143444 20166 14% 0.57K 5123 28 81968K radix_tree_node
768729 224574 29% 0.10K 19711 39 78844K buffer_head
73280 8287 11% 1.00K 2290 32 73280K xfs_inode
21263 19529 91% 2.84K 1933 11 61856K task_struct
686848 97798 14% 0.06K 10732 64 42928K kmalloc-64
223902 41010 18% 0.19K 5331 42 42648K dentry
32032 23282 72% 1.00K 1001 32 32032K kmalloc-1024
10234 9211 90% 1.88K 602 17 19264K TCP
22152 19924 89% 0.81K 568 39 18176K task_xstate
69216 59714 86% 0.25K 2163 32 17304K kmalloc-256
98421 23541 23% 0.15K 1857 53 14856K xfs_ili
5600 2915 52% 2.00K 350 16 11200K kmalloc-2048
这告诉我,blkdev_request 的构建是不是实际上与脏页有关,而且活动对象实际上并不活动?如果这些对象实际上没有被使用,如何释放它们?这是怎么回事?
作为背景介绍,以下是 drop_caches 所做的事情:
http://lxr.free-electrons.com/source/fs/drop_caches.c
更新:
算出来它们可能不是 blkdev_requests,但可能是出现在该“标题”下的 xfs_buf 条目?不确定这是如何工作的:
/sys/kernel/slab # ls -l blkdev_requests(
lrwxrwxrwx 1 root root 0 Nov 7 23:18 blkdev_requests -> :t-0000384/
/sys/kernel/slab # ls -l | grep 384
lrwxrwxrwx 1 root root 0 Nov 7 23:18 blkdev_requests -> :t-0000384/
lrwxrwxrwx 1 root root 0 Nov 7 23:19 ip6_dst_cache -> :t-0000384/
drwxr-xr-x 2 root root 0 Nov 7 23:18 :t-0000384/
lrwxrwxrwx 1 root root 0 Nov 7 23:19 xfs_buf -> :t-0000384/
我仍然不知道为什么这些会被“drop_slabs”清除,或者如何找出导致这种碎片的原因。
附加问题:有什么更好的方法可以找到这种碎片的根源?
如果您读到这里,感谢您的关注!
额外要求的信息:
内存和 xfs 信息: https://gist.github.com/christian-marie/f417cc3134544544a8d1
页面分配失败: https://gist.github.com/christian-marie/7bc845d2da7847534104
跟进:性能信息和压缩相关的事情
http://ponies.io/raw/compaction.png
压缩代码似乎有点低效,是吧?我拼凑了一些代码来尝试复制失败的压缩:https://gist.github.com/christian-marie/cde7e80c5edb889da541
这似乎重现了该问题。
我还要指出的是,事件跟踪告诉我有很多次回收失败,一遍又一遍:
<...>-322 [023] .... 19509.445609: mm_vmscan_direct_reclaim_end: nr_reclaimed=1
Vmstat 的输出也令人担忧。当系统处于高负载状态时,压缩会急剧增加(并且大多数都会失败):
pgmigrate_success 38760827 pgmigrate_fail 350700119 compact_migrate_scanned 301784730 compact_free_scanned 204838172846 compact_isolated 18711615 compact_stall 270115 compact_fail 244488 compact_success 25212
回收/压缩过程中确实存在一些问题。
目前,我正在考虑通过为 ipoib 设置添加 SG 支持来减少高阶分配。真正的问题似乎可能与 vmscan 有关。
这很有趣,并引用了这个问题:http://marc.info/?l=linux-mm&m=141607142529562&w=2
答案1
因为有很多评论,我想根据我的观察给出答案。
根据您的输出https://gist.github.com/christian-marie/7bc845d2da7847534104
我们可以确定以下内容:
- 尝试的内存分配的 GFP_MASK 可以执行以下操作。
- 可以进入紧急池(I思考这意味着访问区域高水位以下的数据)
- 不要使用紧急储备(我思考这意味着不允许访问低于最小水位的内存)
- 从其中一个正常区域分配。
- 可以交换以腾出空间。
- 可以删除缓存以腾出空间。
区域碎片位于此处:
[3443189.780792] Node 0 Normal: 3300*4kB (UEM) 8396*8kB (UEM) 4218*16kB (UEM) 76*32kB (UEM) 12*64kB (M) 0*128kB 0*256kB 0*512kB 0*1024kB 0*2048kB 0*4096kB = 151056kB
[3443189.780801] Node 1 Normal: 26667*4kB (UEM) 6084*8kB (UEM) 2040*16kB (UEM) 96*32kB (UEM) 22*64kB (UEM) 4*128kB (U) 0*256kB 0*512kB 0*1024kB 0*2048kB 0*4096kB = 192972kB
当时的内存使用情况如下:
[3443189.780759] Node 0 Normal free:149520kB min:40952kB low:51188kB high:61428kB active_anon:9694208kB inactive_anon:1054236kB active_file:7065912kB inactive_file:7172412kB unevictable:0kB isolated(anon):5452kB isolated(file):3616kB present:30408704kB managed:29881160kB mlocked:0kB dirty:0kB writeback:0kB mapped:25440kB shmem:743788kB slab_reclaimable:1362240kB slab_unreclaimable:783096kB kernel_stack:29488kB pagetables:43748kB unstable:0kB bounce:0kB free_cma:0kB writeback_tmp:0kB pages_scanned:0 all_unreclaimable? no
[3443189.780766] Node 1 Normal free:191444kB min:45264kB low:56580kB high:67896kB active_anon:11371988kB inactive_anon:1172444kB active_file:8084140kB inactive_file:8556980kB unevictable:0kB isolated(anon):4388kB isolated(file):4676kB present:33554432kB managed:33026648kB mlocked:0kB dirty:0kB writeback:0kB mapped:45400kB shmem:2263296kB slab_reclaimable:1606604kB slab_unreclaimable:438220kB kernel_stack:55936kB pagetables:44944kB unstable:0kB bounce:0kB free_cma:0kB writeback_tmp:0kB pages_scanned:0 all_unreclaimable? no
在页面分配失败输出中,每个区域的碎片情况都很糟糕。有很多空闲的 0 阶页面,而高阶页面则少得多甚至没有。“好”的结果将是每个阶都有充足的空闲页面,阶数越高,空闲页面的大小就越小。如果高阶页面 5 及以上为 0,则表示高阶分配存在碎片和匮乏。
我目前没有看到令人信服的证据表明此期间的碎片与 slab 缓存有关。在生成的内存统计数据中,我们可以看到以下内容
Node 0 = active_anon:9694208kB inactive_anon:1054236kB
Node 1 = active anon:11371988kB inactive_anon:1172444kB
用户空间没有分配大页面,因此用户空间将始终占用 0 阶内存。因此,两个区域总共有超过 22GiB 的可碎片整理内存。
我无法解释的行为
当高阶分配失败时,我的理解是内存压缩是总是尝试允许高阶内存分配区域发生并成功。为什么没有发生这种情况?如果确实发生了,为什么在有 22GiB 内存可供重新排序时找不到任何内存进行碎片整理?
我认为我可以解释的行为
这需要更多研究才能正确理解,但我相信自动交换/删除一些页面缓存的分配能力可能不适用于此,因为仍然有大量可用内存,因此不会发生回收。只是在高阶中还不够。
虽然有大量可用内存和每个区域中剩余一些订单 4 请求,“每个订单的所有可用内存总计并从实际可用内存中扣除”问题导致“可用内存”低于“最小”水位,这导致实际分配失败。
答案2
我们在 IP over IB 上使用 Ceph 时遇到了同样的 TX 数据包丢失问题。在我们的案例中,问题是由于 MTU 大小过大(64K)造成的。有人选择了较大的 MTU 大小(64K)来提高吞吐量。但是,当我们长时间运行 Ceph 并承受大量负载时,由于许多 TX 数据包丢失,吞吐量和 osd 延迟变得更糟。当我们将 MTU 大小更改为 9K 时,吞吐量和延迟变得稳定。我们还在考虑根据以下文章将 MTU 大小减小到 8K。 https://www.ibm.com/support/knowledgecenter/en/linuxonibm/liaag/wehs/l0wehs00_otherconfigurationconsiderationoptimalmtusize.htm