Haltbar Datelagerung a Linux Datei APIen

Wärend der Nohaltegkeet vun der Datespäicherung an de Cloudsystemer recherchéiert hunn, hunn ech beschloss mech selwer ze testen fir sécher ze stellen datt ech d'Basis Saache verstanen hunn. ech ugefaang andeems Dir d'NVMe Spezifizéierung gelies hutt Fir ze verstoen wat Garantien betreffend nohalteg Datelagerung (dat heescht, garantéiert datt d'Donnéeën no engem Systemfehler verfügbar sinn) gitt eis NMVe Disken. Ech hunn déi folgend Haaptconclusiounen gemaach: Date musse beschiedegt ugesi ginn aus dem Moment wou de Kommando fir Daten ze schreiwen gëtt bis de Moment wou se op d'Späichermedium geschriwwe ginn. Wéi och ëmmer, déi meescht Programmer benotze ganz glécklech System Appellen fir Daten opzehuelen.

An dësem Beitrag entdecken ech déi persistent Späichermechanismen, déi vun de Linux Datei APIs geliwwert ginn. Et schéngt, datt alles hei einfach soll sinn: de Programm rifft de Kommando write(), an nodeems dëse Kommando fäerdeg ass, ginn d'Donnéeën sécher op Disk gespäichert. Mee write() kopéiert nëmmen Uwendungsdaten an de Kernel Cache, deen am RAM läit. Fir de System ze zwéngen Daten op Disk ze schreiwen, musst Dir e puer zousätzlech Mechanismen benotzen.

Haltbar Datelagerung a Linux Datei APIen

Am Allgemengen ass dëst Material eng Sammlung vun Notizen am Zesummenhang mat deem wat ech geléiert hunn iwwer en Thema dat fir mech interesséiert ass. Wa mir ganz kuerz iwwer dat Wichtegst schwätzen, stellt sech eraus datt fir nohalteg Datelagerung ze organiséieren musst Dir de Kommando benotzen fdatasync() oder opmaachen Dateien mam Fändel O_DSYNC. Wann Dir interesséiert sidd méi ze léieren iwwer wat mat Daten op sengem Wee vu Code op Disk geschitt, kuckt w.e.g dat Artikel.

Features vun der Benotzung vun der Schreiwen () Funktioun

System Opruff write() am Standard definéiert IEEE POSIX als Versuch Donnéeën zu engem Fichier Descriptor ze schreiwen. No erfollegräich Ofschloss write() D'Dateliesoperatioune musse genau d'Bytes zréckginn, déi virdru geschriwwe goufen, dëst maachen och wann d'Donnéeën vun anere Prozesser oder Threads zougänglech sinn (kuck relevant Sektioun vum POSIX Standard). et ass, an der Rubrik iwwer wéi Threads mat normale Dateioperatioune interagéieren, gëtt et eng Notiz déi seet datt wann zwee Threads all dës Funktiounen uruffen, da muss all Uruff entweder all designéiert Konsequenze vum aneren Uruff gesinn, oder guer keng. Konsequenzen. Dëst féiert zu der Conclusioun datt all Datei-I / O-Operatiounen e Spär op d'Ressource halen, déi se operéieren.

Heescht dat, datt d'Operatioun write() ass et atomar? Aus enger technescher Siicht, jo. Donnéeën liesen Operatiounen mussen entweder alles oder näischt vun deem zréckginn wat mat geschriwwe gouf write(). Awer Operatioun write(), no der Norm, muss net onbedéngt ophalen alles opzeschreiwen, wat et gefrot gouf opzeschreiwen. Si däerf nëmmen en Deel vun den Donnéeën schreiwen. Zum Beispill kënne mir zwee Threads hunn, déi all 1024 Bytes op eng Datei mat deemselwechte Dateideskriptor beschriwwen hunn. Aus der Siicht vum Standard ass en akzeptabelt Resultat wann all Schreifoperatioun nëmmen ee Byte an d'Datei ka addéieren. Dës Operatioune bleiwen atomarer, awer nodeems se ofgeschloss sinn, ginn d'Donnéeën, déi se an d'Datei geschriwwen hunn, gemëscht. hei ganz interessant Diskussioun iwwer dëst Thema op Stack Overflow.

fsync () an fdatasync () Funktiounen

Deen einfachste Wee fir Daten op Disk ze spülen ass d'Funktioun ze ruffen fsync(). Dës Funktioun freet de Betribssystem fir all modifizéiert Blocks vum Cache op Disk ze transferéieren. Dëst beinhalt all Dateimetadaten (Zougangszäit, Dateimodifikatiounszäit, a sou weider). Ech gleewen datt dës Metadaten selten gebraucht ginn, also wann Dir wësst datt et Iech net wichteg ass, kënnt Dir d'Funktioun benotzen fdatasync(). d' hëllefen Op der fdatasync() Et gëtt gesot datt während der Operatioun vun dëser Funktioun sou eng Quantitéit u Metadaten op Disk gespäichert gëtt, déi "néideg ass fir déi korrekt Ausféierung vun de folgenden Dateliesoperatiounen." An dat ass genee wat déi meescht Uwendungen këmmeren.

Ee Problem deen hei ka entstoen ass datt dës Mechanismen net garantéieren datt d'Datei no engem méiglechen Ausfall entdeckt gëtt. Besonnesch wann Dir eng nei Datei erstellt, musst Dir ruffen fsync() fir de Verzeechnes deen et enthält. Soss, no engem Feeler, kann et erausstellen datt dës Datei net existéiert. De Grond dofir ass datt an UNIX, duerch d'Benotzung vun haarde Linken, eng Datei a verschidde Verzeichnisser existéiere kann. Dofir, wann Dir rufft fsync() et gëtt kee Wee fir eng Datei ze wëssen, wéi eng Verzeechnesdaten och op Disk gespullt ginn (hei Dir kënnt méi iwwer dëst liesen). Et gesäit aus wéi wann den ext4 Dateisystem fäeg ass automatesch zoutrëfft fsync() an d'Verzeichnisser déi entspriechend Dateien enthalen, awer dëst ass vläicht net de Fall mat anere Dateiesystemer.

Dëse Mechanismus kann anescht op verschiddene Dateiesystemer ëmgesat ginn. Ech benotzt blktrace fir ze léieren iwwer wéi eng Diskoperatiounen an ext4 an XFS Dateisystemer benotzt ginn. Béid ginn reegelméisseg Schreifbefehle op Disk fir souwuel den Dateiinhalt wéi och den Dateiesystemjournal aus, spülen de Cache, an fuert aus andeems Dir e FUA ausféiert (Force Unit Access, Daten direkt op Disk schreiwen, de Cache ëmgoen) Schreift an de Journal. Si maachen dëst wahrscheinlech fir ze bestätegen datt d'Transaktioun stattfonnt huet. Op Drive déi FUA net ënnerstëtzen, verursaacht dëst zwee Cache-Spülen. Meng Experimenter hunn dat gewisen fdatasync() e bësse méi séier fsync(). Utility blktrace weist dat un fdatasync() schreift normalerweis manner Daten op Disk (an ext4 fsync() schreift 20 KiB, an fdatasync() - 16 KiB). Och hunn ech erausfonnt datt XFS liicht méi séier ass wéi ext4. An hei mat der Hëllef blktrace gelongen dat erauszefannen fdatasync() spült manner Daten op Disk (4 KiB an XFS).

Eendeiteg Situatiounen déi entstinn wann Dir fsync () benotzt

Ech kann un dräi zweedeiteg Situatiounen denken fsync()déi ech an der Praxis begéint hunn.

Déi éischt esou Fall ass am Joer 2008 geschitt. Dann ass de Firefox 3-Interface gefruer wann eng grouss Zuel vu Dateien op Disk geschriwwe goufen. De Problem war datt d'Ëmsetzung vun der Interface eng SQLite Datebank benotzt huet fir Informatioun iwwer säi Staat ze späicheren. No all Ännerung, déi am Interface geschitt ass, gouf d'Funktioun genannt fsync(), déi gutt Garantien fir stabil Datelagerung ginn huet. Am ext3 Dateisystem dann benotzt, d'Funktioun fsync() all "dreckeg" Säiten am System op Disk gedumpt, an net nëmmen déi, déi mat der entspriechender Datei verbonne waren. Dëst bedeit datt wann Dir e Knäppchen am Firefox klickt, kéint Megabytes vun Daten ausléisen fir op eng magnetesch Scheif ze schreiwen, wat vill Sekonnen dauere kéint. D'Léisung vum Problem, souwäit ech verstinn aus et Material war Aarbecht mat der Datebank ze asynchronous Hannergrond Aufgaben Transfert. Dëst bedeit datt Firefox virdru méi streng Späicherfuerderunge implementéiert huet wéi wierklech gebraucht gouf, an d'Features vum ext3 Dateiesystem hunn dëse Problem nëmmen verschäerft.

Den zweete Problem ass am Joer 2009 geschitt. Duerno, no engem System Crash, hunn d'Benotzer vum neie ext4 Dateiesystem mat der Tatsaach konfrontéiert datt vill nei erstallt Dateien null Längt haten, awer dëst ass net geschitt mat dem eelere ext3 Dateiesystem. Am virege Paragraphe hunn ech geschwat wéi ext3 ze vill Daten op Disk gespullt huet, wat d'Saache vill verlangsamt huet. fsync(). Fir d'Situatioun ze verbesseren, ginn an ext4 nëmmen déi dreckeg Säiten, déi fir eng bestëmmte Datei relevant sinn, op den Disk gespullt. An Daten aus anere Fichier bleiwen an Erënnerung fir eng vill méi Zäit wéi mat ext3. Dëst gouf gemaach fir d'Leeschtung ze verbesseren (par défaut bleiwen d'Donnéeën an dësem Zoustand fir 30 Sekonnen, Dir kënnt dëst konfiguréieren dirty_expire_centisecs; hei Dir kënnt zousätzlech Material iwwer dëst fannen). Dëst bedeit datt eng grouss Quantitéit un Donnéeën no engem Feeler irretrievably verluer kënne ginn. D'Léisung fir dëse Problem ass ze benotzen fsync() an Uwendungen déi stabil Datelagerung musse garantéieren an se sou vill wéi méiglech virun de Konsequenze vu Feeler schützen. Funktioun fsync() funktionnéiert vill méi effizient wann Dir ext4 benotzt wéi wann Dir ext3 benotzt. Den Nodeel vun dëser Approche ass datt seng Notzung, wéi virdrun, d'Ausféierung vun e puer Operatiounen verlangsamt, wéi d'Installatioun vu Programmer. Gesinn Detailer iwwer dëst hei и hei.

Déi drëtt Problem betreffend fsync(), entstanen am Joer 2018. Dann, am Kader vum PostgreSQL Projet, gouf festgestallt datt wann d'Funktioun fsync() e Feeler begéint, et markéiert "dreckeg" Säiten als "propper". Als Resultat, déi folgend Appellen fsync() Si maachen näischt mat esou Säiten. Dofir ginn modifizéiert Säiten an der Erënnerung gespäichert a ginn ni op Disk geschriwwe. Dëst ass eng richteg Katastroph, well d'Applikatioun mengt datt e puer Daten op der Disk geschriwwe sinn, awer tatsächlech wäert et net sinn. Esou Feeler fsync() rar sinn, kann d'Applikatioun an esou Situatiounen bal näischt maachen de Problem ze bekämpfen. Dës Deeg, wann dëst geschitt, Crash PostgreSQL an aner Uwendungen. et ass, am Material "Kënnen Uwendungen aus fsync Feeler recuperéieren?", gëtt dëse Problem am Detail exploréiert. De Moment ass déi bescht Léisung fir dëse Problem direkten I / O mam Fändel ze benotzen O_SYNC oder mat engem Fändel O_DSYNC. Mat dëser Approche wäert de System Feeler mellen, déi während spezifesche Schreifoperatioune kënne geschéien, awer dës Approche erfuerdert d'Applikatioun fir d'Puffer selwer ze managen. Liest méi iwwer dëst hei и hei.

Dateien opmaachen mat den O_SYNC an O_DSYNC Fändelen

Loosst eis zréck op d'Diskussioun vu Linux Mechanismen déi stabil Datelagerung ubidden. Mir schwätzen nämlech iwwer de Fändel ze benotzen O_SYNC oder Fändel O_DSYNC wann Dir Dateien opmaacht mat Systemruff oppen (). Mat dëser Approche gëtt all Daten Schreifoperatioun gemaach wéi no all Kommando write() de System gëtt Kommandoen entspriechend fsync() и fdatasync(). d' POSIX Spezifikatioune dëst nennt een "Synchroniséierter I/O Dateiintegritéitsfähegkeet" an "Datenintegritéitsfäegkeet". Den Haaptvirdeel vun dëser Approche ass datt fir d'Datenintegritéit ze garantéieren, musst Dir nëmmen ee Systemruff maachen, anstatt zwee (zum Beispill - write() и fdatasync()). Den Haaptnodeel vun dëser Approche ass datt all Schreiwen mat dem entspriechende Dateideskriptor synchroniséiert ginn, wat d'Fäegkeet limitéiere kann fir den Applikatiounscode ze strukturéieren.

Benotzt Direct I/O mam O_DIRECT Fändel

System Opruff open() ënnerstëtzt Fändel O_DIRECT, déi entwéckelt ass fir de Betribssystem-Cache ze ëmgoen fir I/O-Operatiounen auszeféieren andeems se direkt mat der Disk interagéieren. Dëst, a ville Fäll, bedeit datt Schreifbefehle vum Programm ausgestallt ginn direkt an Kommandoen iwwersat ginn fir mat der Disk ze schaffen. Mä, am Allgemengen, ass dëse Mechanismus keen Ersatz fir Funktiounen fsync() oder fdatasync(). D'Tatsaach ass, datt d'Disk selwer kann defer oder Cache entspriechend Daten Schreiwen Kommandoen. An, fir d'Saache méi schlëmm ze maachen, an e puer spezielle Fäll sinn d'I / O Operatiounen déi duerchgefouert ginn wann Dir de Fändel benotzt O_DIRECT, Emissioun an traditionell gebufferten Operatiounen. Deen einfachste Wee fir dëse Problem ze léisen ass de Fändel ze benotzen fir Dateien opzemaachen O_DSYNC, wat bedeit datt all Schreifoperatioun vun engem Opruff gefollegt gëtt fdatasync().

Et huet sech erausgestallt datt den XFS Dateisystem viru kuerzem e "schnell Wee" fir O_DIRECT|O_DSYNC-Datenopnam. Wann e Block iwwerschriwwe gëtt mat O_DIRECT|O_DSYNC, dann XFS, amplaz de Cache ze spülen, wäert de FUA Schreifbefehl ausféieren wann den Apparat et ënnerstëtzt. Ech hunn dëst verifizéiert andeems Dir den Utility benotzt blktrace op engem Linux 5.4/Ubuntu 20.04 System. Dës Approche sollt méi effizient sinn, well wann se benotzt gëtt, gëtt e minimale Betrag vun Daten op d'Disk geschriwwe an eng Operatioun benotzt, anstatt zwee (de Cache schreiwen an ze spülen). Ech hunn e Link fonnt Patch 2018 Kernel, deen dëse Mechanismus implementéiert. Et gëtt eng Diskussioun do iwwer d'Applikatioun vun dëser Optimisatioun op aner Dateiesystemer, awer souwäit ech weess, ass XFS deen eenzegen Dateiesystem deen dëst bis elo ënnerstëtzt.

sync_file_range () Funktioun

Linux huet e System Uruff sync_file_range(), wat Iech erlaabt nëmmen en Deel vun der Datei op Disk ze spülen, anstatt déi ganz Datei. Dësen Uruff initiéiert en asynchronen Datefluch a waart net bis se fäerdeg ass. Awer am Certificat sync_file_range() d'Equipe gëtt gesot "ganz geféierlech". Et ass net recommandéiert et ze benotzen. Fonctiounen a Gefore sync_file_range() ganz gutt beschriwwen an dat Material. Speziell schéngt dësen Uruff RocksDB ze benotzen fir ze kontrolléieren wann de Kernel dreckeg Daten op Disk spült. Awer zur selwechter Zäit, fir stabil Datelagerung ze garantéieren, gëtt et och benotzt fdatasync(). d' Code RocksDB huet e puer interessant Kommentaren zu dësem Thema. Zum Beispill, schéngt et, datt den Opruff sync_file_range() Wann Dir ZFS benotzt, spült et keng Daten op Disk. D'Erfahrung seet mir datt de Code dee selten benotzt gëtt wahrscheinlech Bugs enthält. Dofir géif ech roden dëse System Uruff ze benotzen, ausser et ass absolut néideg.

System Appellen déi hëllefen d'Datepersistenz ze garantéieren

Ech sinn zu der Conclusioun komm datt et dräi Approche sinn déi kënne benotzt ginn fir I / O Operatiounen auszeféieren déi d'Datepersistenz garantéieren. Si all verlaangen eng Funktioun Uruff fsync() fir den Dossier an deem d'Datei erstallt gouf. Dëst sinn d'Approche:

  1. Opruff eng Funktioun fdatasync() oder fsync() no Funktioun write() (et ass besser ze benotzen fdatasync()).
  2. Schafft mat engem Dateideskriptor opgemaach mat engem Fändel O_DSYNC oder O_SYNC (besser - mat engem Fändel O_DSYNC).
  3. Benotzt de Kommando pwritev2() mat Fändel RWF_DSYNC oder RWF_SYNC (Preferenz mat engem Fändel RWF_DSYNC).

Leeschtung Notes

Ech hunn d'Performance vun de verschiddene Mechanismen, déi ech iwwerpréift hunn, net virsiichteg gemooss. D'Ënnerscheeder, déi ech an der Geschwindegkeet vun hirer Aarbecht gemierkt hunn, si ganz kleng. Dëst bedeit datt ech falsch sinn, an datt ënner verschiddene Konditiounen déiselwecht Saach verschidde Resultater produzéiere kann. Als éischt wäert ech schwätzen iwwer wat d'Leeschtung méi beaflosst, an dann wat d'Leeschtung manner beaflosst.

  1. D'Dateidaten iwwerschreiwe ass méi séier wéi d'Daten op eng Datei ze addéieren (de Leeschtungsvirdeel kann 2-100% sinn). Dateen un eng Datei bäizefügen erfuerdert zousätzlech Ännerungen un de Metadaten vun der Datei, och no engem Systemruff fallocate(), awer d'Gréisst vun dësem Effekt kann variéieren. Ech recommandéieren, fir déi bescht Leeschtung, ze ruffen fallocate() déi erfuerderlech Plaz virauszedeelen. Da muss dëse Raum explizit mat Nullen gefëllt a genannt ginn fsync(). Dëst wäert sécherstellen datt déi entspriechend Blocken am Dateiesystem als "allokéiert" markéiert sinn anstatt "net allocéiert". Dëst gëtt eng kleng (ongeféier 2%) Leeschtungsverbesserung. Zousätzlech kënnen e puer Disken e méi luesen éischten Zougang zu engem Block hunn wéi anerer. Dëst bedeit datt d'Füllung vum Raum mat Nullen zu enger bedeitender (ongeféier 100%) Verbesserung vun der Leeschtung féiert. Besonnesch kann dëst mat Disken geschéien AWS EBS (dëst sinn inoffiziell Donnéeën, ech konnt se net bestätegen). Dat selwecht gëllt fir d'Lagerung GCP Persistent Disk (an dëst ass schonn offiziell Informatioun, bestätegt duerch Tester). Aner Experten hunn datselwecht gemaach Observatioun, Zesummenhang mat verschiddenen Disken.
  2. Der manner System rifft, der méi héich Leeschtung (de Gewënn kann ongeféier 5%). Gesäit aus wéi eng Erausfuerderung open() mat Fändel O_DSYNC oder ruffen pwritev2() mat Fändel RWF_SYNC méi séier wéi en Uruff fdatasync(). Ech de Verdacht, datt de Punkt hei ass, datt dës Approche eng Roll spillt an der Tatsaach, datt manner System Uriff musse gemaach ginn fir dee selwechte Problem ze léisen (een Uruff amplaz zwee). Awer den Ënnerscheed an der Leeschtung ass ganz kleng, sou datt Dir et komplett ignoréiere kënnt an eppes an der Applikatioun benotze wat seng Logik net komplizéiert.

Wann Dir un d'Thema vun nohalteger Datelagerung interesséiert sidd, hei sinn e puer nëtzlech Materialien:

  • ech / O Zougang Methoden - Iwwersiicht iwwer d'Basis vun Input / Output Mechanismen.
  • Vergewëssert Iech datt d'Donnéeën d'Disk erreecht - eng Geschicht iwwer wat geschitt mat den Daten um Wee vun der Applikatioun op den Disk.
  • Wéini sollt Dir den Inhaltsverzeechnes fsynchroniséieren - d'Äntwert op d'Fro wéini ze benotzen fsync() fir Verzeichnungen. Fir dëst an enger Nossschuel ze setzen, stellt sech eraus datt Dir dëst maache musst wann Dir eng nei Datei erstellt, an de Grond fir dës Empfehlung ass datt am Linux vill Referenzen op déiselwecht Datei kënne sinn.
  • SQL Server op Linux: FUA Internals - hei ass eng Beschreiwung wéi persistent Datelagerung am SQL Server op der Linux Plattform implementéiert gëtt. Et ginn e puer interessant Vergläicher tëscht Windows a Linux System Appellen hei. Ech si bal sécher datt et dank dësem Material war datt ech iwwer FUA Optimiséierung vun XFS geléiert hunn.

Hutt Dir Daten verluer, déi Dir geduecht hutt sécher op enger Disk gespäichert ze sinn?

Haltbar Datelagerung a Linux Datei APIen

Haltbar Datelagerung a Linux Datei APIen

Source: will.com