12.13. Harde schijven optimaliseren

12.13.1. Sysctl-variabelen

12.13.1.1. vfs.vmiodirenable

De sysctl-variabele vfs.vmiodirenable kan de waarde 0 (uit) of 1 (aan) hebben. De standaardwaarde is 1. Deze variabele bepaalt hoe mappen door het systeem in een cache bewaard worden. De meeste mappen zijn klein en gebruiken slechts een klein fragment (typisch 1 K) in het bestandssysteem en nog minder (typisch 512 bytes) in de buffercache. Als deze variabele uit staat (op 0) bewaart de buffercache slechts een bepaald aantal mappen in de cache, ook al is er een overvloed aan geheugen beschikbaar. Wanneer deze aan staat (op 1), wordt de VM paginacache gebruikt, waardoor voor het cachen van mappen al het geheugen kan worden gebruikt. Het is echter wel zo dat het minimale in-core geheugen dat gebruikt wordt om een map te cachen in dat geval de fysieke paginagrootte is (typisch 4 K) in plaats van 512  bytes. Het is aan te raden deze optie aan te laten staan als gebruik gemaakt wordt van diensten die met grote aantallen bestanden werken, zoals webcaches, grote mailsystemen en newsservers. Als deze optie aan blijft staan, verlaagt die de prestaties niet, ook al kost het meer geheugen. Door experimenteren is dit voor een systeem na te gaan.

12.13.1.2. vfs.write_behind

De sysctl-variabele vfs.write_behind staat standaard aan (1). Dit betekent dat het bestandssysteem gegevens naar het medium gaat schrijven op het moment dat er een volledig cluster aan gegevens verzameld is. Dit is meestal het geval bij het schrijven van grote sequentiële bestanden. Het idee is om te voorkomen dat de buffercache verzadigd raakt met vuile buffers zonder dat dit bijdraagt aan de I/O-prestaties. Dit kan echter processen ophouden en onder sommige omstandigheden is het wellicht beter deze sysctl uit te zetten.

12.13.1.3. vfs.hirunningspace

De sysctl-variabele vfs.hirunningspace bepaalt hoeveel nog te schrijven gegevens er in het complete systeem op elk moment in de wachtrij naar schijfcontrollers mag staan. De standaardwaarde is meestal voldoende, maar op machines met veel schijven, is het beter deze te verhogen naar vier of vijf megabyte. Het instellen van een te hoge waarde (groter dan de schrijfdrempel van de buffercache) kan leiden tot zeer slechte prestaties bij clustering. Stel deze waarde niet arbitrair hoog in! Hogere schrijfwaarden kunnen vertraging veroorzaken in het lezen, als dit tegelijk plaatsvindt.

Er zijn verscheidene andere sysctl's voor buffercache en VM-pagecache. Het wordt afgeraden deze te wijzigen. Het VM-systeem is zeer goed in staat zichzelf automatisch te optimaliseren.

12.13.1.4. vm.swap_idle_enabled

De sysctl-variabele vm.swap_idle_enabled is nuttig in grote meergebruikersystemen met veel gebruikers die af- en aanmelden en veel onbenutte processen. Dergelijke systemen hebben de neiging om voortdurend de vrije geheugenreserves onder druk te zetten. Het is mogelijk om de prioriteit van geheugenpagina's die verband houden met onbenutte processen sneller te laten dalen dan met het normale pageout-algoritme, door deze sysctl aan te zetten en via vm.swap_idle_threshold1 en vm.swap_idle_threshold2 de swapout hysterese (in seconden onbenut) af te stemmen. Deze optie dient alleen gebruikt te worden als ze echt nodig is, want de andere kant van de medaille is dat dit eerder pre-page geheugen inhoudt in plaats van later, waardoor het meer wisselbestand- en schijfbandbreedte kost. In een klein systeem heeft deze optie een voorspelbaar effect, maar in grote systemen waar al sprake is van een matige paging kan deze optie het mogelijk maken voor het VM-systeem om hele processen gemakkelijk in en uit het geheugen te halen.

12.13.1.5. hw.ata.wc

Ten tijde van FreeBSD 4.3 is er geflirt met het uitzetten van IDE-schrijfcaching. Hierdoor neemt de bandbraadte naar IDE-schijven af, maar het werd als noodzakelijk beschouwd vanwege ernstige problemen met gegevensinconsistentie die door harde schijfproducenten geëintroduceerd waren. Het probleem is dat IDE-schijven niet de waarheid vertellen over wanneer een schrijfactie klaar is. Door IDE-schrijfcaching wordt data niet alleen ongeordend geschreven, maar soms kan zelfs het schrijven van sommige blokken voortdurend uitgesteld worden als er sprake is van een hoge schijfbelasting. Een crash of stroomstoring kan dan ernstige corruptie aan het bestandssysteem veroorzaken. Daarom werd de standaardinstelling van FreeBSD voor alle zekerheid gewijzigd. Helaas was het resultaat een groot verlies aan prestaties en na die uitgave is de standaardwaarde weer terug veranderd. Met de sysctl-variabele hw.ata.wc kan gecontroleerd worden of schrijfcaching aan of uit staat. Als schrijfcaching uit staat, kan het die weer aangezet worden door hw.ata.wc op 1 te zetten. Aangezien dit een kernelvariabele is, moet deze ingesteld worden vanuit de bootloader tijdens het opstarten. Nadat de kernel eenmaal opgestart is, heeft het wijzigen van deze sysctl geen effect.

Meer informatie staat in ata(4).

12.13.1.6. SCSI_DELAY (kern.cam.scsi_delay)

De kernelinstelling SCSI_DELAY kan gebruikt worden om de opstarttijd te versnellen. De standaardwaarde is nogal hoog en kan 15 seconden vertraging veroorzaken. Met modernere SCSI-systemen is 5 seconden al voldoende (zeker met moderne schijven). De kern.cam.scsi_delay opstart variabele moet hier gebruikt worden. De variabele en kernelconfiguratie-optie accepteren waarden uitgedrukt in milliseconden en niet in seconden.

12.13.2. Softupdates

tunefs(8) kan gebruikt worden om een bestandsysteem nauwkeurig af te stellen. Het heeft veel opties, maar nu wordt alleen het aan- en uitzetten van softupdates besproken. Dat gaat als volgt:

# tunefs -n enable /filesystem
# tunefs -n disable /filesystem

Een bestandssysteem kan niet met tunefs(8) gewijzigd worden als het aangekoppeld is. Softupdates aanzetten wordt dus in het algemeen gedaan vanuit enkelegebruikermodus, voordat partities aangekoppeld zijn.

Softupdates zorgen voor een drastische verbetering van de prestaties met betrekking tot metagegevens, met name het aanmaken en verwijderen van bestanden, door gebruik van een geheugencache. Het wordt dan ook aangeraden om op alle bestandssystemen softupdates te gebruiken. Er zijn twee nadelen aan softupdates: softupdates garanderen een consistent bestandssysteem in geval van een crash, maar het kan makkelijk enkele seconden (zelfs een minuut) achter liggen met het daadwerkelijk bijwerken op de fysieke harde schijf. Als een systeem crasht gaat wellicht meer werk verloren dan anders het geval zou zijn. Daarnaast vertragen softupdates het vrijgeven van bestandssysteemblokken. Als een bestandssysteem (zoals de rootpartitie) bijna vol is, dan kan het verrichten van een grote update, zoals make installworld, ertoe leiden dat het bestandssysteem ruimtegebrek krijgt en dat daardoor de operatie mislukt.

12.13.2.1. Meer over softupdates

Er zijn traditioneel twee methodes om de metagegevens van een bestandssysteem terug naar de schijf te schrijven. Het bijwerken van metagegevens houdt het bijwerken van van niet-inhoudelijke gegevens zoals inodes of mappen in.

Historisch gezien was het gebruikelijk om updates aan metagegevens synchroon weg te schrijven. Als een map bijvoorbeeld gewijzigd was, wachtte het systeem totdat de verandering daadwerkelijk naar de schijf geschreven was. De gegevensbuffers (de inhoud van een bestand) werden doorgeschoven naar de buffercache en op een later moment asynchroon op de schijf opgeslagen. Het voordeel van deze benadering is dat ze altijd veilig is. Als het systeem faalt tijdens het bijwerken, zijn de metagegevens nog altijd consistent. Een bestand kan volledig gecreëerd zijn of helemaal niet. Als de gegevensblokken van een bestand nog niet van de buffercache naar de schijf geschreven zijn ten tijde van de crash, is fsck(8) in staat om dit te herkennen en het bestandssysteem te repareren door de lengte van het bestand nul te maken. Deze implementatie is ook helder en eenvoudig. Het nadeel is echter dat het wijzigen van metagegevens een traag proces is. Een rm -r benadert bijvoorbeeld alle bestanden in een map sequentiëel, maar elke mapverandering (verwijderen van een bestand) wordt synchroon naar de schijf geschreven. Dit omvat ook het bijwerken van de map zelf, van de inodetabel en mogelijk ook van indirecte blokken die voor het bestand in kwestie zijn gealloceerd. Gelijksoortige processen spelen zich af bij een commando als tar -x, waarbij een grote bestandshiëearchie wordt uitgepakt.

De tweede mogelijkheid is om het bijwerken van metagegevens asynchroon weg te schrijven. Dit is standaard in Linux®/ext2fs en als een *BSD UFS-bestandssysteem met mount -o async aangekoppeld is, is de werking hetzelfde. Alle bijwerkingen aan metagegevens worden eenvoudigweg doorgegeven aan de buffercache en vermengd met inhoudelijke updates van de bestandsgegevens. Het voordeel is een grote winst aan snelheid, omdat er niet telkens gewacht hoeft te worden op het bijwerken van metagegevens tot deze daadwerkelijk naar de schijf geschreven zijn. De implementatie is ook in dit geval helder en eenvoudig. Het grote nadeel is uiteraard dat er geen enkele garantie is voor de consistentie van het bestandssysteem. Als het systeem faalt tijdens een operatie waarbij veel metagegevens worden bijgewerkt (bijvoorbeeld door een stroomstoring of iemand drukt op de resetknop), blijft het bestandssysteem in een onvoorspelbare toestand achter. Er is geen mogelijkheid om de toestand van het bestandssysteem te onderzoeken als het systeem weer opstart, want de gegevensblokken van een bestand kunnen al weggeschreven zijn geweest terwijl het wegschrijven van bijwerkingen aan de inodetabel of de bijhorende map nog niet plaats heeft gevonden. Het is zelfs onmogelijk om een fsck te implementeren die de overgebleven chaos kan opruimen: de benodigde informatie is gewoon niet volledig aanwezig op de schijf. Als een bestandssysteem op deze manier onherstelbaar beschadigd is, is de enige optie newfs(8) te gebruiken en vervolgens te herstellen van een back-up.

De gebruikelijke oplossing voor dit probleem is het implementeren van dirty region logging, ook wel journaling genoemd, hoewel deze term niet consistent gebruikt wordt en soms ook wordt gebruikt voor andere vormen van transactielogging. Het bijwerken van metagegevens wordt nog steeds synchroon geschreven, maar slechts naar een klein gebied van de schijf. Later worden ze dan naar de juiste locatie verplaatst. Omdat het loggebied klein is, hoeven de koppen van de schijf zelfs tijdens schrijfintensieve operaties nog maar over een kleine fysieke afstand te bewegen en door deze snellere respons zijn dit soort operaties sneller dan op de traditionele manier. De extra complexiteit van de implementatie is nogal beperkt, dus het risico van introductie van extra bugs valt mee. Een nadeel is dat alle metagegevens tweemaal geschreven worden (eerst naar het loggebied en later nog eens naar de definitieve locatie). Dus bij normaal gebruik kan er sprake zijn van wat men wel noemt een “performance pessimization”. Anderzijds kunnen in geval van een crash alle nog uitstaande metagegevensoperaties snel worden teruggedraaid of vanuit het loggebied alsnog worden afgemaakt wanneer de machine weer opstart. Het bestandssysteem start dan snel op.

Kirk McKusick, de vader van het Berkeley FFS, loste dit probleem op met softupdates, wat betekent dat alle uitstaande acties voor het bijwerken van metagegevens in het geheugen bewaard worden en dan geordend naar de schijf geschreven worden. Dit heeft het gevolg dat in geval van intensieve operaties met betrekking tot metagegevens, latere bijwerkingen aan een item eerdere bewerkingen opvangen (“catch”) als deze nog in het geheugen zitten en nog niet weggeschreven waren. Dus alle operaties, op bijvoorbeeld een map, worden in het algemeen eerst in het geheugen uitgevoerd voordat er wordt bijgewerkt naar schijf. De gegevensblokken worden geordend conform hun positie, zodat ze nooit weggeschreven worden voordat hun metagegevens geschreven zijn. Als het systeem een crash ondervindt, veroorzaakt dat impliciet het terugdraaien van uitstaande operaties (“log rewind”): alle operaties die nog niet weggeschreven waren lijken nooit gebeurd te zijn. Zo wordt een consistent bestandssysteem in stand gehouden dat eruit ziet alsof het 30 tot 60 seconden eerder was. Het gebruikte algoritme garandeert dat alle bronnen die in gebruik zijn als zodanig gemarkeerd worden in hun daarvoor geschikte bitmaps: blokken en inodes. Na een crash is de enige allocatiefout die kan optreden dat bronnen gemarkeerd kunnen zijn als in gebruik (“used”), terwijl ze feitelijk alweer beschikbaar (“free”) zijn. fsck(8) herkent deze situatie en stelt dergelijke vrij te maken bronnen opnieuw beschikbaar. Het is volkomen veilig om na een crash te negeren dat het bestandssysteem niet schoon is en het tot aankoppelen te dwingen met mount -f. Om niet langer gebruikte bronnen vrij te maken moet later fsck(8) uitgevoerd worden. Dit is dan ook het idee achter background fsck: op het moment dat het systeem aan het opstarten is, wordt er alleen een snapshot van het systeem bewaard. fsck kan later uitgevoerd worden. Alle bestandssystemen kunnen “dirty” aangekoppeld worden en het systeem kan gewoon verder opstarten naar meergebruikermodus. Vervolgens zijn er fscks gepland die in de achtergrond draaien voor elk bestandssysteem dat niet schoon is en waarmee bezette bronnen vrijgegeven worden. Bestandssystemen die geen gebruik maken van softupdates moeten echter nog steeds gebruik maken van de normale fsck in de voorgrond.

Het voordeel van softupdates is dat operaties op metagegevens bijna net zo snel zijn als asynchrone updates (dat wil zeggen sneller dan met logging, waarbij de metagegevens keer op keer geschreven worden). Nadelen zijn de complexiteit van de code (wat een groter risico op bugs impliceert in een gebied dat bijzonder gevoelig is voor verlies van gebruikersgegevens) en een groter geheugenverbruik. Tevens moet de gebruiker wennen aan enkele eigenaardigheden. Na een crash lijkt de toestand van het bestandssysteem wat “ouder”. In situaties waar de standaard synchrone benadering een aantal lege bestanden zou hebben achtergelaten na fsck, is het met softupdates juist zo dat dergelijke bestanden er helemaal niet zijn, omdat de metagegevens of de bestandsinhoud nooit naar de schijf zijn geschreven. Schijfruimte wordt pas vrijgegeven als de bijwerkingen aan metagegevens en inhoudelijke bestandsgegevens weggeschreven zijn, wat mogelijk pas enige tijd na het uitvoeren van rm plaatsvindt. Dit kan problemen veroorzaken als er grote hoeveelheden gegevens naar een bestandssysteem geschreven worden dat onvoldoende vrije ruimte heeft om alle bestanden twee keer te kunnen bevatten (bijvoorbeeld in /tmp).