Während meiner Benchmarks für den gemeinsamen Technical Report mit NetApp & Veeam TR-4948 wurde mir bewusst, wie wichtig das Thema LVM für eine gute Storage Performance ist. In aktuellen Veeam Projekten nutzen wir bevorzugt Hardened Repositories mit einer Kombination aus einem Rackserver + einer E-Series als direct attached Storage via FC oder SAS.

Die allermeisten Storage Systeme am Markt profitieren von Parallelität, also mehreren RAIDs, Volumes und LUNs, die optimalerweise bei Dual-Controller Systemen wie der NetApp E-Series über beide Controller präsentiert werden, um die maximale Performance zu erreichen. Dieser Ansatz hat jedoch den Nachteil, dass man dadurch sehr viele, unter Umständen kleine Objekte in Form von LUNs erzeugt. Besonders in Backup Umgebungen ist man jedoch daran interessiert, möglichst große und zusammenhängende Speicherbereiche zu haben, da die Job Administration sonst sehr komplex werden kann. Und genau diese beiden gegensätzlichen Ansätze lassen sich mit LVM perfekt vereinen.

Offtopic: Stand heute ist es leider so, dass mit der kommenden Version v13 von Veeam Backup & Replication das Deployment von Hardened Repositories deutlich vereinfacht wird, leider aber noch ohne external Storage Support. Bedeutet: Hier ist weiterhin ein manuelles Deployment z.B. mittels Rocky Linux nötig.

Bevor es mit den eigentlichen Tests losgeht, hier ein paar Worte zum Thema LVM unter Linux. LVM steht für Logical Volume Manager und ist eine Abstraktionsebene zu den physikalischen Speichergeräten. Mittels LVM lassen sich logische Datenträger auch über mehrere Festplatten hinweg erzeugen, und genau darum soll es in diesem Beitrag gehen.

LVM Linear

Wenn man von LVM spricht, geht es meistens um das „Standard LVM“ im linearen Modus. Hier werden mehrere Disks/LUNs logisch zusammengefasst und die Daten sequentiell auf die verfügbaren Member Disks geschrieben. Dabei wird eine Disk erst komplett gefüllt, bevor die nächste genutzt wird. Dieser Modus ist sehr einfach zu verwalten, lässt sich gut erweitern und eignet sich hervorragend, wenn man einfach nur einen Namespace mit großer Kapazität benötigt, Performance aber nicht elementar ist. Ein Vorteil ist noch das die Disks auch unterschiedlich groß sein können.

LVM Striping

Im Gegensatz dazu lässt sich durch Striping eine geringere Latenz und ein deutlich höherer Durchsatz erreichen, was LVM Striping zu einem mächtigen Feature macht. Dabei werden die Daten gleichmäßig über alle Disks/LUNs verteilt, alle Reads und Writes landen mit der angegebenen Stripe Size auf den Member Disks welche gleichmäßig gefüllt werden. Aufgrund des Stripings müssen alle Disks/LUNs innerhalb eines Stripesets gleich groß sein, das sollte man z.B. für Erweiterungen beachten. Hat man unterschiedliche Größen müsste man ein neues Stripeset beginnen und würde dann logischerweise auch nur hierrüber die Daten verteilen.

LVM Linear konfigurieren

Die Devices sdb, sdc, sdd und sde sind jeweils 100GB große VMDKs und werden für das LVM verwendet.

root@vhr-rocky veeam]# lsblk
NAME        MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
sda           8:0    0  100G  0 disk
├─sda1        8:1    0  600M  0 part /boot/efi
├─sda2        8:2    0    1G  0 part /boot
└─sda3        8:3    0 98.4G  0 part
  ├─rl-root 253:0    0 60.8G  0 lvm  /
  ├─rl-swap 253:1    0  7.9G  0 lvm  [SWAP]
  └─rl-home 253:2    0 29.7G  0 lvm  /home
sdb           8:16   0  100G  0 disk
sdc           8:32   0  100G  0 disk
sdd           8:48   0  100G  0 disk
sde           8:64   0  100G  0 disk
sdf           8:80   0  110G  0 disk
sdg           8:96   0  110G  0 disk
sdh           8:112  0  110G  0 disk
sdi           8:128  0  110G  0 disk

Erzeugt die Volumegroup mit den Namen „vg_linear“

[root@vhr-rocky veeam]#  vgcreate vg_linear /dev/sdb /dev/sdc /dev/sdd /dev/sde
  Physical volume "/dev/sdb" successfully created.
  Physical volume "/dev/sdc" successfully created.
  Physical volume "/dev/sdd" successfully created.
  Physical volume "/dev/sde" successfully created.
  Volume group "vg_linear" successfully created

Logical Volume „lv_linear“ anlegen.

[root@vhr-rocky veeam]# lvcreate -l 100%FREE  -n lv_linear  vg_linear
  Logical volume "lv_linear" created.

lvdisplay zeigt Details zum Logical Volume, die relevanten Teile habe ich hervorgehoben.

[root@vhr-rocky veeam]# lvdisplay -m /dev/vg_linear/lv_linear
  --- Logical volume ---
  LV Path                /dev/vg_linear/lv_linear
  LV Name                lv_linear
  VG Name                vg_linear
  LV UUID                57GeWQ-Miyb-GX07-kXPW-rjjl-sfNV-1g0ouO
  LV Write Access        read/write
  LV Creation host, time vhr-rocky, 2025-05-27 11:54:49 +0200
  LV Status              available
  # open                 0
  LV Size                399.98 GiB
  Current LE             102396
  Segments               4
  Allocation             inherit
  Read ahead sectors     auto
  - currently set to     256
  Block device           253:3

  --- Segments ---
  Logical extents 0 to 25598:
    Type                linear
    Physical volume     /dev/sdb
    Physical extents    0 to 25598

  Logical extents 25599 to 51197:
    Type                linear
    Physical volume     /dev/sdc
    Physical extents    0 to 25598

  Logical extents 51198 to 76796:
    Type                linear
    Physical volume     /dev/sdd
    Physical extents    0 to 25598

  Logical extents 76797 to 102395:
    Type                linear
    Physical volume     /dev/sde
    Physical extents    0 to 25598

Anschließend noch das Filesystem anlegen, mounten und die Filesystem Rechte vergeben.

mkfs.xfs -b size=4096 -m reflink=1,crc=1 /dev/vg_linear/lv_linear

mkdir /mnt/linear
mount /dev/vg_linear/lv_linear  /mnt/linear/

sudo chown -R veeam:veeam /mnt/linear
sudo chmod 700 /mnt/linear

LVM Striping konfigurieren

Die Devices sdf, sdf, sdh und sdi sind jeweils 110GB große VMDKs und werden für das LVM verwendet.

root@vhr-rocky veeam]# lsblk
NAME        MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
sda           8:0    0  100G  0 disk
├─sda1        8:1    0  600M  0 part /boot/efi
├─sda2        8:2    0    1G  0 part /boot
└─sda3        8:3    0 98.4G  0 part
  ├─rl-root 253:0    0 60.8G  0 lvm  /
  ├─rl-swap 253:1    0  7.9G  0 lvm  [SWAP]
  └─rl-home 253:2    0 29.7G  0 lvm  /home
sdb           8:16   0  100G  0 disk
sdc           8:32   0  100G  0 disk
sdd           8:48   0  100G  0 disk
sde           8:64   0  100G  0 disk
sdf           8:80   0  110G  0 disk
sdg           8:96   0  110G  0 disk
sdh           8:112  0  110G  0 disk
sdi           8:128  0  110G  0 disk

Erzeugt die Volumegroup mit den Namen „vg_striping“

[root@vhr-rocky veeam]# vgcreate vg_striping /dev/sdf /dev/sdg /dev/sdh /dev/sdi
  Physical volume "/dev/sdf" successfully created.
  Physical volume "/dev/sdg" successfully created.
  Physical volume "/dev/sdh" successfully created.
  Physical volume "/dev/sdi" successfully created.
  Volume group "vg_striping" successfully created

Logical Volume „lv_striping“ anlegen. -i steht hierbei für die Anzahl der Stripes, -I für die Stripe Size.
64k sind der Default für die Stripesize, leider konnte ich hier noch nicht alle Varianten testen, es ist aber sehr wahrscheinlich das größere Stripe Sizes wie 128k oder 256k gut zum Veeam Workload passen.

lvcreate -l 100%FREE  -i 4 -I 64k  -n lv_striping  vg_striping
  Logical volume "lv_striping" created.

lvdisplay zeigt Details zum Logical Volume, die relevanten Teile habe ich hervorgehoben.

root@vhr-rocky veeam]# lvdisplay -m /dev/vg_striping/lv_striping
  --- Logical volume ---
  LV Path                /dev/vg_striping/lv_striping
  LV Name                lv_striping
  VG Name                vg_striping
  LV UUID                yTt0vn-d2W2-e02j-zRTV-XdEM-DKrJ-VRS8LQ
  LV Write Access        read/write
  LV Creation host, time vhr-rocky, 2025-05-27 12:06:26 +0200
  LV Status              available
  # open                 0
  LV Size                439.98 GiB
  Current LE             112636
  Segments               1
  Allocation             inherit
  Read ahead sectors     auto
  - currently set to     1024
  Block device           253:4

  --- Segments ---
  Logical extents 0 to 112635:
    Type                striped
    Stripes             4
    Stripe size         64.00 KiB
    Stripe 0:
      Physical volume   /dev/sdf
      Physical extents  0 to 28158
    Stripe 1:
      Physical volume   /dev/sdg
      Physical extents  0 to 28158
    Stripe 2:
      Physical volume   /dev/sdh
      Physical extents  0 to 28158
    Stripe 3:
      Physical volume   /dev/sdi
      Physical extents  0 to 28158

Anschließend noch das Filesystem anlegen, mounten und die Filesystem rechte vergeben.

mkfs.xfs -b size=4096 -m reflink=1,crc=1 /dev/vg_striping/lv_striping 

mkdir /mnt/striping
mount /dev/vg_striping/lv_striping /mnt/striping/

sudo chown -R veeam:veeam /mnt/striping
sudo chmod 700 /mnt/striping

Benchmarks

Wie üblich in einer Lab Umgebung erfolgt dieser Test virtuell, das hat aber den Vorteil das ich mittels QoS ganz geschickt Performance Limitierungen setzen kann.

Test Setup:
– Rocky Linux 9.5 / minimal Installation als VMware VM
– 9 VMDKs (1x OS / 4x LVM Linear / 4x LVM Striping)
– NetApp NFS Storage als Datastore
– Integration in Veeam als Hardened Repository


Die 8 VMDKs für die LVMs sind mittels NetApp QoS auf 50MB/s beschränkt, um den Effekt der Parallelität optimal zeigen zu können. Wichtig bei QoS auf VMDKs, das Ziel muss die „*-flat.vmdk“ Datei sein und nicht nur die Descriptor Datei.

cl2::*> qos policy-group create -policy-group 50mb_max -vserver DEMO5 -is-shared false -max-throughput 50mb/s

cl2::*> volume file modify -vserver DEMO5 -volume vol_DEMO5_SSD_NFS_DS_01 -qos-policy-group 50mb_max -file /vhr-rocky/vhr-rocky_1-flat.vmdk

Die eigentlichen Tests erfolgen mittels FIO. Auch wenn es für diesen Test unerheblich ist nutze ich die Pattern welche Veeam für die Simulation von Backup Disk I/O empfiehlt, diese sind im KB2014 beschrieben.

LVM Linear
Erwarungsgemäß erreicht man hier maximal 50mb/s, was der maximalen Geschwindigkeit einer VMDK entspricht.

[root@vhr-rocky veeam]# fio --name=full-write-test --filename=/mnt/linear/test_full.dat --size=25G --bs=512k --rw=write --ioengine=libaio --direct=1 --time_based --runtime=60s -numjobs 16
full-write-test: (g=0): rw=write, bs=(R) 512KiB-512KiB, (W) 512KiB-512KiB, (T) 512KiB-512KiB, ioengine=libaio, iodepth=1
...
fio-3.35
Starting 16 processes
Jobs: 16 (f=16): [W(16)][61.7%][w=50.0MiB/s][w=100 IOPS][eta 00m:23s]

Mittels dem Tool iostat lässt sich der Effekt sehr gut verdeutlichen da man hier die Performance der zugrunde liegenden Disks sieht. Output für bessere Lesbarkeit etwas gekürzt.

[root@vhr-rocky veeam]# iostat -xdmt 2
Device            r/s     rMB/s   rrqm/s  %rrqm r_await rareq-sz     w/s     wMB/s   wrqm/s   %util
dm-0             0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00    0.00
dm-1             0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00    0.00
dm-2             0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00    0.00
dm-3             0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00    0.00
dm-4             0.00      0.00     0.00   0.00    0.00     0.00  100.00     50.00     0.00  100.00
sda              0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00    0.00
sdb              0.00      0.00     0.00   0.00    0.00     0.00  100.00     50.00     0.00  100.00
sdc              0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00    0.00
sdd              0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00    0.00
sde              0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00    0.00
sdf              0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00    0.00
sdg              0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00    0.00
sdh              0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00    0.00
sdi              0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00    0.00

Auch innerhalb von Veeam lässt sich genau dieser Effekt zeigen. An dieser Stelle sei erwähnt, dass der „Speed“ immer der maximale Speed ist, der während eines Jobs erreicht wurde. Die grüne Linie ist lesend, also vom Quellsystem, die rote Linie ist der Schreibvorgang ins Repository, in unserem Fall also das LVM.

LVM Striping
Im Gegensatz dazu erreicht man mit Striping den gewünschten Effekt, da alle 4 VMDKs parallel genutzt werden.

[root@vhr-rocky veeam]# fio --name=full-write-test --filename=/mnt/striping/test_full.dat --size=25G --bs=512k --rw=write --ioengine=libaio --direct=1 --time_based --runtime=60s -numjobs 16
full-write-test: (g=0): rw=write, bs=(R) 512KiB-512KiB, (W) 512KiB-512KiB, (T) 512KiB-512KiB, ioengine=libaio, iodepth=1
...
fio-3.35
Starting 16 processes
Jobs: 16 (f=16): [W(16)][13.3%][w=200MiB/s][w=399 IOPS][eta 00m:52s]
[root@vhr-rocky veeam]# iostat -xdmt 2
05/27/2025 02:28:11 PM
Device            r/s     rMB/s   rrqm/s  %rrqm r_await rareq-sz     w/s     wMB/s   wrqm/s  %util
dm-0             0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00
dm-1             0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00
dm-2             0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00
dm-3             0.00      0.00     0.00   0.00    0.00     0.00 3198.00    199.88     0.00 100.00
dm-4             0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00
sda              0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00
sdb              0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00
sdc              0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00
sdd              0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00
sde              0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00
sdf              0.00      0.00     0.00   0.00    0.00     0.00  400.00     50.00   400.00 100.00
sdg              0.00      0.00     0.00   0.00    0.00     0.00  400.00     50.00   400.00 100.00
sdh              0.00      0.00     0.00   0.00    0.00     0.00  399.50     49.94   400.00 100.00
sdi              0.00      0.00     0.00   0.00    0.00     0.00  399.50     49.94   400.00 100.00


Abschließend sei erwähnt, dass sich der identische Ansatz natürlich auch auf Server mit vielen internen Disks und damit mehreren RAIDs anwenden lässt. Wie jede zusätzliche Virtualisierungsschicht fügt natürlich auch LVM mehr Komplexität hinzu, welche Auswirkungen das auf mögliche Erweiterungs- oder Ausfallszenarien hat werde ich in einem kommenden Artikel beleuchten.

Von Matthias Beller

Senior System Engineer und Produktspezialist für Veeam bei der Advanced UniByte GmbH in Metzingen. Mein Schwerpunkt liegt auf Netapp-Storage-Lösungen sowie Backup- und Recovery-Konzepten. Teilnehmer der #BeatTheGostev Challenge 2021. VMCE, VMCA, Netapp NCSE, NCIE-DP, NCIE-SAN. Seit 2023 Mitglied des Veeam Vanguard Programms.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert