Größe von ZFS Datasets

jmt

Well-Known Member
Hallo,

ich habe FreeBSD 10.1 auf meinem Home-Server installiert und dort 2 ZFS-Pools angelegt. Einer als Mirror (2*250G) für das System und einer als Datengrab (RaidZ 5*3T). Als ich nun meine Backups von meinem Arbeitsplatzrechner auf den Homeserver zurückspielen wollte, stellte ich folgendes fest:
Auf dem Arbeitsplatzrechner beansprucht ein Backup (hier als Beispiel genutzt) 508M. Auf dem RaidZ werden daraus 919M und auf dem Mirror sind es noch 704M. Die Filesysteme haben jeweils gzip-9 Kompression. Als Ratio wird auf dem Server 2.59x angegeben. Auf dem Arbeitsplatzrechner ist es sogar nur 2.57x. Wie kommt es zu diesem unterschiedlichen Platzbedarf?
 
Die Daten habe ich alle mit
Code:
zfs list
ermittelt. Der Arbeitsplatzrechner hat ein ashift von 9, die andere beiden Pools ein ashift von 12.
 
Ja, das ist die Record- / Blocksize. Bei einem Ashift von 9 hast du eine minimale Blockgröße von 2^9=512 Byte, bei 12 schon 2^12=4096 Byte. Das führt zu mehr Verschnitt und pfuscht eventuell auch dem Kompressionsalgorithmus negativ ins Handwerk. Die 4-Platten waren daher streng genommen Betrug am Kunden. Was die Plattenhersteller an Metadaten einsparen konnten, verliert der Anwender wahlweise als Verschnitt (bei 4k-Blöcken) oder an Geschwindigkeit (bei 512 Byte Blöcken).
 
Ok, aber die beiden Pools auf meinem Server habe ja die gleiche Ashift. Sollte dann nicht auch die gleiche Menge Platz benötigt werden? 704 zu 919 ist ja schon eine erhebliche Abweichung.
 
Das ist ein Argument. Exakt gleiche Ausgaben kann man nicht erwarten, denn dazu hat ZFS zu viel Magie und zu viele von dir nicht beeinflussbare Faktoren. Beispielsweise kann schon eine andere Anordnung auf den Platten zu leicht abweichenden Werten führen. Ich würde hier darauf tippen, dass 'zfs list' sich beim RAIDZ anders als beim Mirror verhält und Redundanzdaten mit einbezieht. Beispielweise zeigt 'zfs list' bei einem RAIDZ1 aus 3 Platten mit je 4TB am Anfang ca. 12TB freien Speicher an. Obwohl natürlich eine der drei Platten real nicht nutzbar ist. Ob das sinnvoll und logisch ist, ist eine andere Frage. ;)
 
Ok, aber der andere Pool ist ein Mirror. Da sollten die Redundanzen doch größer sein. Kann es sein, dass größere Pools auch eine größere Blocksize haben und somit mehr Verschnitt? Es sind immerhin 78902 Inodes in dem FS. Als Tar ist das Backup 1,2G und belegt 463076k (laut ls).
 
Einmal kurz getestet, jedes "Device" ist 200M groß. Beginnen wir mal mit dem Mirror:
Code:
% zpool status spiegel
  pool: spiegel
state: ONLINE
  scan: none requested
config:

   NAME  STATE  READ WRITE CKSUM
   spiegel  ONLINE  0  0  0
    mirror-0  ONLINE  0  0  0
    md0  ONLINE  0  0  0
    md1  ONLINE  0  0  0

% zpool list spiegel
spiegel  195M  79K  195M  0%  -  0%  1.00x  ONLINE  -

% zfs list | grep spiegel
spiegel  73K  163M  19K  /mnt/mirror

Hier sieht man schon gut, dass ZFS gerade auf kleinen Devices einen relativ großen Metadaten-Overhead hat. Außerdem sind bereits seit einiger Zeit etwa 3,3% eines Pools reserviert, damit der Copy on Write Logik nicht der Speicher ausgeht. Was in älteren Versionen ja immer ein Problem war. So bleiben von 195M nur 163M nutzbar. Die "reale" Größe der Speichermedien von insgesamt ca. 400M taucht nirgends auf. Schreiben wir mal 50M Zufallsdaten:

Code:
% dd if=/dev/random of=data bs=1M count=50

% zpool list spiegel
NAME  SIZE  ALLOC  FREE  FRAG  EXPANDSZ  CAP  DEDUP  HEALTH  ALTROOT
spiegel  195M  50,1M  145M  7%  -  25%  1.00x  ONLINE  -

% zfs list | grep spiegel
spiegel  50,1M  113M  50,1M  /mnt/mirror

die 50M belegen also 50.1M realen Speicher. Was nun nicht verwundern, denn die minimale Blockgröße sind 2^9B und ich habe nur eine große Datei geschrieben. Da ist Verschnitt fast auszuschließen. Nun zum Vergleich das Ganze noch mal über ein RAIDZ1 aus 5 "Platten":

Code:
% zpool status raid
pool: raid
state: ONLINE
  scan: none requested
config:

   NAME  STATE  READ WRITE CKSUM
   raid  ONLINE  0  0  0
    raidz1-0  ONLINE  0  0  0
    md0  ONLINE  0  0  0
    md1  ONLINE  0  0  0
    md2  ONLINE  0  0  0
    md3  ONLINE  0  0  0
    md4  ONLINE  0  0  0

errors: No known data errors

% zpool list raid
NAME  SIZE  ALLOC  FREE  FRAG  EXPANDSZ  CAP  DEDUP  HEALTH  ALTROOT
raid  976M  136K  976M  0%  -  0%  1.00x  ONLINE  -

% zfs list | grep raid
raid  99,1K  748M  27,2K  /mnt/raid

Die reale Größe sind 976M, davon sind erst einmal 748M nutzbar. Schreiben wir also wieder 50M Zufallsdaten:

Code:
% dd if=/dev/random of=data bs=1M count=50

% zpool list raid
NAME  SIZE  ALLOC  FREE  FRAG  EXPANDSZ  CAP  DEDUP  HEALTH  ALTROOT
raid  976M  62,8M  913M  5%  -  6%  1.00x  ONLINE  -

% zfs list | grep raid
raid  50,1M  698M  50,0M  /mnt/raid

Und nun sieht man, dass ich oben im Thread Mist erzählt habe. Oder besser gesagt mich geirrt habe. Während 'zpool list' tatsächlich beim Mirror die Redundanz raus läst und beim RAIDZ1 mit einbezieht, tut 'zfs list' es nicht. Schalten wir also mal Kompression ein. Dieses mal schreibe ich 50M gut komprimierbare Daten. Zuerst der Mirror:

Code:
% zfs set compression=gzip spiegel

% cp /tmp/50M /mnt/mirror

% zfs list | grep spiegel
spiegel  6,11M  157M  6,03M  /mnt/mirror

Und nun das RAIDZ1:
Code:
% zfs set compression=gzip raid

% cp /tmp/50M /mnt/raid
% zfs list | grep raid
raid  6,27M  741M  6,17M  /mnt/raid

Hier hat das RAIDZ1 einen leicht größeren Overhead, aber die paar Kilobyte mögen auch nur Rauschen sein. Fazit: Klein-Yamagi zieht seine Erklärung in Sachen Einbeziehung der Redundanz zurück und weiß nicht so recht, was bei dir passiert. Außer vielleicht, dass die 3,3% und der Metadaten-Overhead den Unterschied erklären. Das wäre dann auch bei leerem Pool im 'zfs list' zu sehen. Vielleicht hat ja noch jemand anders eine Idee. :)
 
So etwas habe ich auch bei großen Dateien festgestellt. Ich habe besagtes Backup in ein Tar-Archiv gepackt und dann kopiert. Die Archive belegen auf beiden Systemen fast den gleichen Platz. Dies ändert sich halt drastisch, wenn man mit dem entpackten Archiv arbeitet. Yamagi, hast Du eine Datei oder viele kleine Dateien für Deinen Test verwendet?

Mir kommt es so vor, als würde ZFS bei größeren Pools auch eine größere minimale Blockgröße verwenden.
 
Hier ein paar Beobachtungen:

Verzeichnis auf 250G:
Code:
 # ll
total 479505
-rw-r--r--  1 root  wheel  1291702272 Jan 14 02:23 dumont.tar
Dergleichen auf 10T:
Code:
# ll
total 505250
-rw-r--r--  1 root  wheel  1291702272 Jan 14 02:23 dumont.tar
Man muss nach dem Kopieren etwas warten, da die "total"-Angabe erst langsam ihren endgültigen Wert erreicht.

Nun ein Test mit vielen Dateien ohne Inhalt:
1101000 Files
1102 Directories

250G:
Code:
# zfs list sys/HOME/f
NAME         USED  AVAIL  REFER  MOUNTPOINT
sys/HOME/f   299M   206G   299M  /export/home/f
Dergleichen auf 10T:
Code:
# zfs list tank/BACKUP/Rechner/f
NAME                    USED  AVAIL  REFER  MOUNTPOINT
tank/BACKUP/Rechner/f   464M  2.87T   464M  /export/backup/Rechner/f

Damit verbraucht der größere Pool 50% mehr Platz bei leeren Dateien.

Nun noch mal mit gut komprimierbaren Daten:
File: rc.initdiskless von 10.1-RELEASE-p3
111000 Files
112 Directories

250G:
Code:
]# zfs list sys/HOME/g
NAME         USED  AVAIL  REFER  MOUNTPOINT
sys/HOME/g   897M   205G   897M  /export/home/g
Dergleichen auf 1T:
Code:
# zfs list tank/BACKUP/Rechner/g
NAME                    USED  AVAIL  REFER  MOUNTPOINT
tank/BACKUP/Rechner/g  1.40G  2.87T  1.40G  /export/backup/Rechner/g

Kleiner Auszug aus zfs get all:
250G:
Code:
sys/HOME/g  referenced  897M  -
sys/HOME/g  compressratio  2.58x  -
sys/HOME/g  recordsize  128K  defaultsys/HOME/g  checksum  on  default
sys/HOME/g  compression  gzip-9  local
sys/HOME/g  usedbysnapshots  0  -
sys/HOME/g  usedbydataset  897M  -
sys/HOME/g  refcompressratio  2.58x  -
sys/HOME/g  written  897M  -
sys/HOME/g  logicalused  1.38G  -
sys/HOME/g  logicalreferenced  1.38G  -
Dergleichen auf 10T:
Code:
tank/BACKUP/Rechner/g  referenced  1.40G  -
tank/BACKUP/Rechner/g  compressratio  2.58x  -
tank/BACKUP/Rechner/g  recordsize  128K  default
tank/BACKUP/Rechner/g  compression  gzip-9  local
tank/BACKUP/Rechner/g  usedbysnapshots  0  -
tank/BACKUP/Rechner/g  usedbydataset  1.40G  -
tank/BACKUP/Rechner/g  refcompressratio  2.58x  -
tank/BACKUP/Rechner/g  written  1.40G  -
tank/BACKUP/Rechner/g  logicalused  1.38G  -
tank/BACKUP/Rechner/g  logicalreferenced  1.38G

Bei dem großen Pool verbraucht der mit Ratio 2.58 komprimierte mehr Platz als der nicht komprimierte Inhalt.
 
Spaßeshalber habe ich den letzten Test von oben ( mit rc. ) noch mal auf einem unkomprimierten FS gemacht. Hier die Ergebnisse:
250G:
Code:
sys/HOME/h  referenced  1.72G  -
sys/HOME/h  compressratio  1.00x  -
sys/HOME/h  recordsize  128K  default
sys/HOME/h  compression  off  local
sys/HOME/h  usedbysnapshots  0  -
sys/HOME/h  usedbydataset  1.72G  -
sys/HOME/h  refcompressratio  1.00x  -
sys/HOME/h  written  1.72G  -
sys/HOME/h  logicalused  1.38G  -
sys/HOME/h  logicalreferenced  1.38G  -
Dergleichen mit 10T:
Code:
tank/BACKUP/Rechner/h  referenced  2.08G  -
tank/BACKUP/Rechner/h  compressratio  1.00x  -
tank/BACKUP/Rechner/h  recordsize  128K  default
tank/BACKUP/Rechner/h  compression  off  local
tank/BACKUP/Rechner/h  usedbysnapshots  0  -
tank/BACKUP/Rechner/h  usedbydataset  2.08G  -
tank/BACKUP/Rechner/h  refcompressratio  1.00x  -
tank/BACKUP/Rechner/h  written  2.08G  -
tank/BACKUP/Rechner/h  logicalused  1.38G  -
tank/BACKUP/Rechner/h  logicalreferenced  1.38G  -
Warum auch immer, der große Pool verbraucht mehr Platz als der kleine. Das habe ich so nicht erwartet. Es scheint fast so, als sollte man verschiedene Pools für unterschiedliche Daten haben. Habt Ihr das erwartet oder eine Erklärung dafür?
 
Zurück
Oben