Parallelisierung des Backups

In mehreren GWDG-Nachrichtenartikeln und den MPG-DV-Treffen 2016 wurde bereits über das Kernproblem eines jeden Backups berichtet:

Das Identifizieren der geänderten Dateien dauert zu lange!

Nachfolgend eine Anayse des Problems und mehrere Lösungsansätze:

Backup großer Datenbereiche mit TSM

Nachdem das Thema "Looking for suggestions to deal with large backups not completing in 24-hours" (zu Deutsch also „Das Backup läuft in 24 Stunden nicht durch“ – oder ein Synonym für das Backup großer Datenbereiche) im Juli 2018 auf der TSM-Mailing-Liste „ADSM-L“ diskutiert wurde, haben wir uns entschlossen, den Text aus den GWDG-Nachrichten 10/2016 zu aktualisieren und vor allem auch englischsprachig (FIXME Link auf die GWDG-Nachrichten folgt!) für die internationalen Interessenten zu veröffentlichen. Das bereits vor zwei Jahren angesprochene permanente Wachstum von Daten stellt die Filesystem-Admins weiterhin vor die große bzw. größere Herausforderung, das Backup der Daten innerhalb des vorgegebenen Zeitfensters zu bewältigen und so die zugesagte Absicherung gegen Manipulation und Datenverlust einzuhalten. Der nachfolgende Artikel beleuchtet anhand der Backup-Lösung „IBM Spectrum Protect (ISP)“ (ehemals „Tivoli Storage Manager „TSM“) verschiedene Möglichkeiten und Ansätze. Es werden diese sowohl kurz erläutert wie die Grenzen und Beschränkungen aufgezeigt. Der zweite Teil des Artikels entwickelt auf Basis der Grundidee „Parallelisierung mittels mehrerer Backup-Threads“ verschiedene Varianten, das Backup zu beschleunigen.

Ausgangslage

Die Datenmengen wachsen, durchschnittlich um 20% pro Jahr (1,2). Neben den Herausforderungen, diese Daten sinnvoll und performant zu speichern, fällt häufig ein Aspekt aus dem Fokus:

Wie werden diese wachsenden Datenmengen gesichert?

Nominell wächst die Leistung der Tape-Systeme schneller als das Datenvolumen (1,2), aber auch diese Sicht ist leider unvollständig, da der Prozess des Sicherns, das eigentliche Backup, häufig den Flaschenhals darstellt.

„IBM Spectrum Protect (ISP)“ (bzw. zuvor schon als „WDSF/VM“,“DFDSM“, „ADSM“ und „Tivoli Storage Manager (TSM)“) verfolgt bereits seit langem den Ansatz, beim Backup nur die Änderungen seit dem letzten Backup zu sichern und dabei auf regelmäßige Vollsicherungen zu verzichten, also einen „incremental forever“-Ansatz.

Der Vorteil liegt auf der Hand:
Gerade bei großen Datenmengen (> 10 TB) ist die täglich geänderte Datenmenge relativ gering, so dass auch bei sehr viele Versionen (bei der GWDG in der Regel bis zu 90) das Volumen der täglichen Sicherungen im Vergleich zur abgesicherten Datenmenge (ich übernehme hier die IBM-Wortwahl „Front End Capacity (FEC)“) eher gering ist . Damit ist auch die benötigte Kapazität für das Vorhalten der Versionen im Vergleich zur FEC nur geringfügig größer. Sichert man hingegen regelmäßig die Daten vollständig, so muss die Backupkapazität das Mehrfache der FEC umfassen. Bei gemischten Ansätzen, z.B. dem „Grandfather-Father-Son (GFS)“-Prinzip mittels

  • monatliche Vollsicherungen (Grandfather)
  • wöchentliche Differenzsicherungen (Father)
  • tägliche Sicherungen (Son)

erhöht sich die notwendige Backupkapazität gegenüber dem „incremental forever“.

Aber das „incremental forever“ löst ein wesentliches Problem einer jeden inkrementellen Sicherung nicht: die Antwort auf die Frage, welche Daten überhaupt gesichert werden müssen. ISP/TSM identifiziert diese zu sichernden Daten („Backup-Kandidaten“) dadurch, dass es alle Verzeichnisse und Dateien auf dem zu sichernden Rechner mit denen aus dem letzten Backup vergleicht und sich geänderte Dateien merkt. Dieser Prozess läuft in der Regel mit einer Geschwindigkeit von 1 – 2 Mio. Objekten (Dateien und Ordner) pro Stunde. Damit dauert allein das Durchsuchen eine 100 TB-Filesystems mit rund 100 Mio. Objekten zwischen 50 und 100 Stunden, ein tägliches Backup eines solchen Filesystems ist mit den üblichen Ansätzen nicht möglich. Hinzu kommt das Problem, dass sich innerhalb dieser erheblichen Suchzeit, wohl wieder nennenswerte viele Daten neu ändern oder sogar gelöscht werden. Als Ergebnis wirft ISP/TSM reichlich Fehlermeldungen (ANS4037E Object '<NAME>' changed during processing. Object skipped oder ANS4005E Error processing '<NAME>': file not found).

Was kann man also tun?

Lösungen, die keine sind

Eine Variante ist wohl die „Vogel-Strauß-Methode“: Man passt die Dienstbeschreibung der Fileserver an und sichert dem Nutzer keine täglichen Backups, sondern nur (zunächst) alle zwei Tage zu. Im Rahmen des Datenwachstums wird die Backup-Häufigkeit fortlaufend angepasst. Bei spätestens 150 Mio. Objekten dürfte es nur noch eine monatliche Sicherung sein :-(

An diesem Punkt sollte über die zweite „Null-Lösung“ nachgedacht werden:
Das Backup entsprechender Filesysteme komplett aufzugeben und die Nutzer nicht in einer (Daten-) Sicherheit zu wiegen, die es nicht (mehr) gibt.

Da das Suchen der „Backup-Kandidaten“ also das Problem des Backups ist, könnte man also überlegen, in den sauren Apfel zu beißen und doch nur Vollsicherungen zu machen, im Vergleich zu DISK-Storage sind Tapes ja auch relativ günstig. Leider ist dies nach unseren Erfahrungen auch definitiv keine Lösung:
Für eine Vollsicherung von 100 TB benötigt man bei einer 10GE-Anbindung zwar theoretisch nur knapp 24 Stunden. Praktisch wirken aber wahrscheinlich einige Hemmnisse, so dass man effektiv nur etwa 2 – 4 TB pro Tag sichert und für jede Vollsicherung rund 25 – 50 Tage benötigt – also in etwa die gleiche Zeit wie beim „incremental“.

Beschleunigung mit ISP-Bordmitteln

IBM bietet für die Beschleunigung des Backups einige Bordmittel an:

Vereinfachte Identifikation ausschließlich über das Änderungsdatum

Üblicherweise vergleicht der ISP-Client zahlreiche Meta-Daten um Objekte für das erneute Backup auszuwählen. Neben dem Datum der letzten Änderung sind dies auch Dateigröße, Prüfsumme, Zugriffsrechte / ACLn. Im interaktiven Aufruf dsmc i und/oder als Object im Client-Schedule kann durch die Option -INCRbydate die Prüfung auf den Vergleich des Änderungsdatums des Objektes mit dem Datum des letzten Backups reduziert und somit erheblich beschleunigt werden. Allerdings birgt die Option auch einige Probleme: Insbesondere wenn keine Snapshots genutzt werden oder falls der Backup abbricht, fallen Dateien, die während des Backups in bereits abgearbeiteten Ordner geändert oder erstellt werden, beim nächsten Lauf mit -incrbydate heraus, wenn sie nicht nochmal verändert wurden. IBM empfiehlt daher ausdrücklich, regelmäßig ein normales „incremental“ auszuführen 4. Ähnliche Probleme können auftreten, wenn Client und Server unterschiedliche Systemzeiten haben.
Ein weiterer wichtiger Punkt: Gelöschte Dateien werden nicht erkannt, verbleiben im Backup und Dateien, die mit einem alten Datum ins System kommen, z.B. durch die Installation von Software, werden nicht gesichert!

Zusammenfassend lässt sich feststellen, dass die -INCRbydate-Option nur für die täglichen Sicherungen zusammen mit einer „normalen“ Sicherung am Wochenende eingesetzt werden kann, wenn das normale Backup geringfügig länger als 24 Stunden dauert.

Ausschalten von ACLn und Prüfsummen

Die Verarbeitung (und damit zuvor die Prüfung) von ACLn und das Erstellen von Prüfsummen verlangsamt den Identifikationsprozess und kann über mehrere Optionen beeinflusst werden. Es sollte aber gut abgewogen werden, ob der relativ geringe Geschwindigkeitsgewinn gegenüber dem Verlust an Informationen ausreichend überwiegt.

  • skipacl unterbindet die ACL-Verabeitung vollständig, wahrscheinlich werden die ACLn aber auch nicht gesichert (Option nur für Unixe + MacOS)
  • skipaclupdatecheck schaltet auch die Checksummenermittlung ab (Option für Unixe + MacOS und Windows)
  • skipntsecuritycrc unterbindet die Berechnung einer CRC-Prüfsumme (Option nur für Windows)

Parallelisierung von Backups bei mehreren Filespaces

Liegen die zu sichernden Daten auf mehreren Partitionen lässt sich der Backupprozess über die Option RESSOURCEUTILIZATION auf parallele Streams verteilen (entgegen der IBM-Dokumentation sind deutlich mehr als 10 mögliche, aus der Praxis wird von > 100 Streams berichtet) und damit sowohl die Bandbreite besser ausnutzen als auch durch die Parallelisierung die Suchzeit erheblich verringern. Da durch diese Parallelisierung auch zusätzliche Sessions auf Seiten des ISP-Servers erzeugt werden, muss gegebenenfalls die Anzahl der MAXSESSIONS erhöht werden.
Dieser Ansatz funktioniert nur wenn tatsächlich mehrere Filespaces gesichert werden sollen. Als Workaround kann ein einzelner Filespace natürlich mit der VIRTUALMOUNTpoint-Option in scheinbar mehrere Filespaces aufgeteilt werden, dann funktioniert dieser Ansatz natürlich auch.
(Siehe auch Exkurs zu „Workaround für VIRTUALMOUNTPOINTS bei Windows-Clients“)

Explizites Backup nur der geänderten Dateien

Sofern Informationen vorliegen, welche Dateien sich seit dem letzten Backup ändert haben und welche Datei seitdem gelöscht wurden, kann ISP/TSM auch ausschließlich eine Sicherung dieser Dateien vornehmen. Statt einem „incremental Backup“ ist dann ein selective Backup mit der expliziten Angabe dieser Dateien möglich:

  • dsmc sel –filelist=<DATEI mit Namen geänderter Dateien>
    bzw.
  • dsmc expire –filelist=<DATEI mit Namen gelöschter Dateien>

Das Grundprinzip des „selective backup“ wird auch im nachfolgenden Ansatz und bei den „Filesystemen, die ein schnelles Backup unterstützen“ genutzt, erfordert aber zwei explizite Listen von Dateien, die geändert oder gelöscht wurden.

JournalBasedBackup / FilepathDemon

Bereits seit TSM 5 bietet IBM die Methode des „JournalBasedBackup (JBB)“ an.
Hierbei wird über den „JBB-Demon“ (bzw. „FilepathDemon“) das zu sichernde Filesystem überwacht und Informationen zu neuen, geänderten und gelöschten Dateien gesammelt. Beim Backup werden diese Informationen vom TSM/ISP-Client analog dem „selective backup“ genutzt. Der Aufwand für die Identifikation der Backup-Kandidaten entfällt und das Backup reduziert sich auf die Übertragung der neuen / geänderten Daten.
Tests an der GWDG mit einem Linux-Filerserver mit ~ 150 TB Kapazität verteilt über 22 Filespaces waren aber nicht erfolgreich: Der Ressourcenbedarf für den JBB war zwar erheblich, der Zeitgewinn, vor allem durch regelmäßige Neuindizierungen doch eher spärlich. :-( In anderen Konstellationen mag der JBB deutliche Vorteile bringen.

Daneben gibt es noch eine wichtige Einschränkung:
Journal Based Backup geht nur mit lokalen Filesystemen. CIFS / NFS und Clusterfilesysteme gehen nicht.

Hinweis:
Optimierungen für die Datenübertragung finden sich im Performance Tuning-Guide (V7.1.6).

Hybrider Ansatz mit Snapshots

Zahlreiche Filesysteme und auch die meisten Filer bietet die Möglichkeit, Snapshots anzulegen. In der Kombination von Snapshots und dem ISP-Backup lässt sich ein hybrider Ansatz umsetzen:

Backups so häufig wie möglich, also beispielsweise wöchentlich, zwischendurch erfolgen Snapshots.
Meist gibt es neben der erheblichen Ausweitung des Backupzeitfensters noch den positiven Nebeneffekt, dass die Endnutzer direkt auf die Snapshots zugreifen können und die Admins von zahlreichen Restore-Anfragen entlastet werden. Stützt man zudem das Backup auf einen Snapshot, löst sich auch das Problem der geöffneten Files (Fehlermeldung ANE4987E Error processing '<NAME>': the object is in use by another process).

Voraussetzung für diesen Ansatz ist natürlich, dass die Filesysteme Snapshots unterstützen – und zwar in ausreichender Menge.

Filesysteme, die ein schnelles Backup unterstützen

Einige Filesysteme / Filer unterstützen ein schnelles Backup mittels ISP indem sie die notwendigen Backup-Kandidaten ermitteln und dem ISP-Client zur Verfügung stellen, beispielsweise:

IBM Spectrum Scale (ISS, ehemals GPFS)

IBMs Clusterfilesystem unterstützt natürlich das Backup mit ISP/TSM und bietet sogar ein eigenes Skript mmbackup an. Dieses nutzt nicht nur die Informationen zu den Backupkandidaten, sondern kann auch die Datenübertragung über mehrere (ISP/TSM-)Knoten und GPFS-Server parallelisieren.
Aber mmbackup läuft nicht einfach „out-of-the-box“: Die anfängliche Erstellung der Konfiguration erfordert zwar ein wenig Ausprobieren, danach läuft mmbackup aber sowohl stabil wie performant.
IBM Spectrum Scale bietet außer zu ISP/TSM auch eine enge Verzahnung mit HPSS als HSM-System, so dass sich das Problem auch durch (teilweise) Verlagerung der Daten ins HPSS verringern lässt – wobei ISP/ISS auch sehr große Datenmengen in vergleichsweise kurzer Zeit sichern kann.

NetApp SnapDiff

Auch NetApp unterstützt das Backup der eigenen NAS-Filer bereits seit TSM 5 in vielfältiger Art und Weise. Neben NDMP gehört über die Funktion SnapDiff auch eine Beschleunigung des inkrementellen Backups dazu. Beim SnapDiff werden die Änderungen an Dateien und Verzeichnisses zwischen zwei Snapshots an den ISP-Clienten übergeben. Die Integration geht soweit, dass der ISP/TSM-Client die benötigten Snapshots sogar auf dem Filer auslösen kann und nach einem erfolgreichen Backup den vorletzten selbstständig löschen kann.

Da die SnapDiff-Funktion nur zwei Snapshots vergleicht, aber in keiner Weise berücksichtigt, ob das letzte Backup erfolgreich war, ergeben sich die gleichen Probleme wie beim Nutzen der INCRbydate-Option: Fehler aus der letzten Sicherung werden nicht kompensiert und ein regelmäßiges „normales“ inkrementelles Backup wird dringend empfohlen. mmbackup berücksichtigt hingegen den Backup-Status aller Daten und ist bezüglich der zuvor genannten Probleme fehlertolerant.

Grundsätzlich sollte jedes Cluster-/ScaleOut-Filesystem eine Liste mit neuen, geänderten und gelöschten Dateien bereitstellten können, da diese (Meta-)Informationen für die Konsistenz der Daten (und ganz besonders der Caches) auf den Clusterknoten notwendig sind. In der Praxis bestehen die Probleme darin, dass diese Informationen nicht einfach zugänglich sind und es seitens der Hersteller keine Werkzeuge zum Zugriff auf diese Daten gibt. Quantum hat den Bedarf auf Kundenseite wahrgenommen und prüft derzeit, wie für das StorNext-Filesystem diese Informationen bereitgestellt werden können. DELL/EMC bietet mit den ISILON-Systemen auch ScaleOut-NAS-Systeme an, in der Version 7 des OneFS genannten Betriebssystems gibt es zwar die Möglichkeit geänderte Dateien protokollieren zu lassen, der Resourcenbedarf ist aber so hoch, dass es eine nachhaltige Beeinträchtigung des Gesamtsystems gibt. Mit OneFS 8 soll es auch hier Verbesserungen geben.

Zwei (einfache) Ideen für alle Filesysteme

Damit stellt sich für alle Nutzer, die kein IBM Spectrum Scale in Betrieb haben (mmbackup ist hierfür die beste Lösung!) und weder Vollsicherungen noch NDMP machen wollen die Frage: Was nun?
Wie zuvor ausgeführt, benötigt das Identifizieren der Backup-Kandidaten beim ISP-Backup die meiste Zeit. Dieser Prozess untersucht den gesamten Dateibaum des zu sichernden Filesystems – sequentiell in einem einzelnen Thread. Die Lösung liegt also darin, aus diesem einen Prozess mehrere parallele zu machen.
Nutzer lassen sich meist in Gruppen einteilen (z.B. Arbeitsgruppen oder Institute), besonders in akademischen Umgebungen findet sich diese Einteilung auch in Filesystemen wieder, da dort zur einfacheren Zugriffssteuerung häufig zunächst eine Ordnerebene mit Fakultäten oder Instituten existiert und unterhalb dieser Ebene liegen die Nutzer- und Arbeitsgruppenverzeichnisse.

Variante 1

Eine Parallelisierung des Backups ist möglich, wenn man statt einem einzigen ISP-Knoten für das gesamte Filesystem jeweils jeder Fakultät bzw. jedem Institut einen eigenen Knoten einrichtet und das Backup „fakultätsweise“ / „institutsweise“ erfolgt. Statt einem einzelnen Prozess durchsuchen nun mehrere parallel das Filesystem (Fileserver sollten in der Lage sein sogar mehrere Hundert parallele Prozesse zu verarbeiten), die Suchzeiten sollten sich erheblich reduzieren. In der Praxis offenbaren sich bei diesem Ansatz mindestens zwei Probleme:

  • Nicht alle Fakultäten / Institute haben gleich viele Daten, meist gibt es ein oder zwei die allein nahezu die gesamte Kapazität des Filesystems nutzen. Daher laufen die Backups der übrigen wesentlich schneller, für die „Großnutzer“ verringert sich die Backupzeit im schlimmsten Falle nur geringfügig. In Summe ist der (Zeit-)Gewinn meist nur marginal.
  • Kommen weitere Fakultäten (wohl nicht so häufig) oder Institute hinzu, muss der Backup-Admin rechtzeitig seine Konfiguration anpassen, sonst bleiben die neuen außen vor.

Unter Unix lassen sich die Knoten relativ elegant über die VIRTUALMOUNT-Option trennen, für Windows muss man entweder für jeden Knoten entsprechenden „exclude.dir“-Regeln erstellen, was sowohl aufwändig wie fehlerträchtig ist oder mit einem Trick arbeiten (siehe Exkurs „Workaround für VIRTUALMOUNTPOINTS bei Windows-Clients“).

Variante 2

Häufig sind die Benutzer auf den Filesystemen aber nicht in Gruppen organisiert, sondern alle Verzeichnisse liegen flach nebeneinander auf der Einstiegsebene. Für jedes Benutzerverzeichnis einen eigenen ISP-Knoten anzulegen, wiederholt zum einen das zweite zuvor genannte Problem und ist in Anbetracht der Anzahl von Nutzern sehr aufwändig.
Einfacher ist es daher, die Verzeichnisse anhand eines Musters zu unterscheiden, beispielsweise nach dem (oder den) ersten Zeichen: ^[a,A], ^[b,B], … ,^[z,Z], ^[0-9] (ISP verseht an dieser Stelle sogar „regular Expressions“!)
Man erhält also 27 bzw. 729 ISP/TSM-Knoten, die automatisch auch alle neuen Verzeichnisse umfassen. Unglücklicherweise erfassen die RegEx-Formulierungen nur die Verzeichnisse, die existieren, nicht aber die die gelöschten. Abhilfe ist möglich, wenn man zusätzlich alle Verzeichnisse des Startpfades ohne Unterverzeichnisse sichert.
Obwohl diese Variante häufig besser als die erste ist, erfüllt sie nicht alle Erwartungen:

  • Das Lösen des „gelöschte Verzeichnisse“-Problems ist umständlich.
  • Die Konfiguration wird – insbesondere wenn man nach den ersten beiden Buchstaben unterscheidet – sehr umfangreich.
  • Änderungen der Verzeichnisnamen verteilen die Daten über mehrere ISP-Knoten und besonders der Restore wird aufwändig.

Zusammenfassend ist festzustellen, dass es für beide Ansätze sicherlich Einsatzszenarien gibt, aber aus der Erfahrung an der GWDG ist zu berichten, dass der Aufwand recht hoch ist und es immer wieder ein paar „Power-User“ gibt, die bei diesen beiden Ansätzen nochmals eine Sonderbehandlung benötigen um einen brauchbaren Nutzen zu erzielen.

Ein Ansatz für alle Filesysteme

Idee und Erste Schritte mit der BASH

Bereits im letzten Jahrzehnt stand die (damalige) Generali Versicherungs-AG vor dem eingangs skizzierten Problem und Rudolf Wüst als Backup-Admin erweiterte die zuvor genannten Ansatz um einen entscheidende Idee. Hieraus entwickelte er eine Lösung, die erfolgreich mit bis zu 2000 Threads das „Such-Problem“ parallelisierte. Freundlicherweise teilte Herr Wüst seine Erweiterung gern und der Autor hat sie aufgegriffen und im Rahmen der Tätigkeit an der GWDG weiterentwickelt.
Ziel einer praktikablen Lösung muss es sein, sowohl alle Verzeichnisse zu erfassen, sie in einem ISP/TSM-Knoten zu speichern und dennoch das Suchen zu parallelisieren. Dies gelingt, wenn man statt dem einfachen Backup-Aufruf ein Skript ausführt, das seinerseits mehrere parallele Threads zum Sichern der Verzeichnisse startet. Der Kern des Skriptes besteht also in einer Schleife der folgenden Form (Beispiel 1).

Für alle (finde alle Verzeichnisse im Startpfad)
{
	Starte einen Backup-Thread für das aktuelle Verzeichnis
}

Beipiel 1: Pseudocode der Parallelisierung

Statt einem „incremental backup“ werden also viele „partial incremental backup“ ausgeführt und zwar für jedes Verzeichnis einer. Die gelöschten Verzeichnisse erfasst man mit einem anschließenden Backup des Startpfades ohne Unterverzeichnisse – die letzte Angabe ist enorm wichtig, sonst macht man ein normales „incremental backup“ auf dem gesamten Filesystem.

Als Quelltext für die BASH sieht dies wie in Beispiel 2 aus.

startpath=<Startpfad>;
folderlist=<Pfad zu einer Datei, wo die Ordnernamen gespeichert werden>;
find $startpath –xdev –mindepth 1 –maxdepth 1 –type d –print > $folderlist
for $i in $(cat $folderlist)
do
	dsmc –i $i –subdir=yes &
done
dsmc –i $startpath –subdir=no
rm $folderlist;

Beipiel 2: Quellcode für die BASH

Im Rahmen der ersten Tests wird man herausfinden, dass das Skript in der vorliegenden Form tatsächlich ebenso viele Threads wie vorhandene Verzeichnisse startet. Zum einen zwingt man damit den Rechner, der das Backup ausführt in die Knie, zum zweiten wird wahrscheinlich quasi sofort die Maxsessions-Einstellung des ISP/TSM-Servers erreicht und dieser verweigert weitere Verbindungen.
Abhilfe schafft ein Zähler, der bei Erreichen der erlaubten Anzahl von Threads einfach wartet. In der Bash haben die abgespaltenen Backup-Threads als parent process ID die process ID des Skriptes selbst, so lassen sich diese Threads sogar dann zählen, wenn man das Skript für mehrere Filesysteme gleichzeitig laufen lässt.

Als BASH-Code sieht die Schleife damit wie in Beispiel 3 aus.

pid=$$;	# parents process id 
startpath=<Startpfad>;
folderlist=<Pfad zu einer Datei, wo die Ordnernamen gespeichert werden>;
maxthreads=<max. Anzahl paralleler Threads>;
find $startpath –xdev –mindepth 1 –maxdepth 1 –type d –print > $folderlist

while [ -s $folderlist ]
do
	nthreads=$(ps axo ppid,cmd | grep $ppid | grep -v grep | wc -l)
	if [ $nthreads -le $maxthreads ]
	then
		# get new start path
		folder=$(head -n 1 < $folderlist);

		# backup actual folder
		dsmc i $folder/ -subdir=yes -quiet >> $ppid.log &

		# remove first line from folderlist
		sed -i '1 d' $folderlist
	else
		sleep 5; # wait to complete another thread
	fi;
done
dsmc –i $startpath –subdir=no

# Am Ende auf alle laufenden Threads warten
while [ $nthreads -gt 1 ]
do
	>&2 echo "Waiting for $nthreads threads to end"
	sleep 60;
	nthreads=$(ps axo ppid,cmd | grep $ppid | grep -v grep | wc -l)
done
rm $folderlist;

Beipiel 3: erweiterter Quellcode für die BASH

In der erweiterten Form werden nun wesentliche Ziele erreicht, aber vollständig zufrieden kann man dennoch nicht sein:

  • Für das Reporting über den ISP/TSM-Server fehlt ein Rückgabe-Wert. Im einfachsten Fall kann man eine Zeile return 0 am Ende anhängen, dann ist das Schedule immer erfolgreich – unabhängig davon, ob Fehler auftreten oder nicht. Wie im Beispiel 3 schon ergänzt, sollte man also eher die Ausgabe der einzelnen „partial incremental backups“ einsammeln und zum Ende des Skriptes auswerten, beispielsweise nach Fehlern suchen oder die „Summaries“ zusammenfassen. Anhängig von der Art (ggf. auch Anzahl) der Fehler und der „Files failed“, kann dann das Skript die passenden Rückgabewerte geben. (Diese Erweiterung ist im veröffentlichten Quellcode bereits enthalten.)
  • Das bei der Idee genannte Problem, dass es einzelne Verzeichnisse einen nennenswerten Anteil der Filesystemgröße nutzen und damit die Laufzeit des Backups maßgeblich beeinflussen, wird durch das Skript nicht gelöst. Die Ungleichheit der Datenmenge / Objektanzahl wird sicherlich kleiner, verlagert sich letztendlich aber nur.
    Als nächsten Schritt könnte man daher die Verzeichnisliste über mehrere Ebenen erstellen und die somit größere Anzahl partieller Backups vergrößern. Im Ergebnis sollte sich die Ungleichheit nochmal stärker ausgleichen.
  • Im Reporting des ISP/TSM-Server lassen sich neben dem Return Code eines „Client-Schedules“ natürlich auch detailliert Fehlermeldungen und in Form der Summary ein Überblick auslesen, dies ist mit dem angegebenen Skript (derzeit) nicht möglich, es liefert nur einen ampelhaften Status über den Return Code.

Ein Ausflug in die PowerShell

Basierend auf dem BASH-Code wurde versucht, den Algorithmus mit der Windows-PowerShell umzusetzen. Unix-Affinität einerseits, sicherlich verbunden mit Vorbehalten gegenüber der Powershell, vor allem aber der doppelte Aufwand haben dieses Projekt nach einigem Aufwand beendet ohne bereits eine lauffähige Version erstellt zu haben.

PERL – eine Lösung für alle (?) Welten und Weiterentwicklung des Einfach-Ansatzes

Die am nächsten liegende Lösung wurde zunächst übersehen: eine Programmier-/Skriptsprache für alle Betriebssysteme und zwar weder BASH/MinGW/ WSL noch PowerShell / PowerShell Core on Linux, sondern PERL.

PERL bietet zahlreiche Funktionen – auch im Bereich des Zugriffs auf Dateien und Verzeichnisse, die durch die jeweilige Implementierung so gekapselt sind, dass der eigentliche Befehl unabhängig vom Betriebssystem ist. Filesystem-Pfade können sogar sowohl in Unix- wie Windows-Nomenklatur (also mit / bzw. \ als Verzeichnistrenner) angegeben werden und dank der Funktion File::Spec→canonpath werden sie ins jeweils korrekte Format konvertiert. Der Quellcode braucht also zu weiten Teilen nicht für die jeweilige Plattform individuell angepasst werden. Ausnahmen sind die Pfade zu den Binaries, also \opt\tivoli\client\ba\bin\dsmc bzw. C:\Program Files\Tivoli\baclient\dsmc.exe und (derzeit) das nur teilweise Auslesen des Verzeichnisbaumes mittels find (Linux) und Robocopy (Windows).

Ein weiterer Grund, der für PERL spricht ist, dass es auf eine einfache Art und Weise sowohl die Nutzung von Threads ermöglicht und ebenso einfach sicherstellen lässt, dass jeweils nur eine bestimmte Anzahl von (Sub-)Threads gleichzeitig laufen und somit das Starten weiterer Threads erst nach Beendigung vorheriger erfolgt – und dies unabhängig vom Betriebssystem!

Die für die BASH skizzierten Schritte reduzieren sich damit in PERL auf drei wesentliche Schritte:

  1. Erzeugen eines neuen Subthreads mit dem fork()-Befehl
  2. Verzweigen des Quellcodes in die Pfade „Hauptskript“ und „Skript für den Subthread“,
    im Hauptskript wird eigentlich nur die Anzahl der gestarteten Threads hochgezählt, im Subthread findet hingegen das „partial incremental backup“ statt
  3. Kontrolle, ob die gewünschte Anzahl Threads erreicht ist und auf das Beenden eines Threads warten und dann einen neuen starten.

Im Detail ist der Quellcode natürlich etwas komplexer und berücksichtigt zum Beispiel auch, dass das Starten eines Subthreads nicht erfolgreich war.

Erste Weiterentwicklung: Tieferes Eintauchen in den Verzeichnisbaum und Starten paralleler Threads auf Basis mehrerer Verzeichnisebenen

Die Tests mit dem Parallelisierungsansatz direkt unterhalb des Basispfades zeigten genau jene Effekte die bereits bei der Parallelisierung über Institute angesprochen wurden: Einzelne Verzeichnisse sind (meist) größer als alle übrigen parallel liegenden zusammen, so dass der Geschwindigkeitsgewinn erheblich geringer ausfällt als erwartet / oder gewünscht. Eine bessere Ausbalancierung lässt sich nur über zusätzliche Verzeichnisse erreichen, diese finden sich, wenn man neben der ersten, obersten Verzeichnisebene unterhalb des Startpfades weitere Ebenen durchsucht und das Backup dann über alle diese Verzeichnisse machen lässt. Problematisch ist hierbei zunächst, dass die Verzeichnisse verschachtelt sind, also ein partielles Backup eines Verzeichnisses von einer höheren Ebene auch jene Unterverzeichnisse umfasst, die in weiteren parallelen Threads sowieso gesichert werden. Im vorliegenden Skript wurde dieses Problem dadurch gelöst, dass alle Verzeichnisse oberhalb der eingestellten „Tauchtiefe“ mit der Option -SUbdir=No gesichert werden, also nur die Inhalte dieser Verzeichnisse samt Namen der Unterverzeichnisse, aber nicht deren Inhalt. In einem zweiten Schritt werden die Verzeichnisse auf der untersten angegebenen Ebene mit Ihren Unterverzeichnissen (Option -SUbdir=Yes) gesichert (Da die Sicherungen ohne Unterverzeichnisse in der Regel erheblich schneller gehen, werden zunächst jene Verzeichnisse mit Unterverzeichnissen gesichert und jene ohne als zweites).

Auswertung der einzelnen Läufe

Nicht nur für das Profiling (s.u.) sondern auch um eine Zusammenfassung des Backups zu erstellen, schreibt jeder Sub-Thread seinen Ausgabe in eine eigenen Datei, die neben der Prozess-ID des Skriptes seine eigene ID im Namen enthält. So können auch bei einem Abbruch des Skriptes die Ausgaben eindeutig zugeordnet werden.
Obwohl die Gesamtauswertung erst am Ende des Backups erfolgen kann, führt doch hinreichend tiefes Eintauchen in den Verzeichnisbaum in der Praxis doch schnell zu mehreren tausend bis hunderttausenden kleinen Dateien und damit zu erheblichen Problemen. Daher schreiben die Subthreads nach Beendigung Ihres Backups den Inhalt der Ausgabe-Datei in eine zentrale Log-Datei, die zum Abschluss des Skriptes ausgewertet wird. Im Rahmen dieses Zusammenschreibens wird außerdem die Information, ob Unterverzeichnisse verarbeitet wurden, gespeichert und die Laufzeit bereits für das Profiling in Sekunden umgerechnet und gespeichert. Außerdem wird der Rückgabewert des Backup-Aufrufs hinzugefügt.
In der aktuellen Implementierung (September 2018) summiert die abschließende Auswertung

  • die Anzahl der inspizierten Objekte
  • die Anzahl der gesicherten Objekte
  • die Anzahl der aktualisierten Objekte
  • die Anzahl der gelöschten Objekte
  • die Anzahl der verwaisten Objekte
  • die Anzahl der fehlerhaften Objekte
  • die Anzahl der inspizierten Bytes
  • die Anzahl der übertragenen Bytes
  • die Zeit für den Datentransfer
  • die verstrichene Zeit

ggf. erfolgt eine Umrechnung auf die gemeinsame Größe (Bytes, Sekunden).

Darüber hinaus wird die Anzahl

  • der Warnungen (/^AN[RS][0-9]{4}E/)
  • der schwerwiegenden Fehler (/^AN[RS][0-9]{4}S/)
  • der Fehler infolge ANS1228E und ANS1820E
  • der Server-Out-of-Space-Fehler (ANS1292S) zusätzlich

gezählt und jeweils als Summe ausgegeben.

Aus der Summe der verstrichenen Zeiten und der Laufzeit der Schleife über die Verzeichnisse („WALL CLOCK TIME“) berechnet das Skript einen parallelen Speedup, der anzeigt, wie viel schneller die Parallelisierung gegenüber der Summe der Einzelzeiten ist.

Performance-Optimierung mittels Profiling

Die Laufzeit auch des parallelen Backups wird wesentlich durch die Laufzeiten der einzelnen Backup-Läufe bestimmt. Ohne detaillierte Messung (aber anhand des Vergleichs des Skriplaufs mit auskommentiertem Backup-Aufruf) wird davon ausgegangen, dass die Laufzeit der PERL-Anweisungen im Vergleich vernachlässigbar ist. Ziel der Optimierung ist also die „richtige“ Reihenfolge der Verzeichnisse, so dass

  1. die großen, langlaufenden möglichst parallel laufen
  2. Mit den großen begonnen wird, weil sich eine Miss-Balance bei den kürzeren Laufzeiten der kleineren Verzeichnisse weniger dramatisch auswirkt

Da im Voraus die Laufzeit der Backups nicht geschätzt werden kann, erfolgt die Optimierung auf Basis des letzten Backups (und unterstellt natürlich keine dramatischen Änderungen, die aber nur durch aufwändige und damit zeitintensive Analysen vorherzusagen wären). Wie zuvor beschrieben schreiben die Sub-Threads am Ende des Backups auch die Laufzeit in Sekunden in die zentrale Logdatei, so dass bei deren Auswertung auch eine Liste aller Verzeichnisse mit den jeweiligen Laufzeiten erstellt wird. Diese Liste wird nach absteigenden Laufzeiten sortiert und in eine Profildatei geschrieben.
Beim nächsten Aufruf des Skriptes erstellt dieses eine Liste aller Verzeichnisse die gesichert werden sollen. Im nächsten Schritt (dieser Teil funktioniert für Windows noch nicht und ist daher zurzeit wieder ausgelagert worden) vergleicht das Backup-Skript diese Liste mit den Einträgen aus der Profiling-Datei:

  • Verzeichnisse, die zwar in der Profiling-Datei stehen, aber nicht mehr in der Verzeichnisliste vorhanden sind, werden ignoriert,
  • neue Einträge der Verzeichnisliste, zu denen es keine Laufzeit in der Profiling-Datei gibt, werden mit einer hohen Laufzeit (10^10 Sekunden ⇒ 316 Jahre) versehen und somit als erste einsortiert.

Sofern keine Profiling-Datei vorliegt, werden die Verzeichnisse in der Reihenfolge abgearbeitet, wie sie in der Liste aus dem Verzeichnisbaum stehen.

Zum Abschluss der Auswertung wird die Profiling-Liste überschrieben.

Offene Punkte / Ausblick

Es sind noch einige Fragen offen, beispielsweise nach dem Übertragen der Summary in das Serverlog.

Für eine „runde Sache“ sollte noch eine Fehlerbehandlung ergänzt werden, um das Skript gegenüber bestimmten Situationen fehlertolerant zu machen.

Denkbar ist auch die Teilung der Arbeistschritte „Verzeichnisse identifizieren“ und „partial incremental backup“, so dass bei sehr großen Filessystemen die Liste der abzuarbeitenden Verzeichnisse wieder aufgefüllt wird, sobald das Backup-Fenster verstrichen ist, aber noch immer ein oder wenige Threads laufe – wahrscheinlich ist aber das Erhöhen der Eintauchtiefe hierfür der bessere Ansatz.

Ein Problem was nicht gelöst werden kann, ist die Tatsache, dass partial incremental backups nicht die Last Backup-Attribute der Knoten bzw. Filespaces ändern und dies natürlich auch nicht im Rahmen des skizzierten Skriptes erfolgt. Von einem schreibenden Eingriff in die DB2 der ISP/TSM-Server sollte man absehen, da dies die Gewährleistung durch IBM berührt. IBM untersagt ausdrücklich direkte Zugriffe auf die ISP/TSM-DB2 außerhalb von entsprechenden Anweisungen im Rahmen des Supports.

Und wie beschleunigt man den Restore?

Die zuvor genannten Ansätze mit ISP-Bordmitteln und der skizzierte Ansatz für die Parallelisierung funktioniert erst einmal nur für das Backup. Sollen viele Dateien aus dem Backup restored werden, ist dies bei den Ansätzen mit mehreren Knoten für einen Filespace sehr einfach, da sowieso für jeden Knoten ein eigener Restore laufen muss und die Prozesse hierbei parallel laufen. Für den Ansatz der parallelen Threads ist eine Anpassung für den Restore auf Basis einer Filelist einfach möglich: Statt eine folderliste wird beim Restore über eine Dateiliste parallelisiert.

Zu Bedenken ist aber, dass in einer Umgebung mit einer Tapelibrary als Storage-Backend die Leistung des Restore in der Regel durch die Anzahl der Laufwerke begrenzt ist. Außerdem organisiert ISP den Restore normalerweise (also ohne die Option -disablenqr=yes) so, dass die Tapemounts optimiert werden. Wird eine Filelist parallel durch zahlreiche parallele Threads abgearbeitet, so kann der Server die Tape-Zugriffe nicht optimieren. Kommt allerdings ein Disk-basierter FILE- oder Container-Pool zum Einsatz ist der parallele Restore über zahlreiche Threads schneller. Sofern die Daten über Server-Replikation auf zwei Servern vorgehalten werden, kann der Restore auch über beide Server verteilt und damit zusätzlich beschleunigt werden.

Erfahrungen zeigen leider, dass „Full Restores“ auch bei Parallelisierung einen enormen Aufwand bedeuten und sich nur unbefriedigend beschleunigen lassen.

Verfügbarkeit / Zugang zum Quellcode / Alternativen

Es ist davon auszugehen, dass weder der genannte Ideengeber noch die GWDG den Anspruch erheben können, als einzige die skizzierte Idee gehabt und implementiert zu haben. Vielmehr dürften zahlreiche ISP/TSM-Nutzer vor dem gleichen Problem stehend, ähnliche Lösungen gefunden haben.

Eine kommerzielle Implementierung, die einen ähnlichen Ansatzes der Parallelisierung verfolgt, findet sich im Produkt „MAGS“ der General Storage). Neben einem verbindlichen Support bietet „MAGS“ eine regelmäßige Weiterentwicklung und nutzt bei „ISILON“ ScaleOut -Systemen auch mehrere NAS-Knoten für die Parallelisierung. Eine detailliertere Produktbetrachtung soll hier nicht erfolgen, den Mehrwert muss man auch individuell ermitteln.

Das im Rahmen dieses Artikels angesprochene Skript ist im GITLAB der GWDG frei unter der Apache 2.0-Lizenz in mehreren Varianten verfügbar. Die Skripte dürfen uneingeschränkt eingesetzt und verändert werden. Über eine Rückmeldung und Vorschläge freuen wir uns natürlich.

Übertragbarkeit auf andere Backuplösungen

Die dargestellten Ansätze adressieren das Problem der Identifikation von Dateien und sind somit natürlich auf alle anderen Fragestellungen übertragbar, wo eine Dateiliste erstellt werden soll. Ersetzt man den Aufruf der ISP-CLI durch ein weiteres „find“ lassen sich auch parallel alle Dateien finden, über entsprechende Parameter auch gefiltert nach allen von find unterstützten Attributen. Ebenso kann man eine weitere Schleife ergänzen die beliebige Operationen mit allen Einträgen einer vollständigen Dateiliste macht. Damit lassen sich auch andere Backuplösungen optimieren, die eine Verzeichnis- oder Fileliste verarbeiten können.

Danksagung

Der Autor dankt den Herren Gerd Becker (Empalis GmbH), Wolfgang Hitzler (IBM) und Manuel Panea (MPCDF) für das Korrekturlesen des ursprünglichen Artikels und die gemachten Änderungs- und Verbesserungsvorschläge.

Besonderer Dank gilt Herrn Rudolf Wüst (Generali Shared Services S.c.a.r.I.) für die Freigiebigkeit, seine Ideen zu teilen.

Exkurse

Workaround für VIRTUALMOUNTPOINTS bei Windows-Clients

Für Unix und Linux und MacOS gibt es im TSM/ISP die Möglichkeit, einzelne Verzeichnisse als virtuelle Laufwerke zu konfigurieren. Hiermit vereinfacht sich die Konfiguration des Backups, da direkt das virtuelle Laufwerk als Backup-Quelle angegeben werden kann anstatt das tatsächliche Laufwerk anzugeben und alle Verzeichnisse, die nicht gesichert werden sollen, mittels Exclude-Regeln auszuschließen.
Eine vergleichbare Funktion gibt es für Windows leider nicht. Damit entfällt auch die Möglichkeit, das Backup über verschiedene virtuelle Laufwerke zu parallelisieren.
Sofern aber nur einzelne Verzeichnisse gesichert werden sollen, nicht aber auch parallel das übrige Wurzelverzeichnis, müssen meist zahlreiche Ausschlussregeln in Form von exclude.dir-Einträge in der dsm.opt erstellt werden. Selbstredend ist dieser Weg hochgradig fehlerträchtig, zusätzlich werden natürlich alle im Wurzelverzeichnis eines Laufwerks neu erstellten Verzeichnisse nicht automatisch ausgeschlossen, sondern in das Backup eines jeden Knotens hineingenommen.

Mit dem folgenden Workaround kann unter Windows die Konfiguration vereinfacht und die Parallelisierung des Backups erreicht werden:

  • Man erstelle für jedes Verzeichnis, das gesichert werden soll eine erweiterte Freigabe.
  • Durch das Hinzufügen eines $ an den Freigabennamen wird diese vom Windows-SMB-Dienst auch nicht in der Netzwerkübersicht aufgelistet (versteckte Freigabe)
  • Zugriff auf diese Freigabe benötigen nur die lokalen Admins des Backup-Knotens
    WICHTIG: damit lässt sich auch das Fehlen der NT-Backup-Privilegien auf Nicht-Windows-Filesystemen umgehen :-)
  • Die zu sichernden Pfade können über das Loopback-Device angesprochen werden:
    DOMAIN \\127.0.0.1\<Freigabe1>
    DOMAIN \\127.0.0.1\<Freigabe2>
    usw.

Aus Sicht des TSM/ISP-Clients sind die Freigaben unabhängige Netzwerkshares und können parallel gesichert werden!

Weiterer netter Randeffekt:
Werden Verzeichnisse verschoben, muss man nur die Freigabe nachziehen, aus Sicht des TSM-Clients liegen die Daten schließlich noch immer am gleichen Ort (\\127.0.0.1\<Freigabe>) – gegebenenfalls umfangreiche Vollsicherungen entfallen ;-)

… und es wird noch besser:
Mit den lokalen Freigabe sind sogar Wechsel zwischen verschiedenen Servern als Host für den Client kein Problem mehr :-D

… während der zusätzliche Overhead die Leistung des Clients (nach Erfahrungen der GWDG und des MPI-BPC und MPI EM) nur um weniger als 10% schmälert …

Threads in PERL

PERL bietet ein eigenes Thread-Modul und damit eine wesentlich elegantere Methode als die komplexen Lösungen für die BASH oder die Powershell:

Über den fork()-Befehl erzeugt der PERL-Interpreter einen zweiten Thread, der an just dieser Stelle im Skript startet. Dieser Thread bearbeitet wie das originale Skript alle nachfolgenden Anweisungen. Es daher sinnvoll die unterschiedlichen Aufgaben über eine IF-Anweisung zu verzweigen. Hierfür bietet die Abfrage des Rückgabewertes der fork()-Routine an: ist der Wert nicht definiert, konnte kein Thread erzeugt werden, ist der Wert „wahr“, gibt es einen neuen Thread – und es ist die Elternroutine, in der dieses IF ausgeführt wurde. Im Kindthread ist der Wert ebenfalls definiert, aber „falsch“. Die Abfrage könnte also wie folgt aussehen:

my $cpid = fork();
if (! defined $cpid)
{	# forking failed!
       exit 1; # Abbruch des Skriptes
}
if ($cpid)
{	# parent process
	# … was der Elternprozess auch immer tun soll
}
else
{	# child process
	# … was der Kindprozess auch immer tun soll
}


Auch das Einsammeln / Abwarten der gestarteten Threads gestaltet sich wesentlich einfacher: Über die wait()-Funktion wird auf das Beenden eines Kindthreads gewartet, alle können also mit einer einfachen Schleife abgewartet werden:

while (wait() != -1 ) ;