使用xfs,20个磁盘和Ceph的“大型”服务器上页面碎片的原因

任何在Linux IO系统方面具有一定经验的人的洞察力都是有帮助的。 这是我的故事:

最近提出了六个戴尔PowerEdge rx720xds集群通过Ceph提供文件。 这些机器有24个核心,两个插槽,两个numa区和70千兆字节的内存。 磁盘被格式化为每个磁盘的扫描(我们看不到直接暴露它们的方法)。 networking由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 

通过这些机器的IO会以几百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/sr/sw/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 

当碎片变得更糟,系统似乎开始在内核空间旋转,一切都崩溃了。 在这个失败期间的一个exception是,xfsaild似乎使用了大量的CPU,并陷入了不可中断的睡眠状态。 尽pipe如此,在系统总体失败期间,我不想妄加任何奇怪的结论。

解决方法到目前为止。

为了确保这些分配不失败,即使在分散的情况下,我也设定:

 vm.min_free_kbytes = 16777216 

在SLAB高速caching中看到数以百万计的blkdev_requests后,我试图通过以下方式减less脏页面:

 vm.dirty_ratio = 1 vm.dirty_background_ratio = 1 vm.min_slab_ratio = 1 vm.zone_reclaim_mode = 3 

可能会同时改变太多的variables,但是为了防止inode和dentries造成碎片,我决定把它们保持在最低限度:

 vm.vfs_cache_pressure = 10000 

这似乎有帮助。 碎片仍然很高,减lessinode和dentry的问题意味着我注意到一些奇怪的东西,导致我…

我的问题:

为什么我有这么多的blkdev_requests(这些活动不less),当我放弃caching时就会消失?

这是我的意思:

 # slabtop -o -sc | 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 -sc | 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的build立实际上并不涉及到脏页面,而且活动对象并不真正活动? 如果这些物体实际上没有被使用,这些物体怎么能被释放? 这里发生了什么?

对于一些背景,下面是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”清除了,或者如何解决导致这种碎片化的原因。

奖金的问题:什么是更好的方式来find这种碎片的来源?

如果你读了这么多,谢谢你的关注!

额外要求的信息:

内存和xfs信息: https : //gist.github.com/christian-marie/f417cc3134544544a8d1

页面分配失败: https : //gist.github.com/christian-marie/7bc845d2da7847534104

跟进:perf信息和压缩相关的东西

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

我想我会用我的观察来回答,因为有很多评论。

根据你的输出在https://gist.github.com/christian-marie/7bc845d2da7847534104

我们可以确定如下:

  1. 所尝试的内存分配的GFP_MASK被允许执行以下操作。
    • 可以访问应急池(我认为这意味着访问一个区域的高水位以下的数据)
    • 不要使用紧急储备(我认为这意味着不允许访问低于最小水印的memroy)
    • 从一个正常区域分配。
    • 可以交换,以腾出空间。
    • 可以放下caching以腾出空间。

区域碎片位置在这里:

 [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页,less到更高的订单页面。 一个“好”的结果将是每个订单的丰富的免费页面,随着订单的顺序越高,尺寸越小。 具有0的高阶页面5及以上表示高阶分配的分裂和饥饿。

我目前还没有看到有说服力的证据表明在这个时期的分裂与板砖缓冲有什么关系。 在得到的内存统计中,我们可以看到以下内容

 Node 0 = active_anon:9694208kB inactive_anon:1054236kB Node 1 = active anon:11371988kB inactive_anon:1172444kB 

用户空间没有大的页面分配,因此用户空间总是要求0号内存。 因此,在这两个地区总共有超过22GiB的碎片整理内存。

我无法解释的行为

当高阶分配失败时,我的理解是总是试图进行内存压缩,以便允许高阶内存分配的区域发生并成功。 为什么这不会发生? 如果真的发生了,那么为什么在22GiB的重新sorting时间里没有find任何内存碎片?

行为我想我可以解释

这需要更多的研究才能正确理解,但是我相信分配自动交换/放下一些页面caching成功的能力在这里可能不适用,因为有很多空闲内存仍然可用,所以不会发生回收。 在更高的订单只是不够。

虽然在每个区域剩下大量的空闲内存几个4阶请求,但是“最小”水印下的“空闲内存”是“每个命令的总空闲内存总数和从实际空闲内存中扣除”的结果,什么导致了实际的分配失败。