具有 xfs、20 个磁盘和 Ceph 的“大型”服务器上页面碎片的原因

pin*_*ngu 18 linux xfs fragmentation linux-kernel ceph

对 linux IO 系统有一定经验的人的任何见解都会有所帮助。这是我的故事:

最近建立了一个由六个 Dell PowerEdge rx720xds 组成的集群,通过 Ceph 提供文件。这些机器在两个插槽上有 24 个内核,有两个 numa 区域和 70 GB 的内存。磁盘被格式化为一个磁盘的突袭(否则我们看不到直接暴露它们的方法)。网络由 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
Run Code Online (Sandbox Code Playgroud)

通过这些机器的 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/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
Run Code Online (Sandbox Code Playgroud)

问题:

大约 48 小时后,连续页面非常碎片化,以至于 magniutde 四个(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 
Run Code Online (Sandbox Code Playgroud)

当碎片变得相当严重时,系统似乎开始在内核空间中旋转,一切都崩溃了。此故障期间的一个异常情况是 xfsaild 似乎使用了大量 CPU 并陷入不间断睡眠状态。不过,我不想在整个系统故障期间突然得出任何奇怪的结论。

到目前为止的解决方法。

为了确保这些分配不会失败,即使在碎片情况下,我设置:

vm.min_free_kbytes = 16777216
Run Code Online (Sandbox Code Playgroud)

在 SLAB 缓存中看到数百万个 blkdev_requests 后,我尝试通过以下方式减少脏页:

vm.dirty_ratio = 1
vm.dirty_background_ratio = 1
vm.min_slab_ratio = 1
vm.zone_reclaim_mode = 3
Run Code Online (Sandbox Code Playgroud)

可能一次更改太多变量,但以防万一 inode 和 dentries 导致碎片化,我决定将它们保持在最低限度:

vm.vfs_cache_pressure = 10000
Run Code Online (Sandbox Code Playgroud)

这似乎有所帮助。尽管如此,碎片仍然很高,减少的 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           
Run Code Online (Sandbox Code Playgroud)

这是说,我认为在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/
Run Code Online (Sandbox Code Playgroud)

我仍然不知道为什么这些会被“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

Mat*_*Ife 4

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

基于您在https://gist.github.com/christian-marie/7bc845d2da7847534104的输出

我们可以确定以下几点:

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

区域碎片位于此处:

[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
Run Code Online (Sandbox Code Playgroud)

而当时的内存利用率是这样的:

[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
Run Code Online (Sandbox Code Playgroud)

页面分配失败输出中每个区域的碎片都是坏的。有很多自由的 0 阶页面,而高阶页面则少得多甚至没有。一个“好的”结果是每个订单都有大量的免费页面,订单越高,页面的大小逐渐变小。具有 0 个高阶页 5 及以上表示高阶分配出现碎片和饥饿。

我目前没有看到令人信服的证据表明这一时期的碎片与slab 缓存有关。在生成的内存统计数据中,我们可以看到以下内容

Node 0 = active_anon:9694208kB inactive_anon:1054236kB
Node 1 = active anon:11371988kB inactive_anon:1172444kB
Run Code Online (Sandbox Code Playgroud)

用户空间没有分配大页,因此用户空间将始终占用 0 阶内存。因此,这两个区域总共有超过 22GiB 的可碎片整理内存。

我无法解释的行为

当高阶分配失败时,我的理解是,总是尝试内存压缩,以便允许高阶内存分配区域发生并成功。为什么这不会发生?如果确实发生了,为什么当有 22GiB 的内存可供重新排序时却找不到任何内存来进行碎片整理?

我认为我可以解释的行为

这需要更多的研究才能正确理解,但我相信分配自动交换/删除某些页面缓存以成功的能力可能不适用于此处,因为仍然有大量可用内存,因此不会发生回收。只是在更高的订单中还不够。

虽然每个区域中都留有大量可用内存一些订单 4 请求,但“每个订单的所有可用内存总计并从实际可用内存中扣除”问题会导致“可用内存”低于“最小”水位线,即是什么导致了实际的分配失败。