首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >ZFS --为什么压缩文件显示磁盘使用量几乎是表观大小的两倍?

ZFS --为什么压缩文件显示磁盘使用量几乎是表观大小的两倍?
EN

Unix & Linux用户
提问于 2023-04-19 05:27:18
回答 1查看 70关注 0票数 1

使用FreeBSD 11.1-稳定,我有一个ZFS数据集配置gzip-9压缩,以及记录大小为8K。(此卷用于小文件的存档,而不是速度。)

zfs get all pool02/redactedStorage显示的压缩比为1.4x,比我预料的还要糟糕,但这里有大量的文本文件和压缩文件,所以这并不令人担忧。然后,我查看了存储在该数据集中的一些大型的压缩文件,并感到困惑。

du -hdu -hA的输出不是我所期望的压缩文件的输出。

例如,我预计一个40 MB的零文件几乎不会占用任何磁盘空间:

代码语言:javascript
运行
复制
# dd if=/dev/zero of=testfile bs=4M count=10
# du -h testfile
512B    testfile
# du -hA testfile
 40M    testfile

但是我预计一个40 MB的随机文件会占用大约40 MB的磁盘空间,因为它是不可压缩的(为了所有实际目的)。但我没想到它会消耗近两倍的空间:

代码语言:javascript
运行
复制
# dd if=/dev/random of=testfile.rnd bs=4M count=10
# du -h testfile.rnd
 92M    testfile.rnd
# du -hA testfile.rnd
 40M    testfile.rnd

从研究来看,它似乎是间接地占用了额外的空间。

对于testfile (零):

代码语言:javascript
运行
复制
Dataset pool02/redactedStorage [ZPL], ID 56, cr_txg 360697, 958G, 22881480 objects, rootbp DVA[0]=<0:9dd68959000:3000> DVA[1]=<0:14e1475b5000:3000> [L0 DMU objset] fletcher4 uncompressed LE contiguous unique double size=800L/800P birth=25863270L/25863270P fill=22881480 cksum=13497492df:14cc540c2b5f:e089aa02d6109:73afb0d244bcb42

    Object  lvl   iblk   dblk  dsize  lsize   %full  type
  22910497    3   128K     8K      0  40.0M    0.00  ZFS plain file
                                        168   bonus  System attributes
        dnode flags: USED_BYTES USERUSED_ACCOUNTED
        dnode maxblkid: 5119
        path    /testfile
        uid     0
        gid     1004
        atime   Wed Apr 19 00:08:20 2023
        mtime   Wed Apr 19 00:08:20 2023
        ctime   Wed Apr 19 00:08:20 2023
        crtime  Wed Apr 19 00:08:20 2023
        gen     25862395
        mode    100644
        size    41943040
        parent  17938432
        links   1
        pflags  40800000004
Indirect blocks:
    [ No Indirect blocks ]

对于testfile.rnd (随机性):

代码语言:javascript
运行
复制
Dataset pool02/redactedStorage [ZPL], ID 56, cr_txg 360697, 958G, 22881480 objects, rootbp DVA[0]=<0:9dbfec9d000:3000> DVA[1]=<0:14ffe1461000:3000> [L0 DMU objset] fletcher4 uncompressed LE contiguous unique double size=800L/800P birth=25863170L/25863170P fill=22881480 cksum=13b3f2c021:15912a82ff8a:ebef1e0641453:7abda3903292dba

    Object  lvl   iblk   dblk  dsize  lsize   %full  type
  22910499    3   128K     8K  91.9M  40.0M  100.00  ZFS plain file
                                        168   bonus  System attributes
        dnode flags: USED_BYTES USERUSED_ACCOUNTED
        dnode maxblkid: 5119
        path    /testfile.rnd
        uid     0
        gid     1004
        atime   Wed Apr 19 00:16:47 2023
        mtime   Wed Apr 19 00:16:48 2023
        ctime   Wed Apr 19 00:16:48 2023
        crtime  Wed Apr 19 00:16:47 2023
        gen     25862495
        mode    100644
        size    41943040
        parent  17938432
        links   1
        pflags  40800000004
Indirect blocks:
    [ 5120 Indirect blocks redacted ]

那么,它是5120个间接块*128 K=640米,然后这些块被压缩,从而导致51.9米的开销?

如果是的话,什么是最好的方法来避免混乱呢?创建一个具有更大记录大小的新数据集并将内容移到上面?

以下是我的数据集参数:

代码语言:javascript
运行
复制
NAME                  PROPERTY              VALUE                      SOURCE
pool02/redactedStorage  type                  filesystem                 -
pool02/redactedStorage  creation              Mon Jan 28  1:03 2019      -
pool02/redactedStorage  used                  958G                       -
pool02/redactedStorage  available             15.1T                      -
pool02/redactedStorage  referenced            958G                       -
pool02/redactedStorage  compressratio         1.40x                      -
pool02/redactedStorage  mounted               yes                        -
pool02/redactedStorage  quota                 none                       local
pool02/redactedStorage  reservation           none                       local
pool02/redactedStorage  recordsize            8K                         local
pool02/redactedStorage  mountpoint            /mnt/pool02/redactedStorage  default
pool02/redactedStorage  sharenfs              off                        default
pool02/redactedStorage  checksum              on                         default
pool02/redactedStorage  compression           gzip-9                     local
pool02/redactedStorage  atime                 on                         default
pool02/redactedStorage  devices               on                         default
pool02/redactedStorage  exec                  on                         default
pool02/redactedStorage  setuid                on                         default
pool02/redactedStorage  readonly              off                        default
pool02/redactedStorage  jailed                off                        default
pool02/redactedStorage  snapdir               hidden                     default
pool02/redactedStorage  aclmode               passthrough                local
pool02/redactedStorage  aclinherit            passthrough                inherited from pool02
pool02/redactedStorage  canmount              on                         default
pool02/redactedStorage  xattr                 off                        temporary
pool02/redactedStorage  copies                1                          default
pool02/redactedStorage  version               5                          -
pool02/redactedStorage  utf8only              off                        -
pool02/redactedStorage  normalization         none                       -
pool02/redactedStorage  casesensitivity       sensitive                  -
pool02/redactedStorage  vscan                 off                        default
pool02/redactedStorage  nbmand                off                        default
pool02/redactedStorage  sharesmb              off                        default
pool02/redactedStorage  refquota              none                       local
pool02/redactedStorage  refreservation        none                       local
pool02/redactedStorage  primarycache          all                        default
pool02/redactedStorage  secondarycache        all                        default
pool02/redactedStorage  usedbysnapshots       0                          -
pool02/redactedStorage  usedbydataset         958G                       -
pool02/redactedStorage  usedbychildren        0                          -
pool02/redactedStorage  usedbyrefreservation  0                          -
pool02/redactedStorage  logbias               latency                    default
pool02/redactedStorage  dedup                 off                        inherited from pool02
pool02/redactedStorage  mlslabel                                         -
pool02/redactedStorage  sync                  standard                   default
pool02/redactedStorage  refcompressratio      1.40x                      -
pool02/redactedStorage  written               958G                       -
pool02/redactedStorage  logicalused           501G                       -
pool02/redactedStorage  logicalreferenced     501G                       -
pool02/redactedStorage  volmode               default                    default
pool02/redactedStorage  filesystem_limit      none                       default
pool02/redactedStorage  snapshot_limit        none                       default
pool02/redactedStorage  filesystem_count      none                       default
pool02/redactedStorage  snapshot_count        none                       default
pool02/redactedStorage  redundant_metadata    all                        default

以及显示相关池的zdb的部分输出:

(请注意这个池的底层vdev的ashift: 12。)

代码语言:javascript
运行
复制
pool02:
    version: 5000
    name: 'pool02'
    state: 0
    txg: 25383030
    pool_guid: 1288056053628670413
    hostid: 3785389258
    hostname: 'redacted'
    com.delphix:has_per_vdev_zaps
    vdev_children: 1
    vdev_tree:
        type: 'root'
        id: 0
        guid: 1288056053628670413
        create_txg: 4
        children[0]:
            type: 'raidz'
            id: 0
            guid: 9072182531784548301
            nparity: 2
            metaslab_array: 49
            metaslab_shift: 37
            ashift: 12
            asize: 23978959699968
            is_log: 0
            create_txg: 4
            com.delphix:vdev_zap_top: 36
            children[0]:
                type: 'disk'
                id: 0
                guid: 17108175667375824896
                path: '/dev/gptid/e07bacd6-1224-11e9-98bd-90b11c29519f'
                whole_disk: 1
                DTL: 293
                create_txg: 4
                com.delphix:vdev_zap_leaf: 37
            children[1]:
                type: 'disk'
                id: 1
                guid: 6726950469173540573
                path: '/dev/gptid/e443f9f2-1224-11e9-98bd-90b11c29519f'
                whole_disk: 1
                DTL: 292
                create_txg: 4
                com.delphix:vdev_zap_leaf: 38
--------==== 10 ADDITIONAL PHY DISKS REDACTED ====---------            
    features_for_read:
        com.delphix:hole_birth
        com.delphix:embedded_data
EN

回答 1

Unix & Linux用户

发布于 2023-04-20 05:54:05

在由12个带4K扇区的磁盘组成的vdev上对8K记录进行条带化( ashift为12)是一个糟糕的想法,并造成巨大的开销:

来自OpenZFS:

https://openzfs.github.io/openzfs-docs/Basic概念/RAIDZ.html

由于这些输入,如果记录大小小于或等于扇区大小,则RAIDZ的奇偶校验大小将有效地等于具有相同冗余的镜像。例如,对于具有raidz1和recordsize=4K的3个磁盘,我们将在磁盘上分配:

  • 一个4K数据块
  • 一个4K填充块

可用空间比为50%,与双面镜相同。3个磁盘的ashift=12和recordsize=128K的raidz1的另一个示例:

  • 总条纹宽度为3
  • 一个条带可以有多达2个4K大小的数据部分,因为有一个奇偶校验块。
  • 我们将有128 K/2= 64条,数据为8K,平价为4K。

因此,在这种情况下,可用空间比率将为66%。RAIDZ的磁盘越多,条纹越宽,空间效率越高。

该文本后面是一个图表,如果截图并包含在这里,它将是难以辨认的,但它表明,对于记录大小为1倍或2倍的扇区大小,开销将是67%的RAIDZ2。

根据图表,这种情况下的解决方案是将recordsize提高到256 K,这在12个磁盘RAIDZ2 vdev上的parity+padding成本为18%。(相比之下,128 K recordsize将产生24%的开销)。

但没那么简单。对于“经典”文件系统,最初选择8K recordsize可能是正确的,因为recordsize最大块大小,而不是固定块大小。但是,对于具有相对较小文件的较大recordsize,仍有一定的损失。

增加recordsize只会影响更改后创建的数据,但在这种情况下,池的空间消耗仅为6%,当前压缩比为1.4x。现有数据可以保持在原地,而不会造成任何长期能力问题。然而,在需要收回间接费用的情况下:

https://openzfs.github.io/openzfs-docs/Performance和调优/工作负载Tuning.html

如果更改记录大小是因为应用程序在使用不同的应用程序时执行得更好,则需要重新创建其文件。在每个文件上,cp后面跟着mv就足够了。或者,当完成完整接收时,send/recv应该重新创建具有正确记录大小的文件。

从一个在泳池上进行的真实实验中得出:

代码语言:javascript
运行
复制
# zfs set recordsize=256K pool02/redactedStorage

# dd if=/dev/zero of=testfile256.40M.zeroes bs=1M count=40
# du -h testfile256.40M.zeroes
512B    testfile256.40M.zeroes

# dd if=/dev/random of=testfile256.40M.rnd bs=1M count=40
# du -h testfile256.40M.rnd
 40M    testfile256.40M.rnd

# dd if=/dev/random of=testfile256.8K.rnd bs=8192 count=1
# du -h testfile256.8K.rnd
 37K    testfile256.8K.rnd

正如您所看到的,一个40M文件使用的是逻辑上的空间。但是一个8K文件正在消耗37K的空间!

因此,recordsize应该调优到数据集的内容。

当然,128 K的默认recordsize似乎是最优的,我只是不应该碰它。

代码语言:javascript
运行
复制
# zfs set recordsize=128K pool02/redactedStorage
# cp testfile256.40M.rnd testfile128.40M.rnd
# du -h testfile128.40M.rnd
512B    testfile128.40M.rnd
# mv testfile128.40M.rnd testfile128.40M.rnd2
# du -h testfile128.40M.rnd2
 40M    testfile128.40M.rnd2

# cp testfile256.8K.rnd testfile128.8K.rnd
# mv testfile128.8K.rnd testfile128.8K.rnd2
# du -h testfile128.8K.rnd2
 19K    testfile128.8K.rnd2

这确实显示了使用19K磁盘空间的8K测试文件,但是存在必要的元数据开销。查看不可压缩的现有文件<=8K的大小,它们都显示了在原始recordsize=8K下磁盘使用情况的19K。我进一步尝试了recordsize=64K,它并没有改变这些样本文件的大小。

还请注意,在新的cp下创建文件的实例确实需要mv后面的D34

这篇文章还很好地描述了正在发生的事情,我将为后人介绍:

https://klarasystems.com/articles/choosing-the-right-zfs-pool-layout/

  1. Padding、磁盘扇区大小和记录大小设置:在RAID-Z中,奇偶校验信息与每个块相关联,而不是RAID-5中的特定条带,因此每个数据分配必须是p+1 (parity+1)的倍数,以避免释放的段太小而不能重用。如果分配的数据不是p+1‘填充’的倍数,这就是RAID-Z比RAID-5需要更多空间进行奇偶校验和填充的原因。这是一个复杂的问题,但简而言之:为了避免空间效率低下,您必须保持ZFS记录大小比磁盘扇区大小大得多;您可以在512个字节扇区磁盘上使用recordsize=4K或8K,但是如果您使用的是4K扇区,那么记录大小应该是原来的几倍(默认的128 K),否则您可能会损失太多的空间。
票数 3
EN
页面原文内容由Unix & Linux提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://unix.stackexchange.com/questions/743384

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档