Es, pÄtot datu uzglabÄÅ”anas stabilitÄti mÄkoÅsistÄmÄs, nolÄmu sevi pÄrbaudÄ«t, lai pÄrliecinÄtos, ka saprotu pamata lietas. es sÄkÄs, izlasot NVMe spec lai saprastu, kÄdas garantijas attiecÄ«bÄ uz datu noturÄ«bu (tas ir, garantijas, ka dati bÅ«s pieejami pÄc sistÄmas kļūmes) dod mums NMVe diskus. Es izdarÄ«ju Å”Ädus galvenos secinÄjumus: dati ir jÄuzskata par bojÄtiem no datu rakstÄ«Å”anas komandas doÅ”anas brīža un lÄ«dz brÄ«dim, kad tie tiek ierakstÄ«ti datu nesÄjÄ. TomÄr lielÄkajÄ daÄ¼Ä programmu datu ierakstÄ«Å”anai diezgan droÅ”i izmanto sistÄmas zvanus.
Å ajÄ rakstÄ es izpÄtÄ«Å”u Linux failu API nodroÅ”inÄtos noturÄ«bas mehÄnismus. Å Ä·iet, ka Å”eit visam jÄbÅ«t vienkÄrÅ”am: programma izsauc komandu write(), un pÄc Ŕīs komandas pabeigÅ”anas dati tiks droÅ”i saglabÄti diskÄ. Bet write() tikai kopÄ lietojumprogrammas datus kodola keÅ”atmiÅÄ, kas atrodas RAM. Lai piespiestu sistÄmu ierakstÄ«t datus diskÄ, ir jÄizmanto daži papildu mehÄnismi.
KopumÄ Å”is materiÄls ir piezÄ«mju kopums par to, ko esmu iemÄcÄ«jies par mani interesÄjoÅ”u tÄmu. Ja mÄs ļoti Ä«si runÄjam par svarÄ«gÄko, izrÄdÄs, ka, lai organizÄtu ilgtspÄjÄ«gu datu glabÄÅ”anu, jums ir jÄizmanto komanda fdatasync() vai atveriet failus ar karogu O_DSYNC. Ja vÄlaties uzzinÄt vairÄk par to, kas notiek ar datiem ceÄ¼Ä no koda uz disku, apskatiet Å”is rakstu.
RakstīŔanas () funkcijas izmantoŔanas iezīmes
SistÄmas zvans write() definÄts standartÄ IEEE POSIX kÄ mÄÄ£inÄjums ierakstÄ«t datus faila deskriptorÄ. PÄc veiksmÄ«gas darba pabeigÅ”anas write() datu lasÄ«Å”anas operÄcijÄm ir jÄatgriež tieÅ”i tie baiti, kas tika ierakstÄ«ti iepriekÅ”, to darot pat tad, ja datiem tiek piekļūts no citiem procesiem vai pavedieniem (Å”eit atbilstoÅ”Ä POSIX standarta sadaļa). Å eit, sadaÄ¼Ä par to, kÄ pavedieni mijiedarbojas ar parastajÄm failu operÄcijÄm, ir piezÄ«me, kurÄ teikts, ka, ja divi pavedieni izsauc Ŕīs funkcijas, katram izsaukumam ir jÄredz vai nu visas otra izsaukuma noteiktÄs sekas, vai arÄ« nekÄdas. sekas. Tas liek secinÄt, ka visÄm failu I/O operÄcijÄm ir jÄbÅ«t bloÄ·Ätai resursam, ar kuru tÄs darbojas.
Vai tas nozÄ«mÄ, ka operÄcija write() ir atoms? No tehniskÄ viedokļa, jÄ. Datu nolasÄ«Å”anas operÄcijÄm ir jÄatgriež viss vai nekas no tÄ, kas tika rakstÄ«ts write(). Bet operÄcija write(), saskaÅÄ ar standartu, nav jÄbeidzas, pierakstot visu, kas viÅai tika lÅ«gts pierakstÄ«t. Ir atļauts ierakstÄ«t tikai daļu datu. PiemÄram, mums var bÅ«t divas straumes, kas katra pievieno 1024 baitus failam, ko apraksta tas pats faila deskriptors. No standarta viedokļa rezultÄts bÅ«s pieÅemams, ja katra no rakstÄ«Å”anas operÄcijÄm failam var pievienot tikai vienu baitu. Å Ä«s darbÄ«bas paliks atomÄras, taÄu pÄc to pabeigÅ”anas failÄ ierakstÄ«tie dati tiks sajaukti. Å”eit ir ļoti interesanta diskusija par Å”o tÄmu vietnÄ Stack Overflow.
fsync() un fdatasync() funkcijas
VienkÄrÅ”Äkais veids, kÄ izskalot datus diskÄ, ir izsaukt funkciju fsync(). Å Ä« funkcija pieprasa operÄtÄjsistÄmai pÄrsÅ«tÄ«t visus modificÄtos blokus no keÅ”atmiÅas uz disku. Tas ietver visus faila metadatus (piekļuves laiku, faila modifikÄcijas laiku un tÄ tÄlÄk). Es uzskatu, ka Å”ie metadati ir reti nepiecieÅ”ami, tÄpÄc, ja zinÄt, ka tie jums nav svarÄ«gi, varat izmantot funkciju fdatasync(). Uz palÄ«dzÄt par fdatasync() tajÄ teikts, ka Ŕīs funkcijas darbÄ«bas laikÄ diskÄ tiek saglabÄts tÄds metadatu daudzums, kas "nepiecieÅ”ams turpmÄko datu nolasÄ«Å”anas darbÄ«bu pareizai izpildei". Un tas ir tieÅ”i tas, kas rÅ«p lielÄkajai daļai lietojumprogrammu.
Viena problÄma, kas var rasties Å”eit, ir tÄda, ka Å”ie mehÄnismi negarantÄ, ka fails bÅ«s atrodams pÄc iespÄjamÄs kļūmes. Jo Ä«paÅ”i, veidojot jaunu failu, jums ir jÄzvana fsync() direktorijam, kurÄ tas ir. PretÄjÄ gadÄ«jumÄ pÄc avÄrijas var izrÄdÄ«ties, ka Å”is fails neeksistÄ. Iemesls tam ir tas, ka UNIX sistÄmÄ cieto saiÅ”u izmantoÅ”anas dÄļ fails var pastÄvÄt vairÄkos direktorijos. TÄpÄc, zvanot fsync() fails nevar zinÄt, kura direktorija dati ir arÄ« jÄizskalo diskÄ (Å”eit JÅ«s varat lasÄ«t vairÄk par to). Å Ä·iet, ka ext4 failu sistÄma to spÄj automÄtiski piemÄrot fsync() uz direktorijiem, kas satur atbilstoÅ”os failus, bet tas var nenotikt citÄs failu sistÄmÄs.
Å o mehÄnismu dažÄdÄs failu sistÄmÄs var ieviest atŔķirÄ«gi. ES izmantoju blktrace lai uzzinÄtu, kÄdas diska darbÄ«bas tiek izmantotas ext4 un XFS failu sistÄmÄs. Abi izdod parastÄs ierakstÄ«Å”anas komandas diskÄ gan failu saturam, gan failu sistÄmas žurnÄlam, iztÄ«ra keÅ”atmiÅu un iziet, veicot FUA (Force Unit Access, datu ierakstÄ«Å”ana tieÅ”i diskÄ, apejot keÅ”atmiÅu) ierakstÄ«Å”anu žurnÄlÄ. ViÅi, iespÄjams, tieÅ”i to dara, lai apstiprinÄtu darÄ«juma faktu. Diskos, kas neatbalsta FUA, tas izraisa divas keÅ”atmiÅas izskaloÅ”anas. Mani eksperimenti to ir parÄdÄ«juÅ”i fdatasync() mazliet ÄtrÄk fsync(). LietderÄ«ba blktrace norÄda uz to fdatasync() parasti diskÄ ieraksta mazÄk datu (ext4 fsync() raksta 20 KiB, un fdatasync() - 16 KiB). Es arÄ« uzzinÄju, ka XFS ir nedaudz ÄtrÄks nekÄ ext4. Un Å”eit ar palÄ«dzÄ«bu blktrace varÄja to noskaidrot fdatasync() diskÄ izskalo mazÄk datu (4 KiB XFS).
Neskaidras situÄcijas, izmantojot fsync()
Es varu iedomÄties trÄ«s neskaidras situÄcijas saistÄ«bÄ ar fsync()ar ko esmu saskÄries praksÄ.
Pirmais Å”Äds incidents notika 2008. gadÄ. TajÄ laikÄ Firefox 3 saskarne āiesaldÄjaā, ja diskÄ tika ierakstÄ«ts liels skaits failu. ProblÄma bija tÄda, ka saskarnes ievieÅ”ana izmantoja SQLite datu bÄzi, lai saglabÄtu informÄciju par tÄs stÄvokli. PÄc katras izmaiÅas, kas notika saskarnÄ, funkcija tika izsaukta fsync(), kas deva labas garantijas par stabilu datu glabÄÅ”anu. Toreiz izmantotajÄ ext3 failu sistÄmÄ funkcija fsync() izskalo visas sistÄmas "netÄ«rÄs" lapas, nevis tikai tÄs, kas bija saistÄ«tas ar attiecÄ«go failu. Tas nozÄ«mÄja, ka, noklikŔķinot uz pogas pÄrlÅ«kprogrammÄ Firefox, magnÄtiskajÄ diskÄ var tikt ierakstÄ«ti datu megabaiti, kas var ilgt daudzas sekundes. ProblÄmas risinÄjums, cik es sapratu tÄ materiÄlu, bija pÄrcelt darbu ar datubÄzi uz asinhroniem fona uzdevumiem. Tas nozÄ«mÄ, ka Firefox agrÄk ieviesa stingrÄkas krÄtuves noturÄ«bas prasÄ«bas, nekÄ patiesÄ«bÄ bija nepiecieÅ”ams, un ext3 failu sistÄmas lÄ«dzekļi Å”o problÄmu tikai saasinÄja.
OtrÄ problÄma radÄs 2009. gadÄ. PÄc tam pÄc sistÄmas avÄrijas jaunÄs ext4 failu sistÄmas lietotÄji atklÄja, ka daudziem jaunizveidotajiem failiem ir nulles garums, taÄu tas nenotika ar vecÄku ext3 failu sistÄmu. IepriekÅ”ÄjÄ rindkopÄ es runÄju par to, kÄ ext3 diskÄ ievietoja pÄrÄk daudz datu, kas ievÄrojami palÄninÄja darbÄ«bu. fsync(). Lai uzlabotu situÄciju, ext4 izskalo tikai tÄs "netÄ«rÄs" lapas, kas attiecas uz konkrÄtu failu. Un citu failu dati paliek atmiÅÄ daudz ilgÄku laiku nekÄ ar ext3. Tas tika darÄ«ts, lai uzlabotu veiktspÄju (pÄc noklusÄjuma dati paliek Å”ajÄ stÄvoklÄ« 30 sekundes, to var konfigurÄt, izmantojot dirty_expire_centisecs; Å”eit JÅ«s varat atrast vairÄk informÄcijas par to). Tas nozÄ«mÄ, ka pÄc avÄrijas var neatgriezeniski zaudÄt lielu datu apjomu. Å Ä«s problÄmas risinÄjums ir izmantot fsync() lietojumprogrammÄs, kurÄm jÄnodroÅ”ina stabila datu glabÄÅ”ana un pÄc iespÄjas vairÄk jÄaizsargÄ tÄs no kļūmju sekÄm. Funkcija fsync() darbojas daudz efektÄ«vÄk ar ext4 nekÄ ar ext3. Å Ä«s pieejas trÅ«kums ir tÄds, ka tÄs izmantoÅ”ana, tÄpat kÄ iepriekÅ”, palÄnina dažas darbÄ«bas, piemÄram, programmu instalÄÅ”anu. Skatiet sÄ«kÄku informÄciju par to Å”eit Šø Å”eit.
TreÅ”Ä problÄma saistÄ«bÄ ar fsync(), radÄs 2018. gadÄ. Tad PostgreSQL projekta ietvaros tika noskaidrots, ka ja funkcija fsync() rodas kļūda, tas atzÄ«mÄ "netÄ«rÄs" lapas kÄ "tÄ«ras". RezultÄtÄ Å”Ädi zvani fsync() nedari neko ar tÄdÄm lapÄm. Å Ä« iemesla dÄļ modificÄtÄs lapas tiek saglabÄtas atmiÅÄ un nekad netiek ierakstÄ«tas diskÄ. TÄ ir Ä«sta katastrofa, jo aplikÄcija domÄs, ka daži dati ir ierakstÄ«ti diskÄ, bet patiesÄ«bÄ tÄ nebÅ«s. TÄdas neveiksmes fsync() ir reti, lietojumprogramma Å”ÄdÄs situÄcijÄs gandrÄ«z neko nevar palÄ«dzÄt novÄrst problÄmu. MÅ«sdienÄs, kad tas notiek, PostgreSQL un citas lietojumprogrammas avarÄ. Å eit, rakstÄ "Vai lietojumprogrammas var atgÅ«ties no fsync kļūmÄm?", Ŕī problÄma ir detalizÄti izpÄtÄ«ta. PaÅ”laik labÄkais risinÄjums Å”ai problÄmai ir izmantot tieÅ”o I/O ar karogu O_SYNC vai ar karogu O_DSYNC. Izmantojot Å”o pieeju, sistÄma ziÅos par kļūdÄm, kas var rasties, veicot noteiktas datu rakstÄ«Å”anas darbÄ«bas, taÄu Ŕī pieeja prasa, lai lietojumprogramma pati pÄrvaldÄ«tu buferus. Lasiet par to vairÄk Å”eit Šø Å”eit.
Failu atvÄrÅ”ana, izmantojot karogus O_SYNC un O_DSYNC
AtgriezÄ«simies pie diskusijas par Linux mehÄnismiem, kas nodroÅ”ina pastÄvÄ«gu datu glabÄÅ”anu. Proti, runa ir par karoga lietoÅ”anu O_SYNC vai karogs O_DSYNC atverot failus, izmantojot sistÄmas zvanu atvÄrt (). Izmantojot Å”o pieeju, katra datu rakstÄ«Å”anas darbÄ«ba tiek veikta it kÄ pÄc katras komandas write() sistÄmai tiek dotas attiecÄ«gi komandas fsync() Šø fdatasync(). Uz POSIX specifikÄcijas to sauc par "Synchronized I/O File Integrity Completion" un "Data Integrity Completion". Å Ä«s pieejas galvenÄ priekÅ”rocÄ«ba ir tÄ, ka, lai nodroÅ”inÄtu datu integritÄti, ir jÄizpilda tikai viens sistÄmas izsaukums, nevis divi (piemÄram, - write() Šø fdatasync()). Å Ä«s pieejas galvenais trÅ«kums ir tas, ka visas rakstÄ«Å”anas darbÄ«bas, izmantojot atbilstoÅ”o faila deskriptoru, tiks sinhronizÄtas, kas var ierobežot iespÄju strukturÄt lietojumprogrammas kodu.
Izmantojot tieŔo I/O ar karogu O_DIRECT
SistÄmas zvans open() atbalsta karogu O_DIRECT, kas ir paredzÄts, lai apietu operÄtÄjsistÄmas keÅ”atmiÅu, lai veiktu I/O darbÄ«bas, tieÅ”i mijiedarbojoties ar disku. Tas daudzos gadÄ«jumos nozÄ«mÄ, ka programmas izdotÄs rakstÄ«Å”anas komandas tiks tieÅ”i tulkotas komandÄs, kuru mÄrÄ·is ir strÄdÄt ar disku. Bet kopumÄ Å”is mehÄnisms neaizstÄj funkcijas fsync() vai fdatasync(). Fakts ir tÄds, ka pats disks var kavÄÅ”anÄs vai keÅ”atmiÅa atbilstoÅ”as āākomandas datu rakstÄ«Å”anai. Un, vÄl ļaunÄk, dažos Ä«paÅ”os gadÄ«jumos I / O darbÄ«bas, kas veiktas, izmantojot karogu O_DIRECT, pÄrraide tradicionÄlajÄs buferizÄtajÄs operÄcijÄs. VienkÄrÅ”Äkais veids, kÄ atrisinÄt Å”o problÄmu, ir izmantot karogu, lai atvÄrtu failus O_DSYNC, kas nozÄ«mÄs, ka katrai rakstÄ«Å”anas darbÄ«bai sekos izsaukums fdatasync().
IzrÄdÄ«jÄs, ka XFS failu sistÄma nesen bija pievienojusi "Ätro ceļu". O_DIRECT|O_DSYNC- datu ieraksti. Ja bloks tiek pÄrrakstÄ«ts, izmantojot O_DIRECT|O_DSYNC, tad XFS, tÄ vietÄ, lai izskalotu keÅ”atmiÅu, izpildÄ«s FUA rakstÄ«Å”anas komandu, ja ierÄ«ce to atbalsta. Es to pÄrbaudÄ«ju, izmantojot utilÄ«tu blktrace Linux 5.4/Ubuntu 20.04 sistÄmÄ. Å ai pieejai vajadzÄtu bÅ«t efektÄ«vÄkai, jo tÄ ieraksta diskÄ minimÄlo datu apjomu un izmanto vienu darbÄ«bu, nevis divas (rakstÄ«Å”ana un keÅ”atmiÅas iztÄ«rÄ«Å”ana). Atradu saiti uz plÄksteris 2018 kodols, kas ievieÅ” Å”o mehÄnismu. Ir dažas diskusijas par Ŕīs optimizÄcijas piemÄroÅ”anu citÄm failu sistÄmÄm, taÄu, cik man zinÄms, XFS ir vienÄ«gÄ failu sistÄma, kas lÄ«dz Å”im to atbalsta.
sync_file_range() funkcija
Linux ir sistÄmas izsaukums sync_file_range(), kas ļauj diskÄ izskalot tikai daļu faila, nevis visu failu. Å is zvans uzsÄk asinhrono skaloÅ”anu un negaida, lÄ«dz tas tiks pabeigts. Bet atsaucÄ uz sync_file_range() Ŕī komanda esot "ļoti bÄ«stama". Nav ieteicams to lietot. ÄŖpaŔības un briesmas sync_file_range() ļoti labi aprakstÄ«ts Å”is materiÄls. Jo Ä«paÅ”i Ŕķiet, ka Å”is izsaukums izmanto RocksDB, lai kontrolÄtu, kad kodols diskÄ izskalo "netÄ«ros" datus. Bet tajÄ paÅ”Ä laikÄ, lai nodroÅ”inÄtu stabilu datu glabÄÅ”anu, tas arÄ« tiek izmantots fdatasync(). Uz kods RocksDB ir daži interesanti komentÄri par Å”o tÄmu. PiemÄram, tas izskatÄs kÄ zvans sync_file_range() Izmantojot ZFS, tas neizskalo datus diskÄ. Pieredze man rÄda, ka reti izmantotajÄ kodÄ var bÅ«t kļūdas. TÄpÄc es ieteiktu neizmantot Å”o sistÄmas zvanu, ja vien tas nav absolÅ«ti nepiecieÅ”ams.
SistÄmas zvani, lai palÄ«dzÄtu nodroÅ”inÄt datu noturÄ«bu
Esmu nonÄcis pie secinÄjuma, ka pastÄv trÄ«s pieejas, ko var izmantot, lai veiktu pastÄvÄ«gas I/O darbÄ«bas. ViÅiem visiem ir nepiecieÅ”ams funkciju izsaukums fsync() direktorijai, kurÄ fails tika izveidots. Å Ä«s ir Å”Ädas pieejas:
Funkcijas izsaukums fdatasync() vai fsync() pÄc funkcijas write() (labÄk lietot fdatasync()).
Darbs ar faila deskriptoru, kas atvÄrts ar karogu O_DSYNC vai O_SYNC (labÄk - ar karogu O_DSYNC).
Komandu lietoÅ”ana pwritev2() ar karogu RWF_DSYNC vai RWF_SYNC (vÄlams ar karogu RWF_DSYNC).
VeiktspÄjas piezÄ«mes
Es rÅ«pÄ«gi neizmÄrÄ«ju dažÄdu pÄrbaudÄ«to mehÄnismu veiktspÄju. AtŔķirÄ«bas, ko pamanÄ«ju viÅu darba ÄtrumÄ, ir ļoti mazas. Tas nozÄ«mÄ, ka es varu kļūdÄ«ties un ka citos apstÄkļos viena un tÄ pati lieta var uzrÄdÄ«t atŔķirÄ«gus rezultÄtus. Vispirms es runÄÅ”u par to, kas vairÄk ietekmÄ veiktspÄju, un pÄc tam par to, kas mazÄk ietekmÄ veiktspÄju.
Faila datu pÄrrakstÄ«Å”ana ir ÄtrÄka nekÄ datu pievienoÅ”ana failam (veiktspÄjas ieguvums var bÅ«t 2ā100%). Lai failam pievienotu datus, ir jÄveic papildu izmaiÅas faila metadatos pat pÄc sistÄmas izsaukuma fallocate(), taÄu Ŕī efekta apjoms var atŔķirties. Es iesaku, lai nodroÅ”inÄtu vislabÄko sniegumu, piezvanÄ«t fallocate() lai iepriekÅ” pieŔķirtu nepiecieÅ”amo vietu. Tad Ŕī vieta ir skaidri jÄaizpilda ar nullÄm un jÄizsauc fsync(). TÄdÄjÄdi attiecÄ«gie bloki failu sistÄmÄ tiks atzÄ«mÄti kÄ "pieŔķirti", nevis "nepieŔķirti". Tas nodroÅ”ina nelielu (apmÄram 2%) veiktspÄjas uzlabojumu. TurklÄt dažiem diskiem var bÅ«t lÄnÄka pirmÄ bloka piekļuves darbÄ«ba nekÄ citiem. Tas nozÄ«mÄ, ka vietas aizpildÄ«Å”ana ar nullÄm var novest pie ievÄrojama (apmÄram 100%) veiktspÄjas uzlabojuma. Jo Ä«paÅ”i tas var notikt ar diskiem. AWS EBS (Å”ie ir neoficiÄli dati, es nevarÄju tos apstiprinÄt). Tas pats attiecas uz uzglabÄÅ”anu. GCP pastÄvÄ«gais disks (un tÄ jau ir oficiÄla informÄcija, ko apstiprina testi). To ir darÄ«juÅ”i arÄ« citi eksperti novÄrojumssaistÄ«ti ar dažÄdiem diskiem.
Jo mazÄk sistÄmas zvanu, jo augstÄka veiktspÄja (pieaugums var bÅ«t aptuveni 5%). Tas izskatÄs pÄc zvana open() ar karogu O_DSYNC vai zvaniet pwritev2() ar karogu RWF_SYNC ÄtrÄk nekÄ zvans fdatasync(). Man ir aizdomas, ka Å”eit ir runa par to, ka, izmantojot Å”o pieeju, nozÄ«me ir tam, ka ir jÄveic mazÄk sistÄmas izsaukumu, lai atrisinÄtu vienu un to paÅ”u uzdevumu (viens zvans divu vietÄ). Bet veiktspÄjas atŔķirÄ«ba ir ļoti maza, tÄpÄc varat to viegli ignorÄt un lietotnÄ izmantot kaut ko tÄdu, kas nesarežģī tÄs loÄ£iku.
Ja jÅ«s interesÄ ilgtspÄjÄ«gas datu uzglabÄÅ”anas tÄma, Å”eit ir daži noderÄ«gi materiÄli:
Kad vajadzÄtu fsinhronizÄt saturoÅ”o direktoriju - atbilde uz jautÄjumu, kad pieteikties fsync() katalogiem. ÄŖsumÄ, izrÄdÄs, ka tas ir jÄdara, veidojot jaunu failu, un Ŕī ieteikuma iemesls ir tas, ka Linux var bÅ«t daudz atsauÄu uz vienu un to paÅ”u failu.
SQL serveris operÄtÄjsistÄmÄ Linux: FUA iekÅ”Äjie elementi - Å”eit ir aprakstÄ«ts, kÄ pastÄvÄ«gÄ datu glabÄÅ”ana tiek ieviesta SQL Server Linux platformÄ. Å eit ir daži interesanti salÄ«dzinÄjumi starp Windows un Linux sistÄmas izsaukumiem. Esmu gandrÄ«z pÄrliecinÄts, ka tieÅ”i pateicoties Å”im materiÄlam uzzinÄju par XFS FUA optimizÄciju.
Vai esat kÄdreiz pazaudÄjis datus, kas, jÅ«suprÄt, ir droÅ”i glabÄti diskÄ?