API-yên pelê yên pelê Linux û hilanîna daneya domdar

Dema ku li ser domdariya hilanîna daneyê di pergalên ewr de lêkolîn dikir, min biryar da ku ez xwe biceribînim da ku ez pê bawer bikim ku min tiştên bingehîn fam kiriye. ez bi xwendina taybetmendiya NVMe dest pê kir ji bo ku em fêm bikin ka çi garantî di derheqê hilanîna daneya domdar de (ango, garantiyên ku dê dane piştî têkçûna pergalê peyda bibin) ji hêla dîskên NMVe ve têne dayîn. Min encamên sereke yên jêrîn çêkir: Divê dane ji gava ku fermana nivîsandina daneyan tê dayîn heya dema ku ew li navgîniya hilanînê tê nivîsandin zirardar bêne hesibandin. Lêbelê, pir bername bi kêfxweşî bangên pergalê bikar tînin da ku daneyan tomar bikin.

Di vê postê de, ez mekanîzmayên hilanînê yên domdar ên ku ji hêla API-yên pelê Linux ve têne peyda kirin vedikolim. Wusa dixuye ku divê her tişt li vir hêsan be: bername fermanê gazî dike write(), û piştî ku ev ferman qediya, dê dane bi ewlehî li dîskê were tomar kirin. Lebê write() tenê daneyên serîlêdanê li cacheya kernelê ya ku di RAM-ê de ye kopî dike. Ji bo ku hûn pergalê neçar bikin ku daneyan li ser dîskê binivîsin, hûn hewce ne ku hin mekanîzmayên din bikar bînin.

API-yên pelê yên pelê Linux û hilanîna daneya domdar

Bi tevayî, ev materyal berhevokek nîşeyan e ku li ser tiştê ku ez li ser mijarek ji min re eleqedar fêr bûm ve girêdayî ye. Ger em bi kurtasî li ser tiştê herî girîng biaxivin, derdikeve holê ku ji bo organîzekirina hilanîna daneya domdar hûn hewce ne ku fermanê bikar bînin fdatasync() an jî pelên bi ala vekin O_DSYNC. Heke hûn dixwazin bêtir fêr bibin ka çi diqewime daneyên di rê de ji kodê ber bi dîskê ve, lê binêre ev tişt.

Taybetmendiyên bikaranîna fonksiyona nivîsandinê().

Banga pergalê write() di standardê de hatiye diyarkirin IEEE POSIX wekî hewldanek ji bo nivîsandina daneyan li ser ravekerek pelê. Piştî qedandina serkeftî write() Operasyonên xwendina daneyê divê tam baytên ku berê hatine nivîsandin vegerînin, vê yekê bikin jî heke dane ji pêvajoyek an mijarên din werin gihîştin (Va ye beşa têkildar a standard POSIX). Ev e, di beşa li ser çawaniya têkiliyek têkel bi karûbarên pelê yên normal re, têbînîyek heye ku dibêje heke her du mijar van fonksiyonan bang bikin, wê hingê divê her bangek hemî encamên destnîşankirî yên banga din, an jî qet nebe. encamên. Ev rê dide vê encamê ku hemî operasyonên pelê I/O divê li ser çavkaniya ku ew li ser dixebitin kilîtekê bigirin.

Ma ev tê wê wateyê ku operasyon write() ew atomî ye? Ji aliyê teknîkî ve, erê. Pêdivî ye ku operasyonên xwendina daneyê hemî an tiştek ji tiştê ku pê re hatî nivîsandin vegerîne write(). Lê operasyon write(), li gorî standardê, ne hewce ye ku bi nivîsandina her tiştê ku jê hatî xwestin were nivîsandin bi dawî bibe. Ew destûr e ku tenê beşek daneyan binivîse. Mînakî, dibe ku em du têlan hebin ku her yek 1024 byte li pelek ku ji hêla heman ravekerê pelê ve hatî şirove kirin zêde dike. Ji nihêrîna standardê, encamek meqbûl dê bibe gava ku her operasyona nivîsandinê tenê yek byte li pelê zêde bike. Ev operasyon dê atomî bimînin, lê piştî ku ew qediyan, daneyên ku wan li pelê nivîsandine dê tevlihev bibin. vir nîqaşek pir balkêş li ser vê mijarê li ser Stack Overflow.

fonksiyonên fsync() û fdatasync().

Rêya herî hêsan ku meriv daneyan li ser dîskê bişewitîne ev e ku meriv fonksiyonê bang bike fsync(). Vê fonksiyonê ji pergala xebitandinê dipirse ku hemî blokên guhezbar ji cache veguherîne dîskê. Di vê yekê de hemî metadata pelê (dema gihîştinê, dema guhartina pelê, û hwd.) vedihewîne. Ez bawer dikim ku ev metadata kêm kêm hewce ye, ji ber vê yekê heke hûn dizanin ku ew ji we re ne girîng e, hûn dikarin fonksiyonê bikar bînin fdatasync(). ew alîkarî li ser fdatasync() Tê gotin ku di dema xebitandina vê fonksiyonê de, mîqdarek wusa metadata li ser dîskê tê hilanîn ku "ji bo pêkanîna rast a operasyonên xwendina daneya jêrîn hewce ye." Û ev tam ya ku pir serîlêdan jê re eleqedar e.

Pirsgirêkek ku li vir dikare derkeve ev e ku van mekanîzmayan garantî nakin ku pel dê piştî têkçûnek gengaz were kifş kirin. Bi taybetî, dema ku pelek nû çêbikin, hûn hewce ne ku bang bikin fsync() ji bo pelrêça ku tê de ye. Wekî din, piştî têkçûnek, dibe ku derkeve holê ku ev pel tune. Sedema vê yekê ew e ku di UNIX de, ji ber bikaranîna girêdanên hişk, pelek dikare di gelek pelrêçan de hebe. Ji ber vê yekê, dema ku bang dikin fsync() rê tune ku pelek bizanibe kîjan daneyên pelrêça jî divê li ser dîskê were şuştin (vir Hûn dikarin li ser vê yekê bêtir bixwînin). Wusa dixuye ku pergala pelê ext4 jêhatî ye otomatîk bikaranîn fsync() ji pelrêçiyên ku pelên têkildar hene, lê dibe ku ev yek di pergalên pelan ên din de nebe.

Dibe ku ev mekanîzma li ser pergalên pelan ên cihêreng bi rengek cûda were bicîh kirin. Min bi kar anî blktrace fêr bibin ka çi operasyonên dîskê di pergalên pelan ên ext4 û XFS de têne bikar anîn. Hem ji bo naveroka pelê û hem jî ji bo kovara pergala pelan fermanên birêkûpêk nivîsandinê li dîskê derdixin, cache-ê dişoxilînin, û bi pêkanîna FUA (Hêzkirina Yekîneya Hêza, nivîsandina daneyan rasterast li ser dîskê, derbaskirina cache) li kovarê dinivîsin. Dibe ku ew vê yekê dikin da ku piştrast bikin ku danûstendin pêk hatiye. Li ser ajokarên ku FUA piştgirî nakin, ev dibe sedema du şûştina cache. Ezmûnên min ev nîşan dan fdatasync() hinekî zûtir fsync(). Utility blktrace nîşan dide ku fdatasync() bi gelemperî kêmtir daneyan li ser dîskê dinivîse (di ext4 fsync() 20 KiB dinivîse, û fdatasync() - 16 KiB). Di heman demê de, min fêr kir ku XFS ji ext4 hinekî zûtir e. Û li vir bi alîkariyê blktrace karîbû ku vê yekê bibîne fdatasync() Daneyên kêmtir li ser dîskê dişewitîne (di XFS de 4 KiB).

Rewşên nezelal ên ku di dema karanîna fsync() de derdikevin holê.

Ez dikarim di derbarê sê rewşên nezelal de bifikirim fsync()ku ez di pratîkê de rast hatim.

Yekemîn bûyera bi vî rengî di sala 2008 de pêk hat. Dûv re pêwendiya Firefox 3 cemidand heke hejmarek mezin ji pelan li ser dîskê hatin nivîsandin. Pirsgirêk ev bû ku pêkanîna navberê databasek SQLite bikar anî da ku agahdariya li ser rewşa xwe hilîne. Piştî her guhertina ku di navberê de çêbû, fonksiyonê hate gazî kirin fsync(), ku garantiyên baş ên hilanîna daneya aram da. Di pergala pelê ext3 de paşê tê bikar anîn, fonksiyon fsync() Hemî rûpelên "pîs" ên pergalê avêtin ser dîskê, û ne tenê yên ku bi pelê têkildar re têkildar bûn. Ev tê vê wateyê ku tikandina bişkokek li Firefox-ê dikaribû megabyte daneyan li ser dîskek magnetîkî were nivîsandin, ku dikare gelek saniyan bigire. Çareseriya pirsgirêkê, bi qasî ku ez jê fêm dikim ew maddî ev bû ku xebata bi databasê veguhezîne karên paşîn ên asynkron. Ev tê vê wateyê ku Firefox berê hewcedariyên hilanînê yên hişktir ji ya ku bi rastî hewce bû bicîh kir, û taybetmendiyên pergala pelê ext3 tenê vê pirsgirêkê zêde kir.

Pirsgirêka duyemîn di sala 2009 de çêbû. Dûv re, piştî têkçûnek pergalê, bikarhênerên pergala pelan a nû ext4 bi vê rastiyê re rû bi rû bûn ku pir pelên nû hatine afirandin dirêjahiya wan sifir bû, lê ev yek bi pergala pelê ext3 ya kevn re çênebû. Di paragrafa paşîn de, min behsa wê yekê kir ku ext3 çawa gelek daneyan li ser dîskê dişewitîne, ku tiştan pir hêdî dike. fsync(). Ji bo baştirkirina rewşê, di ext4 de tenê ew rûpelên qirêj ên ku bi pelek taybetî re têkildar in li ser dîskê têne avêtin. Û daneyên pelên din ji ya ext3 pir dirêjtir di bîranînê de dimîne. Ev ji bo baştirkirina performansê hate kirin (ji hêla xwerû, dane 30 çirkeyan di vê rewşê de dimîne, hûn dikarin vê bikar bînin dirty_expire_centisecs; vir Hûn dikarin li ser vê yekê materyalên din bibînin). Ev tê vê wateyê ku hejmareke mezin a daneyan dikare piştî têkçûnek bê veger winda bibe. Çareseriya vê pirsgirêkê bi kar e fsync() di serîlêdanên ku hewce ne ku hilanîna daneya bi îstîqrar peyda bikin û wan bi qasî ku pêkan ji encamên têkçûnê biparêzin. Karkirin fsync() Dema ku ext4 bikar tîne ji dema ku ext3 bikar tîne pir bi bandortir dixebite. Kêmasiya vê nêzîkbûnê ev e ku karanîna wê, wekî berê, pêkanîna hin operasyonan, wekî sazkirina bernameyan, hêdî dike. Li ser vê yekê hûrgulî bibînin vir и vir.

Pirsgirêka sêyemîn di derbarê fsync(), di sala 2018 de hatî çêkirin. Dûv re, di çarçoveya projeya PostgreSQL de, hate dîtin ku heke fonksiyon fsync() bi xeletiyekê re rûbirû dibe, ew rûpelên "pîs" wekî "paqij" nîşan dide. Di encamê de, bangên jêrîn fsync() Ew bi rûpelên weha tiştek nakin. Ji ber vê yekê, rûpelên hatine guherandin di bîranînê de têne hilanîn û qet li ser dîskê nayên nivîsandin. Ev karesatek rastîn e, ji ber ku serîlêdan dê bifikire ku hin dane li ser dîskê hatine nivîsandin, lê bi rastî ew ê nebe. Têkçûnên wisa fsync() kêm in, serîlêdana di rewşên weha de hema hema tiştek ji bo şerkirina pirsgirêkê nake. Van rojan, gava ku ev diqewime, PostgreSQL û serîlêdanên din têk diçin. Ev e, di materyalê de "Gelo Serlêdan Dikarin Ji Têkçûnên Fsync Vegerin?", ev pirsgirêk bi hûrgulî tê lêkolîn kirin. Niha baştirîn çareserî ji bo vê pirsgirêkê ev e ku rasterast I/O bi ala re bikar bîne O_SYNC yan jî bi ala O_DSYNC. Bi vê nêzîkatiyê, pergal dê xeletiyên ku dibe ku di dema operasyonên nivîsandinê yên taybetî de çêbibin rapor bike, lê ev nêzîkatî hewce dike ku serîlêdan bixwe tamponan birêve bibe. Li ser vê yekê bêtir bixwînin vir и vir.

Vekirina pelan bi karanîna alayên O_SYNC û O_DSYNC

Ka em vegerin li ser nîqaşa mekanîzmayên Linux yên ku hilanîna daneya aram peyda dikin. Ango em behsa bikaranîna alê dikin O_SYNC an ala O_DSYNC dema vekirina pelan bi karanîna banga pergalê vekirî(). Bi vê nêzîkbûnê re, her operasyona nivîsandina daneyê mîna ku piştî her fermanê tête kirin write() sîstemê li gorî wê fermanan dide fsync() и fdatasync(). ew Taybetmendiyên POSIX jê re tê gotin "Temamkirina yekparebûna pelê I/O Senkronîzekirî" û "Têkbûna yekparebûna daneyê". Feydeya sereke ya vê nêzîkatiyê ev e ku ji bo misogerkirina yekparebûna daneyê, hûn tenê hewce ne ku yek bangek pergalê bikin, ji duduyan (mînak - write() и fdatasync()). Kêmasiya sereke ya vê nêzîkbûnê ev e ku hemî nivîsên ku bi karanîna ravekera pelê têkildar têne hevdem kirin, ku dikare şiyana avakirina koda serîlêdanê sînordar bike.

Bi ala O_DIRECT I/O Direct bikar tînin

Banga pergalê open() ala piştgirî dike O_DIRECT, ya ku hatiye dîzaynkirin ku ji cache-ya pergala xebitandinê dûr bixe da ku bi rasterast bi dîskê re danûstandinê bike operasyonên I/O pêk bîne. Ev, di pir rewşan de, tê vê wateyê ku emrên nivîsandinê yên ku ji hêla bernameyê ve têne derxistin dê rasterast li fermanên ku bi mebesta xebata bi dîskê re têne wergerandin. Lê, bi gelemperî, ev mekanîzma ne şûna fonksiyonan e fsync() an fdatasync(). Rastî ev e ku dîsk bixwe dikare defer an cache fermanên nivîsandina daneya têkildar. Û, ji bo ku rewş xirabtir bibe, di hin rewşên taybetî de dema ku ala bikar tînin, operasyonên I/O têne kirin O_DIRECT, weşandin nav operasyonên tampon kevneşop. Rêya herî hêsan a çareserkirina vê pirsgirêkê ev e ku hûn ala bikar bînin da ku pelan vekin O_DSYNC, ku tê wê wateyê ku her operasyona nivîsandinê dê bi bangek were şopandin fdatasync().

Derket holê ku pergala pelê XFS di van demên dawî de ji bo "rêyek bilez" zêde kiriye O_DIRECT|O_DSYNC- tomarkirina daneyan. Heke blokek bi karanîna ji nû ve hatî nivîsandin O_DIRECT|O_DSYNC, wê hingê XFS, li şûna ku cache bişon, heke amûr piştgirî bike dê fermana nivîsandina FUA bicîh bîne. Min ev bi karanîna karûbar verast kir blktrace li ser pergalek Linux 5.4/Ubuntu 20.04. Pêdivî ye ku ev nêzîkatî bikêrtir be, ji ber ku dema ku tê bikar anîn, mîqdarek hindiktirîn daneyê li ser dîskê tê nivîsandin û yek operasyon tê bikar anîn, ji duduyan (nivîsandin û şûştina cache). Min girêdanek dît pîvaz 2018 kernel, ku vê mekanîzmayê pêk tîne. Li wir hin nîqaş li ser sepandina vê xweşbîniyê li pergalên pelan ên din hene, lê bi qasî ku ez dizanim, XFS pergala pelê yekane ye ku heya nuha vê piştgirî dike.

fonksiyona sync_file_range().

Linux xwedan bangek pergalê ye sync_file_range(), ku destûrê dide te ku hûn li şûna tevahiya pelê, tenê beşek pelê li ser dîskê bişon. Ev bang şuştinek daneya asynkron dide destpêkirin û li benda qedandina wê namîne. Lê di sertîfîkayê de sync_file_range() Tê gotin ku tîm "pir xeternak" e. Bikaranîna wê nayê pêşniyar kirin. Taybetmendî û xetere sync_file_range() pir baş tê şirove kirin ev mal. Bi taybetî, ev bang xuya dike ku RocksDB bikar tîne da ku kontrol bike dema ku kernel daneyên qirêj li ser dîskê dişewitîne. Lê di heman demê de, ji bo misogerkirina hilanîna daneya aram, ew jî tê bikar anîn fdatasync(). ew navê dizî RocksDB li ser vê mijarê hin şîroveyên balkêş hene. Ji bo nimûne, ew xuya dike ku bang sync_file_range() Dema ku ZFS bikar tîne, ew daneyan li ser dîskê naşewitîne. Tecrûbe ji min re dibêje ku koda ku kêm tê bikar anîn dibe ku xeletiyan hebe. Ji ber vê yekê, ez ê li dijî karanîna vê banga pergalê şîret bikim heya ku hewce nebe.

Bangên pergalê yên ku alîkariya dabînkirina domandina daneyê dikin

Ez gihîştim vê encamê ku sê nêzîkatî hene ku dikarin werin bikar anîn da ku karûbarên I/O bikin ku domdariya daneyê piştrast dikin. Ew hemî bangek fonksiyonê hewce dikin fsync() ji bo pelrêça ku pel tê de hatî çêkirin. Ev nêzîkatî ev in:

  1. Banga fonksiyonê fdatasync() an fsync() piştî fonksiyonê write() (çêtir e ku bikar bînin fdatasync()).
  2. Bi ravekerek pelê re xebitîn ku bi ala vekir O_DSYNC an O_SYNC (çêtir - bi ala O_DSYNC).
  3. Bi kar tînin emrê pwritev2() bi ala RWF_DSYNC an RWF_SYNC (tercîh bi ala RWF_DSYNC).

Têbiniyên Performansê

Min bi baldarî performansa mekanîzmayên cihêreng ên ku min lêkolîn kiriye pîva nekiriye. Cûdahiyên ku min di leza xebata wan de dîtin pir hindik in. Ev tê vê wateyê ku dibe ku ez xelet bim, û ku di bin şert û mercên cûda de heman tişt dibe ku encamên cûda derxe holê. Pêşîn, ez ê li ser tiştê ku bêtir bandorê li performansê dike, û dûv re jî ya ku kêmtir bandorê li performansê dike biaxivim.

  1. Zêdekirina daneya pelê ji pêvekirina daneyan li pelek zûtir e (feyda performansê dikare 2-100%) be. Zêdekirina daneyan li pelê guheztinên zêde di metadata pelê de hewce dike, tewra piştî bangek pergalê fallocate(), lê mezinahiya vê bandorê dikare cûda bibe. Ez pêşniyar dikim, ji bo performansa çêtirîn, bang bikim fallocate() ji bo pêşî li cîhê pêwîst veqetandin. Wê hingê divê ev cîh bi eşkere bi sifiran were dagirtin û bang kirin fsync(). Ev ê piştrast bike ku blokên têkildar ên di pergala pelan de wekî "veqetandî" ne wekî "nenaskirî" têne nîşankirin. Ev pêşveçûnek piçûk (nêzîkî 2%) performansê dide. Wekî din, dibe ku hin dîsk ji yên din xwedan gihandina yekem a blokê hêdîtir bin. Ev tê vê wateyê ku dagirtina cîhê bi sifiran dikare bibe sedema pêşveçûnek girîng (nêzîkî 100%) di performansê de. Bi taybetî, ev dikare bi dîskan re bibe AWS EBS (ev daneya nefermî ye, min nekarî wê piştrast bikim). Heman tişt ji bo hilanînê jî derbas dibe GCP Persistent Disk (û ev jixwe agahdariya fermî ye, ji hêla ceribandinan ve hatî pejirandin). Pisporên din jî heman tişt kirine çavkirinî, bi dîskên cihêreng ve girêdayî ye.
  2. Kêmtir bangên pergalê, performansa bilindtir dibe (qezenc dikare bi qasî 5%) be. Wekî dijwariyek xuya dike open() bi ala O_DSYNC an bang bikin pwritev2() bi ala RWF_SYNC ji bangekê zûtir fdatasync(). Ez guman dikim ku xala li vir ev e ku ev nêzîkatî di vê rastiyê de rolek dilîze ku ji bo çareserkirina heman pirsgirêkê pêdivî ye ku kêmtir bangên pergalê bêne kirin (li şûna du bangek). Lê cûdahiya performansê pir piçûk e, ji ber vê yekê hûn dikarin wê bi tevahî paşguh bikin û di serîlêdanê de tiştek bikar bînin ku dê mantiqa wê tevlihev neke.

Heke hûn di mijara hilanîna daneya domdar de eleqedar in, li vir çend materyalên kêrhatî hene:

  • Rêbazên gihîştina I / O - nêrîna bingehîn a mekanîzmayên ketin/derketinê.
  • Piştrastkirina daneyan digihîje dîskê - Çîrokek li ser çi diqewime daneyên di riya serîlêdanê ber bi dîskê.
  • Kengê pêdivî ye ku hûn pelrêça tê de senkronîze bikin - bersiva pirsa kengê bikar bînin fsync() ji bo derhêneran. Ji bo ku em vê yekê bi kurtasî bînin ziman, derdikeve holê ku hûn hewce ne ku hûn vê yekê bikin dema ku pelek nû çêbikin, û sedema vê pêşniyarê ew e ku di Linux-ê de dikare gelek referansên heman pelê hebin.
  • Servera SQL li ser Linux: FUA Navxweyî - Li vir ravekirinek e ka çawa hilanîna daneya domdar di SQL Server-ê de li ser platforma Linux-ê tête bicîh kirin. Li vir di navbera bangên pergala Windows û Linux de hin berhevokên balkêş hene. Ez hema piştrast im ku bi saya vê materyalê bû ku ez di derbarê xweşbînkirina FUA ya XFS de fêr bûm.

Ma we daneya ku we difikirî ku bi ewlehî li ser dîskê hatî hilanîn winda kir?

API-yên pelê yên pelê Linux û hilanîna daneya domdar

API-yên pelê yên pelê Linux û hilanîna daneya domdar

Source: www.habr.com