SMB Caching

Mein Skript End2End File prüft die Erreichbarkeit von SMB-Servern durch regelmäßige Schreib/Lese-Zugriffe. Wussten Sie, dass Windows Clients mittlerweile auch Netzwerkzugriffe "cachen"? Das hat natürlich Auswirkungen auf Performancetests und erfordert gewisse Vorkehrungen.

Einfacher Test

Um die Auswirkungen zu zeigen, habe ich einen lesenden Zugriff auf einen Share gestartet:

PS C:\> 1..1 | %{measure-command {Get-Item \\server\share}} | Measure-Object -AllStats -Property totalmilliseconds

Count             : 1
Average           : 30,2331
Sum               : 30,2331
Maximum           : 30,2331
Minimum           : 30,2331
StandardDeviation : 0
Property          : TotalMilliseconds

Analog dazu habe ich in Wireshark dann einige Pakete gesehen, die komplett erklärbar waren.

Die per PowerShell gemessene Performance von 30ms passt in etwa, denn der initiale ARP-Request zählt erst mal nicht von von Paket 2 bei 1.420 bis Paket 19 bei 1.445 sind es ca. 25ms. Die eigentliche Transaktion benötigt insgesamt 19 Pakete.

100 mal Lesen

Nun habe ich den Check einfach erweitert:

PS C:\> 1..100 | %{measure-command {Get-Item \\server\share}} | Measure-Object -AllStats -Property totalmilliseconds

Count             : 100
Average           : 1,515896
Sum               : 151,5896
Maximum           : 38,6184
Minimum           : 0,6864
StandardDeviation : 4,35317630467453
Property          : TotalMilliseconds

Die Werte sind hier sehr irreführend, denn ein Mittelwert von 1,5ms für das Lesen eines Verzeichnisses ist schon sehr kurz. Ein Mitschnitt mit Wireshark bestätigt das Caching. Statt der 19 Pakete sehe ich nicht die 100fache Menge sondern die fast gleiche Information. Es fehlt das ARP-Paket und ein zusätzlicher SMB NEGO ist am Anfang zu vernachlässigen.

Der SMB-Client auf meinem Windows 11 Desktop hat hier also definitiv nicht 100mal die gleiche Anfrage gestellt sondern genau einmal und die folgenden 99 Anfragen kamen aus einem lokalen Cache.

Cache Recherche

Diese Verhalten ist natürlich genial, wenn Dateiserver weiter weg stehen (Latenzzeit z.B. zu Azure Files) oder eine Software die gleichen Informationen mehrfach liest und Caching so den Server und die Verbindung entlastet. Aber mich interessieren dabei natürlich folgende Dinge:

  • Cache Größe
    Wie groß kann den die Information werden, die Windows hier im Cache behält? Landet das im Hauptspeicher oder sogar als Cache auf dem Dateisystem=
  • Cache Dauer
    Wie lange werden die Informationen vorgehalten. Sind das nur wenige Sekunden oder länger und wie bestimmt Microsoft die Cache-Dauer. Vielleicht anhand der letzten Änderung der Quelle?
  • Update
    Wie reduzierte Microsoft das Risiko, dass ein Client auf seiner Seite auf veraltete Daten aus dem Cache zugreift, was z.B. bei dateibasierten Datenbanken (Microsoft Access) katastrophal enden könnte. Sind bestimmte Typen ausgeschlossen oder hat es etwas mit Datei-Sperren zu tun oder kann der Server den Client bei einer Änderung informieren?

All diese Fälle lassen sich nicht zuverlässig per Analyse ermitteln und daher bin ich erst mal auf die Suche nach anderen Quelle von Microsoft zum Verhalten des SMB-Cache gegangen und wurde fündig. Schon die PowerShell liefert mir auf dem Client jede Menge Einstellmöglichkeiten.

PS C:\> Get-SmbClientConfiguration | fl *cache*

DirectoryCacheEntriesMax    : 16
DirectoryCacheEntrySizeMax  : 65536
DirectoryCacheLifetime      : 10
FileInfoCacheEntriesMax     : 64
FileInfoCacheLifetime       : 10
FileNotFoundCacheEntriesMax : 128
FileNotFoundCacheLifetime   : 5

Eine Suche nach den Parametern führte mich direkt zu einer Microsoft Seite mit ausführlichen Details:

SMB Redirector Component Cache
https://www.der-windows-papst.de/wp-content/uploads/2022/03/SMB-Redirector-Component-Cache.pdf

Also habe ich im Sekundentakt gefragt und per Wireshark nachgeschaut, wann die Anfragen kommen.

1..60 `
| %{measure-command {Get-Item \\server\share};start-sleep -Seconds 1} `
| Measure-Object -AllStats -Property totalmilliseconds

Beim Filter auf den beim Zugriff erscheinenden "Create Request File" ist ein 10 Sekunden Intervall gut zu sehen:

Mein Client "liefert also bis zu 10 Sekunden die Daten aus dem Cache, die er schon hatte, ehe er sich wieder zur Quelle aufmacht. Das ist in den meisten Fällen auch unkritisch, da viele Dateien eh nur von einer Person gelesen und geschrieben werden und "intensivere" Dateizugriffe heute nicht mehr über SMB erfolgen sondern Änderungen differenziell (SharePoint/OneDrive) übertragen werden oder über eine Synchronisation (z.B. GIT) stattfindet.

Sicheres Lesen

Sollte aber eine Applikation intensiv mit Dateien arbeiten, dann sollte sie seit Windows 2008 Server/Windows 7 mit dem Cache umgehen können. Eine Applikation sollte aber nun nicht für ihre Belange den Cache auf dem Client generell abschalten, sondern alternative Wege einsetzen, die aber auch schon beim lokalen Storage oder ISCSI/SAN relevant waren. Wann immer ich ein Caching vermeiden möchte, um z.B. Daten transaktionsgesichert zu schreiben oder verteilte Zugriffe zu koordinieren, sollte ich dem Betriebssystem dies auch mitteilen oder mit informieren lassen. Dazu gibt es mehrere Möglichkeiten unter Windows.

Über entsprechende Flag kann ich auch beim Dateizugriff die Feinheiten anpassen.

  • FILE_FLAG_NO_BUFFERING
  • FILE_FLAG_WRITE_THROUGH

Wer z.B. aus seiner Applikation Daten schreibt und sicher sein möchte, dass diese auf der Disk gelandet sind, sollte das Flag:FILE_FLAG_WRITE_THROUGH setzen. Ansonsten könnten die zu schreibenden Blöcke noch einige Zeit im Schreibcache von Windows oder eine RAID-Controllers darauf warten, bis es gerade "passend" ist. Sie sollten diese Flags aber mit Bedacht einsetzen, denn es verzögert ihre Applikation, die nun bis zum Abschluss der Schreiboperation wartet.

Steuerung auf dem Share

Wenn Sie auf dem SMB-Server schauen, dann gibt es es auch dort eine Steuerungsmöglichkeit zum Caching.

Get-SmbShare | ft Name,Cachingmode -autosize

Name    CachingMode
----    -----------
ADMIN$       Manual
C$           Manual
IPC$         Manual

Mit Set-SmbShare können Sie den Wert auf einen der folgenden Optionen ändern:

None
Manual
Documents
Programs
BranchCache
Unknown"

Einen Teil der Optionen könnten Sie auch über die GUI im Windows Explorer einstellen.

Aber auch hier ist dann zu prüfen, welchen Einfluss diese Einstellung auf die Gesamtperformance hat, denn damit weise ich dann alle Clients an, wie sie sich mit diesem Share verhalten sollen.

Die Funktion ist übrigens nicht nur für Windows Server sondern auch andere NAS-Systeme, Samba-Systeme verfügbar und seit langem gibt es auch "WAN-Optimierer", die insbesondere in den frühen Jahren von "SMB over WAN" durch "Caching auf dem Netzwerk" die Performance von SMB merklich verbessert haben.

Schreiben statt Lesen

Wenn ich es mir erlauben kann, dann sollte ich für einen End2End File-Test daher nicht häufiger als alle 10 Sekunden eine Datei lesen, um passable Zahlen zu bekommen oder ich muss den Cache auf dem Client abschalten (unschön) oder einen eigenen Shared ohne Caching einrichten, was auch nicht schön ist. Eine weitere Option wäre natürlich den Schreibzugriff zu messen. Hier kann ich sehr einfach auch "synchron" schreiben und damit bessere Messwerte erhalten. Per PowerShell ist das schnell gemacht:

1..60 `
| %{measure-command {"" | out-file \\server\share\test.txt};start-sleep -Seconds 1} `
| Measure-Object -AllStats -Property totalmilliseconds

Count             : 60
Average           : 12,0639133333333
Sum               : 723,8348
Maximum           : 24,6705
Minimum           : 6,5228
StandardDeviation : 2,78218508708574
Property          : TotalMilliseconds

Im Wireshark ist auch gut zu sehen, dass jede Sekunde auch tatsächlich ein Schreibzugriffe erfolgt.

Hier gibt es kein Caching des SMB-Clients, obwohl der Inhalt der Dateien immer gleich ist. Allerdings dauert der Schreibzugriff natürlich etwas länger als ein Lesen aus dem Server-Cache und belastet den Server auch mehr. Insbesondere mit vielen Clients kann das doch einen Einfluss haben.

Viele Administratoren werden sich aber noch eher damit unwohl fühlen, wenn eine weitere Dateifreigabe mit Schreibzugriff für "Everybody", Anonymous o.ä. freizugeben, über die vielleicht Anwender auch Dateien tauschen und Daten ablegen. Theoretisch könnte ein Skript natürlich ins "Home-Verzeichnis" des Benutzers schreiben und lesen. Für End2End File und andere sollte man als Betreiber aber überlegen, welche Prüfungen ein Client und welche ein Server selbst durchführen sollte. Ob eine Festplatte oder LUN langsam ist, kann ich auf dem Server meist besser, kontinuierlicher und unabhängig vom Client überprüfen. Der Client kann sich daher auf gelegentliches Lesen oder TCP/ICMP-Tests zur Verbindungsüberwachung beschränken.

Share Caching

Zuletzt wollte ich noch wissen, ob das Caching nur Dateien oder auch z.B. eine Share betrifft, und ob es auch einen negativen Cache gibt. Ich habe daher mehrere Share-Zugriffe getestet.

{measure-command {Get-Item \\server\share}} | Measure-Object -AllStats -Property totalmilliseconds

Ich habe den Aufruf jede Sekunde wiederholt und die erste Verzögerung und die folgenden Verzögerungen gemessen, bis es wieder "länger" gedauert hat. Irgendwann muss ja auch der Cache veraltet sein und eine neue Anfrage anfordern.

Szenario Parameter 1. Aufruf 2. Aufruf Reset

Ungültiger Server

\\noserver\noshare

5500ms

13ms

ca. 30 Sek

Server aber kein Share

\\server\noshare

300ms

200ms

nie

Server aber keine Rechte

\\server\nopermission

38ms

9ms

nie

Server und valider Share

\\server\validshare

20ms

1ms

nie

Hier ist interessant, dass es es wohl einen negativen Cache bei ungültigen Servernamen (WINS/DNS) gibt. Die Abfrage eines ungültigen Share dauert aber immer länger als ich es erwartet hätte während die Antwort auf eine gültige Freigabe bei den Folgeaufrufen sehr schnell kommt. Allerdings scheint auch hier der Server die Auswertung der ACLs nicht zu cachen oder zu drosseln. Ich habe nun nicht die CPU-Last des Servers bei dieser Aktion überprüft.

Ich kann hier aber weder den "DirectoryCacheLifetime = 10 Sek" noch den "FileInfoCacheLifetime =10 Sek" meines SMB-Clients nachvollziehen. Die Namensauflösung hat einen Negativ-Cache von ca. 30 Sekunden aber der langsamere erste Aufruf ist später nicht mehr zu sehen, so dass ich hier nur eine Optimierung beim Server sehe aber nicht auf dem Client.

Einschätzung

Vielleicht haben Sie schon häufiger gesehen, dass ein Anwender eine Datei auf einem Dateiserver ablegt und ein Kollege die Datei einige Zeit noch nicht sieht. Dann wissen sie nun, dass das Speichern auf dem Server sofort passiert aber der Kollege dank Cache bis zu 10 Sekunden veraltete Daten sieht. Deswegen sollten Sie nicht generell das Caching auf der Dateifreigabe oder sogar auf dem Client deaktivieren. Caching ist eine wichtige Komponente die gefühlte Performance zu verbessern und die Server zu entlasten. 10 Sekunden ist aus meiner Sicht nicht lang und in Zeiten der Cloud und Client/Server-Datenbanken wie SQL und Webservices gibt es immer weniger Dienste, die wirklich noch über SMB-Freigaben gemeinsame Dateien nutzen. Allerdings sollten die Programme dann schon um die Funktion des "Caching" wissen und mit "FILE_FLAG_WRITE_THROUGH" bei kritischen Daten durchschreiben.

Für meine End2End-Tests bedeutet dies, dass bei den Standardeinstellungen zwei aufeinanderfolgende Lesezugriffe mindestens 10 Sekunden voneinander entfernt sein sollten und kein anderer Prozess die gleiche Datei liest, weil auch das den Cache füllt. Zusätzlich könnte End2End viel zu schnelle und unmögliche Antworten besser verwerfen als die Messwerte zu verfälschen.

Weitere Links