Laden...

Empfehlung und Erfahrungswerte für Hash-Verfahren - Wie grosse Dateien vernünftig Hashen?

Erstellt von Taipi88 vor 4 Jahren Letzter Beitrag vor 4 Jahren 2.132 Views
Taipi88 Themenstarter:in
1.029 Beiträge seit 2010
vor 4 Jahren
Empfehlung und Erfahrungswerte für Hash-Verfahren - Wie grosse Dateien vernünftig Hashen?

Hi,

ich habe eine Spezialaufgabe bekommen, in deren Rahmen ich den Inhalt eines recht großen Verzeichnisses (12TB+) überwachen muss.

Die Dateien sollten prinzipiell nicht geändert werden - und wenn doch muss ich das feststellen und merken. Soweit so gut - ich würde als hingehen - jede Datei hashen, den Hash speichern und dann ungefähr einmal pro Monat jede Datei prüfen und ggf. Änderungen melden.

Nun - da das Verzeichnis so riesig ist wird das Berechnen der Hashes eine ganze Weile dauern, was die Frage nach dem "richtigen" Hashverfahren recht wichtig macht in meinen Augen. Und hierzu bräuchte ich ein paar eurer Tipps und Erfahrungen.

Über die Dateien: Die meisten sind ca. 75MB aufwärts - spontan würde ich hier erst mal auf md5 tippen - mir stellt sich allerdings die Frage ob hier CRC32 ebenfalls angebracht wäre und ob es ggf. noch weitere - eventuell gar schnellere und ausreiched "robuste" Hashverfahren gibt.

Vielen Dank im Voraus.

16.806 Beiträge seit 2008
vor 4 Jahren

Soweit ich die Geräte kenne verwenden WAN Appliances für das Zwischenspeichern von Daten um die Geschwindigkeit zu erhöhen SHA1 via Hardware-Calc und gilt insgesamt als most-trusted.

IIRC ist derzeit für das eindeutige File Hashing derzeit das schnellste Verfahren MD2.

6.911 Beiträge seit 2009
vor 4 Jahren

Hallo Taipi88,

in Anbetracht der Menge können Hash-Funktionen zu langsam sein und eine kryptografische Sicherheit brauchst du wohl auch nicht (andernfalls nimm die Hinweise von Abt). Daher werden m.E. Prüfsummen ausreichen und wesentlich schneller / performanter sind diese auch (aber dafür weniger bis nicht kryptografisch sicher).

Als Verfahren für die Prüfsumme würde ich Adler-32 verwenden. Dies zum Einen aus dem Bauchgefühl und zum Anderen auch da es Tools wie rsync verwenden, somit gibt es einen praktischen "Beweis" dass es damit funktioniert.

Ich würde zur Prüfung auch ein mehrstufiges Verfahren anwenden. Letzte Dateimodifikation (Zeitstempel), Prüfsumme und Byte-Vergleich* um Kollisionen der Prüfsumme bzw. deren false positives zu eliminieren.

Schau dir aber auch File verification an, vllt. gibt es dort schon Tools auf denen du aufbauen kannst.

* mit Span<byte> lässt sich das mit SequenceEqual sogar vektorisiert durchführen, so dass auch das sehr zügig vonstatten gehen kann.

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"

W
955 Beiträge seit 2010
vor 4 Jahren

Kannst du nicht irgendeine Backupsoftware dafür mißbrauchen?

T
2.219 Beiträge seit 2008
vor 4 Jahren

@Taipi88
Wie sollen die Änderungen von dir gemeldet werden?
Ich habe bei mir z.B. auf einem Linux System rsync zum abgleichen meiner Backups.
Diese sind aktuell über 3TB groß und ein Durchlauf zum abgleich dauert dort trotz vieler Dateien, ich spiegle von Debian die Paketquellen, auch nur einige Minuten.

Wenn du, wie von witte vorgeschlagen, auch fertige Tools verwenden kannst und nur z.B. per Ausgabe die Änderungen melden kannst, kannst du mal schauen ab rsync reicht.
Falls es aber doch etwas komplexer wird, würde ich bei der Menge an Daten kein Hashing sondern einfach Daten wie letzte Änderung und Dateigröße merken.
Dies ist bei der Menge an Dateien einfach die schnellste Lösung.

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

Taipi88 Themenstarter:in
1.029 Beiträge seit 2010
vor 4 Jahren

Hi,

ich soll eigentlich zum Abschluss eines jeden Prüfzyklus eine Zusammenfassung der geänderten Dateien bzw. eine "Erfolgsmeldung", dass sich nichts geändert hat per Mail schicken. Ich schätze mal eine halbwegs übersichtliche Zusammenfassung des Ergebnisses mit anpassbarem Layout mit vorhandenen Tools ist eher schwierig 😕 Ich schau mich dennoch mal um.

Die Größe der Datei darf allerdings in diesem Fall nicht bewirken, dass diese Datei als unverändert betrachtet wird, hiermit darf man dann lediglich ausschließen, dass das Errechnen einer Prüfsumme/Hashwerts erforderlich ist, da die Datei definitiv verändert wurde.

Ich werde jetzt erstmal ein wenig rumtesten, ob ich mit Adler32 und MD2 glücklich werden könnte. Falls nicht muss ich wohl oder übel intervenieren, dass das auf dieser Basis vll zu viel gewollt ist.

LG und Vielen Dank

T
2.219 Beiträge seit 2008
vor 4 Jahren

Was spricht den gegen die einfache Prüfung des Zeitstempel der letzten Änderung + die Größe?
So wird es auch von den meisten Tools gemacht, da hashen eben aufgrund von der Dateigröße oder Anzahl einfach zu viel wäre.
Oder kann es sein, dass jemand die Dateien soweit ändern kann, dass er auch den Zeitstempel manipulieren könnte?

Hier wäre es wichtig zu wissen wie diese Änderungen passieren können.
Wenn dies auch nur automatisiert passiert, würde ich nicht davon ausgehen, dass die Zeitstempel manipuliert werden.
Dann reicht die Prüfung auf den Zeitstempel und die Größe vollkommen aus.

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

16.806 Beiträge seit 2008
vor 4 Jahren

Was spricht den gegen die einfache Prüfung des Zeitstempel der letzten Änderung + die Größe?

Zeitstempel sind keine legitime Verifizierung, sie sind nicht reliable. Wird auch von Microsoft und jedem Data Storage Provider absolut abgeraten.

T
2.219 Beiträge seit 2008
vor 4 Jahren

Warum arbeiten dann Tools wie Robocopy und auch rsync dann noch danach?
Gerade bei robocopy und den alten Tools scheint Microsoft dann seine eigenen Regeln nicht ernst genug zu nehmen.

Um bei Robocopy und rsync den Abgleich per Hash zu machen, müsste man extra Parameter mitgeben.
Würde ich in dem Fall auch machen, da schon das lesen der Datenmenge einfach zu lange dauern würde.
Alle Dateien komplett zu lesen dürfte bei einer einzelnen Festplatte als Storage schon fast einen Tag dauern.
Wenn die Überprüfung nur einmal im Monat passieren soll ist das kein Problem aber schon ab einem täglichen Prüfung würde es zu lange dauern und zu viel IO Last produzieren.
Und wenn die Datenmenge dann noch weiter wächst, wäre der Prüfaufwand schon unverhältnismäßig.

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

Taipi88 Themenstarter:in
1.029 Beiträge seit 2010
vor 4 Jahren

Hi,

naja - in diesem Fall ist das ganze ein Raid10 - mit einem Durchsatz von 800 MB/s geht da schon ein bisschen mehr wie nur über eine Platte - Fakt ist nach ersten Tests jedenfalls definitiv, dass der Flaschenhals dennoch der Datenspeicher bleibt.

Wenn das ganze etwas länger dauert wird man bei uns letztlich damit leben müssen - möchte jedoch bei der Datenmenge natürlich trotzdem möglichst effizient vorgehen. Nach Erfassung der urspünglichen Prüfsumme bzw. Hashwert reicht es völlig aus, dass danach jede Datei alle 30 Tage geprüft wird - würde hier entsprechend partitionieren, dass täglich ein kleinerer Teil überprüft wird. (Hier dann auf Basis der Größe der Dateien)

Größe und Zeitstempel sind (auch in meinen Augen) eigentlich kein absolut verlässlicher Indikator für unveränderte Dateien - sicher - der Fall, dass sich dort versehentlich etwas ändert ist in der Theorie selten - aber letztendlich heißt das ja nichts.

Nunja - das erstellen einer Adler32-Prüfsumme für ca. 1TB dauert nach ersten Tests ungefähr 20 Minuten (MD5 und SHA1+2 ähnlich) - damit wäre theoretisch sogar täglich ein kompletter Scan (noch) machbar - da hier allerdings nicht erforderlich - seh ich mit bei einem 30-Tages-Fenster genug Luft für weiteren Wachstum des Datenspeichers. (Werde die Zeit zwar sicherlich noch steigern, da das Ganze reines Prüfsummen berechnen ist - aber selbst wenn's eine Stunde pro TB dauert geht das denke ich in Ordnung)

LG

T
2.219 Beiträge seit 2008
vor 4 Jahren

Bei dem Durchsatz und der lange Zeit zwischen den Läufen, würde es passen.
Ich bin davon ausgegangen, dass z.B. eine tägliche oder wöchentliche Prüfung auch ein möglicher Fall wäre
Dann wäre eine lahme Platte + kurze Prüfintervall einfach ein zu großes Problem für Hashing.

Wenn du mehr als einen Thread verwendest, könntest du auch noch etwas Zeit sparen.
Bei 800MB/s Durchsatz sollten auch größere Dateien schnell durchlaufen werden können.
Per Single Threading würde es bei vielen Daten sonst auch länger als nötig dauern.

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

Taipi88 Themenstarter:in
1.029 Beiträge seit 2010
vor 4 Jahren

Hi,

parallelisiert war das schon - hab erst einmal Parallel.ForEach ohne manuelle Anpassungen des MaxDegreeOfParallelism verwendet. (Muss noch testen, ob weitere Einschränkungen hier weitere Besserung bringen könnten) Die 800 MB/s an Durchsatz kamen nahezu ausschließlich vom Testprogramm. (Hatte hier eigentlich erwartet, dass Parallel.ForEach keine so tolle Idee ist - aber scheinbar ist es kein schlechter Start)

Trotzdem vielen Dank für den Hinweis.

LG

T
2.219 Beiträge seit 2008
vor 4 Jahren

Bin nicht ganz sicher aber würde er bei Parallel.For/Foreach nicht ohne die Einstellung für jede Aufgabe intern dann einen eigenen Task starten?
Wenn du also 1000 Einträge hingibst, müsste er auch 1000 Tasks starten.
Falls diese länger laufen, würde er ggf. neue Threads im ThreadPool anfordern, was bei großen Dateien dann deine Thread Anzahl immer weiter anwachsen lässt.

Versuch in dem Fall mal über MaxDegreeOfParallelism zu begrenzen um weder CPU noch die IO Last zu überladen.
Vielleicht geht da noch etwas mehr Durchsatz 😃
Als Minimum würde ich mit der Enviroment.ProcessorCount + 1 anfangen und es weiter justieren.

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

6.911 Beiträge seit 2009
vor 4 Jahren

Hallo T-Virus,

bei Parallel.For/Foreach nicht ohne die Einstellung für jede Aufgabe intern dann einen eigenen Task starten?

Korrekt. Daher gibt es -- neben den von dir genannten Möglichkeiten -- auch die "Partitioner", mit denen dann pro "Range" ein Task erstellt wird.

Wobei ganz korrekt "Task starten" nicht ist, denn der Task wird zur Ausführung per Scheduler standardmäßig an den ThreadPool übergeben. Gestartet wird dabei nichts.

Falls diese länger laufen, würde er ggf. neue Threads im ThreadPool anfordern, was bei großen Dateien dann deine Thread Anzahl immer weiter anwachsen lässt.

Die Thread-Injection-Logik kapiert das schon dass der "Durchsatz" nicht besser wird und nimmt ggf. sogar Threads wieder weg. Basierend auf einem Hillclimb-Algorithmus. Das Problem sehe ich nicht, sollte aber dennoch nicht ganz außer Acht gelassen werden, insofern ist dein Hinweis gut und passend.

Hallo Taipi88,

ich würde das Problem eher darin sehen, dass paralellisiert und "gleichzeitig" auf das Dateisystem zugegriffen wird. D.h. wenn das Dateisystem dafür nicht ausgelegt ist, so handelst du dir hier einen Flaschenhals ein.
Andererseits fällt augrund der Größe der Dateien ein Producer-Consumer-mäßiges sequentielles Laden der Dateien in den RAM und dann parallele Consumer-Verarbeitung womöglich auch aus.

Es hängt also vom Dateisystem, dessen Konfiguration, vom RAM, etc. ab.

Die meisten sind ca. 75MB aufwärts

Was sind denn die größten Einzeldateien? Bzw. deren Größe?
Sollte das Dateisystem parallele Zugriffe gestatten, so passt Parallel.For(Each).
Andernfalls und wenn mehrere Dateien gleichzeitig in den RAM passen, so würde ich 1 Producer zum Lesen vom Dateisystem in den RAM und Environment.ProcessorCount-Consumer zur Prüfsummenberechnung verwenden.

Mit .NET Core, Pipelines, Span lassen sich auch viele Allokationen vermeiden, so dass der GC weniger Arbeit hat und mehr Ressourcen für die eigentliche Arbeit zur Verfügung stehen.

Unabhängig davon wundert es mich schon dass es scheinbar kein OS-eigenes od. fremdes Tool gibt, welches diese Aufgabe erledigen kann.

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"

Taipi88 Themenstarter:in
1.029 Beiträge seit 2010
vor 4 Jahren

Hi,

dass es keine Tools gibt ist noch nicht gesagt - ich wollte nur erst mal nachschauen, wie schnell Hashing eigentlich grundlegend ist. Waren im Test für die paar Algorithmen nur wenige Zeilen. (Bevor ich dazu verschiedene Software teste wollte ich erst mal schauen, ob Hashing und Prüfsummen in der Größenordnung überhaupt sinnvoll möglich ist)

Was die Nutzung von Span<byte> angeht - MD5, SHA1 und noch einige Andere arbeiten direkt mit einem Stream - dem aktuellen Code von CoreFX entsprechend wird hier bereits intern mit ReadOnlySpan<byte> gearbeitet. (Adler32 aus der SharpZipLib müsste ich hier ggf noch anpassen)

Die größten Dateien sind 30-80GB groß - was die Parallelisierung angeht: Davon hat das Programm massiv profitiert - ich müsste allerdings noch austesten wie viel Parallelität denn tatsächlich angebracht ist. (wie bereits gesagt)

In anderen Worten: Falls ich das wirklich selbst machen muss - werde ich in diesem Fall sicherlich bei Parallel.ForEach bleiben und den Adler32-Algorithmus noch auf ReadOnlySpan<byte> anpassen.

Die Maschine selbst ist ein Windows Server 2016 - ein interessanter Kandidat den ich gestern noch gefunden hatte ist die fciv.exe von Microsoft - diese unterstützt zwar lediglich MD5 und SHA1 - allerdings beherrscht diese bereits das Speichern in einer XML-Datei. Praktisch wäre es also problemlos möglich sofern MD5/SHA1 genügen das alles mit einem winzigen PowerShellScript zu lösen, welches:
a) Alle Dateien die in der XML-DB sind verifiziert und per Mail reportet
b) Nach erfolgreichem Report ggf. neu hinzugekommene Dateien in die XML-DB einträgt

Was hier denke ich schwerlich machbar ist wird eine Partinionierung dieser Prüfung sein - auf diese Art würde nämlich wieder alles am Stück geprüft.

LG