[How-To] Storage Performance Test mit VDBench
In meinem Blog Beitrag zu Storage Performance Test mit IOmeter habe ich aufgezeigt, wie man auf eine einfache Art und Weise die Storage Performance analysieren kann. IOmeter bietet mit seinem GUI einen einfachen und schnellen Weg einen basic Performance Test durchzuführen. Jedoch ist IOmeter nicht für jede Performance Messung das ideal Tool. Da der generierte Workload nicht den Möglichkeiten von modernen Storage Systemen Rechnung trägt. Denn IOmeter bietet die Wahl zwischen sich wiederholenden Bytes, die zu 100% dedupliziert werden, und Pseudozufallsdaten, die weder dedupliziert noch komprimiert werden. Beides ist für den Test eines modernen Speichersystems nicht geeignet.
Hier ist VDbench die bessere Wahl. VDbench ist ein CLI basiertes Performance Analyse und Lastgenerator Tool, welches enorm viele Konfigurationsdetails erlaubt. VDbench erlaubt das generieren von Storage Last von einem oder mehreren Servern. So ist es möglich die Steuerung von Parametern wie read und write, random und sequentiell, I/O Grösse der Datenübertragung und vielem mehr vorzunehmen.
Um die maximale Leistung eines Storage Systems zu erreichen, reicht es nicht aus, einen Performance Test von nur einem Host oder virtuellen Server aus durchzuführen. Um die maximale Leistung zu erhalten, müssen wir eine Arbeitslast von mehreren Hosts auf mehrere Volumes ausführen. Da die meisten Umgebungen virtualisiert sind, wird sich dieser Blog auf eine VMware vSphere-Plattform konzentrieren, aber die Prinzipien sind für andere Plattformen die gleichen.
Bei der Durchführung von Leistungsbenchmarks ist die Anzahl der Hosts und HBAs (FC oder iSCSI) entscheidend, um die besten Ergebnisse zu erzielen. Normalerweise sind 4-8 Hosts mit dualen HBAs, die alle Storage-Host-Ports nutzen, ausreichend. Es kann jedoch bestimmte Konfigurationen und Benchmarks geben, die mehr Hosts erfordern, insbesondere ein 100%iger sequentieller Lese-Benchmark könnte mehr Hosts erfordern, da der Host PCI-Engpass den Durchsatz für jeden Server begrenzt.
Diese 4 – 8 VMs sollten auch mehrer VMDKs (ca. ja 2-4 Stück, 8-16 Total a mindestens 500GB) verwenden, die sich auf verschiedenen Datastores befinden. Jede VM sollte auf einem eigenen ESXi Server laufen. Dadurch wird sichergestellt, dass du das Maximum an verfügbaren Ressourcen von ESXi-Hosts und IO-Queue von den Datastores nutzen kannst.
Vdbench ist ein CLI basiertes Tool, welches von StorageTek entwickelt, von Sun übernommen wurde und derzeit von Oracle betreut wird. Die Idee ist, Engineers bei der Erzeugung von Disk- und Tape I/O-Workloads zu unterstützen, um die Storageleistung und Datenintegrität zu überprüfen. Es kann auf UNIX, Windows, Linux und OS/X ausgeführt werden. Für den Download von VDbench wird ein freier Account bei Oracle benötigt.
Da VDbench in Java geschrieben wurde, muss eine Java Run Time Environment auf den Servern installiert sein. Eine frei verfügbare Version einer Jave JRE kann hier bezogen werden.
Vor dem Start eines Performance Tests, muss das Storage Array mit Daten befüllt werden. Dieser Task nennt man Prefilling.
Prefilling des Storage Array
Beim Benchmarking aller Flash-Speicher-Arrays wird das Array in der Regel zunächst mit Daten gefüllt. Der Fill-Workload ist ein Spezialfall, der dazu dient, ein Array vor Beginn desTests mit Daten zu füllen. Der Workload führt 100 % sequenzielle I/O mit einer Blockgröße von 256k durch, bis alle Volumes einmal beschrieben wurden oder bis die verstrichene Parameterzeit erreicht ist. Wenn das Ziel darin besteht, 100 % aller Datenträger zu beschreiben, muss ein Wert für den Parameter “elapsed time” gewählt werden, der die Schreibrate der Umgebung und den kombinierten Speicherplatz aller Datenträger berücksichtigt. Wird ein zu kleiner Wert für die elapsed time gewählt, bricht der Test ab, bevor alle Datenträger vollständig beschrieben werden können. Wird ein zu grosser Wert für die verstrichene Zeit gewählt, können alle Datenträger vollständig geschrieben werden und der Test wird vor Erreichen der verstrichenen Zeit beendet. Es wird empfohlen, einen sehr grossen Wert für die verstrichene Zeit zu wählen, wenn du den Fill-Workload verwendest.
Die Workloads “Fill” und “Sample” können nicht mit anderen Workloads kombiniert werden, da sonst die Ergebnisse im Bericht nicht korrekt dargestellt werden. Wenn es erforderlich ist, eine Reihe von Systemlasten ohne Unterbrechung laufen zu lassen, kann Fill mit anderen Systemlasten gemischt werden, aber die Laufzeitoption m (mixed workloads) muss angegeben werden. Wenn du den Fill-Workload in Kombination mit anderen Workloads im selben Test angibst, werden die richtigen Workloads gegen den zu testenden Storage ausgeführt, aber der resultierende Bericht stellt die Daten möglicherweise nicht genau dar und der Berichtsschritt kann sogar fehlschlagen.
Der Grund, warum der Fill-Workload nicht mit anderen Workloads gemischt werden darf, liegt in der Art des Workloads. Der Fill-Workload ist dazu gedacht, LUNs in Vorbereitung auf einen Benchmark-Workload aufzufüllen. Der Füll-Workload wird nicht mit unterschiedlichen Intensitäten ausgeführt, um die Workload-Eigenschaften zu erforschen, wie es bei anderen Workloads gewünscht wird. Alle anderen Workloads werden so ausgeführt, dass eine Sättigungskurve entsteht. Das Mischen dieser Workloads im selben Bericht wird derzeit nicht unterstützt.
Das folgende Vdbench-Skript (workload file) zeigt die zum Vorfüllen des Arrays erforderliche Syntax:
hd=default,shell=vdbench,user=administrator
hd=one
sd=sd_01,lun=\\.\PHYSICALDRIVE1,size=600G,host=one,threads=16
sd=sd_02,lun=\\.\PHYSICALDRIVE2,size=600G,host=one,threads=16
sd=sd_03,lun=\\.\PHYSICALDRIVE3,size=600G,host=one,threads=16
sd=sd_04,lun=\\.\PHYSICALDRIVE4,size=600G,host=one,threads=16
*This is our workload definition. Here we use seekpct=eof to tell vdbench to:
*write random data until it completely writes to the entire lun , rdcpct=0 sets the
*workload to 100% write and xfersize determines the block size. In this case we
*set the block size to 256k
wd=wd1,sd=*,hd=*,seekpct=eof,rdpct=0,xfersize=256k
*This is our run definition. It tells vdbench to run the workload definition
* defined in wd1 above at the maximum iorate it can sustain. The elapsed time *does not matter here. The scripte will stop when eof is reached as per the *workload definition.
rd=rd1,wd=wd1,elapsed=144000,interval=1,iorate=max,openflags=directio
Deduplication and Compression
Die Leistungsergebnisse einiger Tests hängen von dem Datenmuster ab, das in den Storage geschrieben wird. Data compaction wie Deduplizierung und Komprimierung führen zu unterschiedlichen Ergebnissen und unterschiedlichen Leistungsniveaus, wenn sich das an den Storage gesendete Datenpatern ändert.
Ein Storage Array, das Deduplizierung unterstützt, muss zum Beispiel jeden Block auf das Speichermedium schreiben, wenn jeder Block eindeutig ist. Wenn ein solches eindeutiges Datenpattern an ein Storage-Array gesendet wird, das Deduplizierung implementiert, verschlechtert der Overhead der Deduplizierung die Leistung (Kosten der Deduplizierung), aber da die Daten alle eindeutig sind, ergibt sich kein Vorteil. Für einen validen Test der Deduplizierungsfunktion eines Storage Arrays ist es wichtig, ein Datenpattern zu senden, das ein gewisses Mass an Redundanz aufweist.
Vdbench unterstützt sowohl Deduplizierung als auch Komprimierung unter Verwendung der folgenden Parameter im Vdbench-Skript:
dedupratio=1.5
compratio=3.0
dedupunit=16k
Obwohl verschiedene Werte für die beiden Parameter dedupratio und compratio verwendet werden können, führt ein dedupratio von 1,5 und ein compratio von 3,0 zu performance benchmark Werten, die den in HPE NinjaSTARS angezeigten Werten am nächsten kommen.
Wenn die Parameter deduplication= oder compression= nicht in der Konfigurationsdatei enthalten sind, wird das für den Test erzeugte Datenpattern alle eindeutigen Daten enthalten, die nicht komprimiert werden können. Standardmässig schreibt Vdbench ein nicht komprimierbares, nicht deduplizierbares random data pattern.
Wie konfiguriere ich die VDbench Konfig Datei?
Storage definitions:
‘sd=’ identifiziert jede Storagedefinition eindeutig. Der SD-Name wird von den Parametern Workload Definition (WD) und Run Definition (RD) verwendet, um zu ermitteln, welche SDs für ihre Workload verwendet werden sollen. Wenn du”default” als SD-Name angibst, werden die eingegebenen Werte als Standard für alle SD-Parameter wie folgt verwendet.
‘lun=’ beschreibt den Namen der RAW disk oder den Dateinamen des zu verwendenden File Systems. Achte darauf, dass du keine Festplatte anbibst, werlche Daten enthält, die dunicht verlieren willst.
‘host=name’ dieser Parameter wird nur benötigt, wenn du einen Multihost Test durchführen möchtest, bei dem die Lun-Namen auf jedem Host unterschiedlich sind. Wenn zum Beispiel eine Lun auf HostA =\\.\PHYSICALDRIVE5 heisst, auf HostB aber =\\.\PHYSICALDRIVE7. Dann musst du Vdbench entsprechend konfigurieren.
‘size=’ beschreibt die Größe der RAW Disk oder Datei. Du kannst dies in Bytes, Kilobytes, Megabytes, Gigabytes oder Terabytes (k/m/g/t) angeben. Wird keine Angabe gemacht, wird die Grösse der RAW Disk oder der Datei entnommen. Vdbench unterstützt Adressen grösser als 2 GB.
‘threads=nn’ gibt die maximale Anzahl der gleichzeitigen I/O an, die für diese SD ausstehen können. Beachte, dass je nach Storage System einige dieser I/Os innerhalb des Betriebssystems in eine Queue gestellt werden können. Sei etwas konservativ mit diesem Wert. Denn wen zu viele outstanding I/Os anstehen, wird die Latenz wieder zunehmen.
Die folgende Tabelle zeigt die Queue Depth der jeweiligen physischen Adapter.
Type | Default Value | Value Name |
QLogic | 64 | qlfxmaxqdepth |
Brocade | 32 | bfa_lun_queue_depth |
Emulex | 32 | lpfc0_lun_queue_depth |
Software iSCSI | 128 | iscsivmk_LunQDepth |
Um die Paramter für sd auszufüllen können mit dem Befehl “vdbench sds” die vorhandenen Disks angezeigt werden.
Workload definitions
Die Workload-Definition ist eine einzelne Zeile, die mit ‘wd=’ beginnt. Du kannst grundsätzlich mehrere Workloads in der Vdbench-Datei definieren, Normalerweise wird jedoch nur ein Workload in der Run Definition (‘rd=’) ausgewählt.
Einige Beispiele für Workloads:
*prefill — 256k seq
wd=wd1,host=*,sd=*,rdpct=0,xf=256k,seekpct=eof
*8k 100Read 100Random – Small Random Reads
wd=wd2,host=*,sd=*,rdpct=100,xf=8k,seekpct=100
*8k 100Write 100Random – Small Random Writes
wd=wd3,host=*,sd=*,rdpct=0,xf=8k,seekpct=100
*16k 60Read 40Write 100Random – Small Mix-Read-Write Random
wd=wd4,host=*,sd=*,rdpct=60,xf=16k,seekpct=100
*256k 100Read 100Seq – Large Sequential Read
wd=wd5,host=*,sd=*,rdpct=100,xf=256k,seekpct=0
*256k 100Write 100Seq – Large Sequential Write
wd=wd6,host=*,sd=*,rdpct=0,xf=256k,seekpct=0
*32k 100Read 100Random – Avg Random Reads
wd=wd7,host=*,sd=*,rdpct=100,xf=32k,seekpct=100
*64K 70Read 30Write 100Random – Avg Mixed-Read-Write Random
wd=wd8,host=*,sd=*,rdpct=100,xf=80k,seekpct=100
*4k-50% 32k-50% 60Read 40Write 100Random – Mixed BlockSize Random
wd=wd9,host=*,sd=*,rdpct=60,xf=(4k,50,32k,50),seekpct=100
Run Definition
Die Run Definition geben an, welche der zuvor definierten Workloads ausgeführt werden müssen, welche I/O-Raten generiert werden müssen und wie lange die Workloads ausgeführt werden sollen. Eine Run Definition kann je nach den verwendeten Parametern zu mehreren tatsächlichen Läufen führen.
Example:
rd=run1,wd=(wd1,wd2),warmup=60,forthreads=(32), iorate=1000,elapsed=60,interval=5
rd=name’ definiert einen eindeutigen Namen für diesen Lauf. Run Namen werden in Ausgabeberichten verwendet, um zu erkennen, über welchen Lauf berichtet wird. Wenn du ‘default’ als RD-Name eingibst, werden die eingegebenen Werte als Standard für alle folgenden SD-Parameter verwendet.
wd=’ identifies workloads to run. Specify a single workload as ‘wd=wd1’ or multiple workloads either by entering them individually ‘wd=(wd1,wd2,wd3)’, a range ‘wd=(wd1-wd3)’ or by using a wildcard character: ‘wd=wd*’.
warmup=60 –> Während der Warmup Phase werden die Performancekennzahlen nicht im Report erfasst.
forthreads=(32) –> Dieser Wert übersteuert den thread Paramter der Storage Definition (Optional)
iorate=’ spezifiziert einen oder mehrere I/O rates.
iorate=100 –> Run a workload of 100 IOPS
iorate=(100,200) –> Run a workload of 100 IOPS, than 200 IOPS
‘elapdsed=nn –> Dieser Parameter gibt die verstrichene Zeit in Sekunden für jeden Lauf an. Dieser Wert muss mindestens doppelt so hoch sein wie der Wert des unten angegebenen Berichtsintervalls. Jede angeforderte Arbeitslast läuft für ‘elapsed=’ Sekunden, während detaillierte Leistungsintervallstatistiken alle ‘interval=’ Sekunden gemeldet werden.
Intervall=nn’: Dieser Parameter gibt die Dauer in Sekunden für jedes Meldeintervall an. Am Ende jedes Berichtsintervalls werden alle gesammelten Statistiken gemeldet.
Es gibt noch viele weitere Run Definition-Parameter, weitere Informationen finden Sie im Vdbench-Benutzerhandbuch.
Beispiel eines Workload Parameter file
concatenate=no
dedupratio=1.5
compratio=3.0
dedupunit=16k
hd=default,vdbench=c:\vdbench,user=Administrator,shell=vdbench,jvms=4 hd=one,system=localhost
sd=default,openflags=directio,size=950g
sd=sd1,host=one,Lun=\\.\PHYSICALDRIVE1
sd=sd2,host=one,Lun=\\.\PHYSICALDRIVE2
sd=sd3,host=one,Lun=\\.\PHYSICALDRIVE3
sd=sd4,host=one,Lun=\\.\PHYSICALDRIVE4
sd=sd5,host=one,Lun=\\.\PHYSICALDRIVE5
sd=sd6,host=one,Lun=\\.\PHYSICALDRIVE6
sd=sd7,host=one,Lun=\\.\PHYSICALDRIVE7
sd=sd8,host=one,Lun=\\.\PHYSICALDRIVE8
*prefill — 256kseq
wd=wd1,host=*,sd=*,rdpct=0,xf=256k,seekpct=eof
*8k 100Read 100Random – Small Random Reads
wd=wd2,host=*,sd=*,rdpct=100,xf=8k,seekpct=100
*8k 100Write 100Random – Small Random Writes
wd=wd3,host=*,sd=*,rdpct=0,xf=8k,seekpct=100
*16k 60Read 40Write 100Random – Small Mix-Read-Write Random
wd=wd4,host=*,sd=*,rdpct=60,xf=16k,seekpct=100
*256k 100Read 100Seq – Large Sequential Read
wd=wd5,host=*,sd=*,rdpct=100,xf=256k,seekpct=0
*256k 100Write 100Seq – Large Sequential Write
wd=wd6,host=*,sd=*,rdpct=0,xf=256k,seekpct=0
*32k 100Read 100Random – Avg Random Reads
wd=wd7,host=*,sd=*,rdpct=100,xf=32k,seekpct=100
*64K 70Read 30Write 100Random – Avg Mixed-Read-Write Random
wd=wd8,host=*,sd=*,rdpct=100,xf=80k,seekpct=100
*8k 100Read 100Random
wd=wd9,host=*,sd=*,rdpct=100,xf=4k,seekpct=100
*8k 100Write 100Random
wd=wd10,host=*,sd=*,rdpct=0,xf=4k,seekpct=100
rd=rd1,wd=wd2,el=900,in=1,warmup=300,forthreads=(32),iorate=max
In dieser Beispieldatei wurden 8 LUNs, ein Host (localhost), mehrere Workloads Definitionen und eine Laufdefinition. Dies führt den Workload ‘wd2’ aus. (8k 100Read 100Random – Small Random Reads) mit einer Aufwärmphase von 300 Sekunden (so dass die ersten 5 Minuten der gesammelten Leistungsdaten ausgeschlossen werden) und läuft bei maximaler IO-Rate für 900 Sekunden mit 32 Threads für jede LUN.
Beispiel eines Mixed Workload Parameter file
concatenate=no
dedupratio=1.5
compratio=3.0
dedupunit=16k
hd=default,vdbench=c:\vdbench50407,user=Administrator,shell=vdbench,jvms=4
hd=one,system=localhost
sd=default,openflags=directio,size=950g
sd=sd1,host= one,Lun=\\.\PHYSICALDRIVE1
sd=sd2,host= one,Lun=\\.\PHYSICALDRIVE2
sd=sd3,host= one,Lun=\\.\PHYSICALDRIVE3
sd=sd4,host= one,Lun=\\.\PHYSICALDRIVE4
sd=sd5,host= one,Lun=\\.\PHYSICALDRIVE5
sd=sd6,host= one,Lun=\\.\PHYSICALDRIVE6
sd=sd7,host= one,Lun=\\.\PHYSICALDRIVE7
sd=sd8,host= one,Lun=\\.\PHYSICALDRIVE8
*prefill — 256kseq
wd=wd1,host=*,sd=*,rdpct=0,xf=256k,seekpct=eof
*8k-50% 32k-50% 60Read 40Write 100Random – Mixed BlockSize Random
wd=wd9,host=*,sd=*,rdpct=60,xf=(8k,50,32k,50),seekpct=100
*8k 60Read 40Write 100Random 128K 50Read 50Write 100Seq **wd10 and wd11 will complete this
wd=wd10,host=*,sd=*,rdpct=60,xf=8k,seekpct=100
wd=wd11,host=*,sd=*,rdpct=50,xf=128k,seekpct=0
*When running wd10 & wd11 loop as *wd=(wd10,wd11) at bottow in rd= section
*4k-20% 8k-20% 16k-20% 64k-20% 128k-10% 256k-10% 65Read 35Write 70Random
wd=wd16,host=*,sd=*,rdpct=65,xf=(4k,20,8k,20,16k,20,64k,20,128k,10,256k,10),seekpct=70
rd=rd1,wd=wd9,el=900,in=1,warmup=300,forthreads=(32),iorate=max
Dies führt eine Arbeitslast ‘wd9’ (8k-50% 32k-50% 60Read 40Write 100Random – Mixed Block Size Random) mit einer Aufwärmphase von 300
Sekunden (die ersten 5 Minuten der gesammelten Leistungsdaten werden also ausgeschlossen) und läuft bei maximaler IO-Rate für 900 Sekunden mit 32 Threads für jede LUN.
VDbench mit dem erstellten Parameter File starten
Mit dem folgenden Befehl wird vdbench mit dem erstellten Paramter File gestartet.
vdbench.bat -f parameter.file
VDbench von mehreren Servern (Multi-Host)
Um VDbench gleichzeitig aber zentral gesteuert von einem Master Host laufen zu lassen, kann das Paramter File mit folgenden Parmetern erweitert und die Storage Definition sd muss entsprechend angepasst werden.
hd=host1,system=localhost
hd=host2,system=192.168.1.2
hd=host3,system=192.168.1.3
hd=host4,system=192.168.1.4
sd=sd1,host=host1,Lun=\\.\PHYSICALDRIVE1
sd=sd2,host=host2,Lun=\\.\PHYSICALDRIVE1
sd=sd3,host=host3,Lun=\\.\PHYSICALDRIVE1
sd=sd4,host=host4,Lun=\\.\PHYSICALDRIVE1
Auf den Remote Hosts muss mit folgendem Befehl der VDbench Remote Deamon gestartet werden, damit der Master Host eine Verbingung herstellen kann.
vdbench rsh
VDbench Array PreFill mit Multi-Host
Um den PreFill in einer Multi-Host Testumgebung durchzuführen, muss das Paramter File folgendermassen erstellt werden:
hd=default,shell=vdbench,user=administrator
hd=host1,system=localhost
hd=host2,system=192.168.1.2
hd=host3,system=192.168.1.3
hd=host4,system=192.168.1.4
sd=sd_11,host=host1,lun=\\.\PHYSICALDRIVE1,size=600G,threads=16
sd=sd_12,host=host1,lun=\\.\PHYSICALDRIVE2,size=600G,threads=16
sd=sd_13,host=host1,lun=\\.\PHYSICALDRIVE3,size=600G,threads=16
sd=sd_14,host=host1,lun=\\.\PHYSICALDRIVE4,size=600G,threads=16
sd=sd_21,host=host2,lun=\\.\PHYSICALDRIVE1,size=600G,threads=16
sd=sd_22,host=host2,lun=\\.\PHYSICALDRIVE2,size=600G,threads=16
sd=sd_23,host=host2,lun=\\.\PHYSICALDRIVE3,size=600G,threads=16
sd=sd_24,host=host2,lun=\\.\PHYSICALDRIVE4,size=600G,threads=16
sd=sd_31,host=host3,lun=\\.\PHYSICALDRIVE1,size=600G,threads=16
sd=sd_32,host=host3,lun=\\.\PHYSICALDRIVE2,size=600G,threads=16
sd=sd_33,host=host3,lun=\\.\PHYSICALDRIVE3,size=600G,threads=16
sd=sd_34,host=host3,lun=\\.\PHYSICALDRIVE4,size=600G,threads=16
sd=sd_41,host=host4,lun=\\.\PHYSICALDRIVE1,size=600G,threads=16
sd=sd_42,host=host4,lun=\\.\PHYSICALDRIVE2,size=600G,threads=16
sd=sd_43,host=host4,lun=\\.\PHYSICALDRIVE3,size=600G,threads=16
sd=sd_44,host=host4,lun=\\.\PHYSICALDRIVE4,size=600G,threads=16
*This is our workload definition. Here we use seekpct=eof to tell vdbench to:
*write random data until it completely writes to the entire lun , rdcpct=0 sets the
*workload to 100% write and xfersize determines the block size. In this case we
*set the block size to 256k
wd=wd1,host=*,sd=sd_*,seekpct=eof,rdpct=0,xfersize=256k
*This is our run definition. It tells vdbench to run the workload definition
* defined in wd1 above at the maximum iorate it can sustain. The elapsed time *does not matter here. The scripte will stop when eof is reached as per the *workload definition.
rd=rd1,wd=wd*,elapsed=144000,interval=1,iorate=max,openflags=directio
Nächster Schritt
Möchtest du mehr über Messungen und Analysen von Storage Systemen erfahren? Wir verfügen über langjährige Erfahrung aus unzähligen Storage-Projekten und Supportfällen und können sicher auch dich unterstützen.
Leave a Reply