Panyimpenan Data Awet lan API File Linux

Nalika nliti kelestarian panyimpenan data ing sistem awan, aku mutusake kanggo nyoba dhewe kanggo mesthekake yen aku ngerti babagan dhasar kasebut. aku diwiwiti kanthi maca spesifikasi NVMe kanggo mangerteni apa sing njamin babagan panyimpenan data sustainable (yaiku, njamin yen data bakal kasedhiya sawise gagal sistem) menehi disk NMVe. Aku nggawe kesimpulan utama ing ngisor iki: data kudu dianggep rusak wiwit prentah nulis data diwenehake nganti wektu ditulis ing media panyimpenan. Nanging, umume program kanthi seneng nggunakake panggilan sistem kanggo ngrekam data.

Ing kirim iki, aku njelajah mekanisme panyimpenan terus-terusan sing diwenehake dening API file Linux. Iku misale jek sing kabeh kudu prasaja kene: program nelpon printah write(), lan sawise printah iki rampung, data bakal disimpen kanthi aman menyang disk. Nanging write() mung nyalin data aplikasi menyang cache kernel sing ana ing RAM. Kanggo meksa sistem nulis data menyang disk, sampeyan kudu nggunakake sawetara mekanisme tambahan.

Panyimpenan Data Awet lan API File Linux

Sakabèhé, materi iki minangka koleksi cathetan sing ana hubungane karo apa sing wis daksinaoni babagan topik sing dakkarepake. Yen kita ngomong kanthi ringkes babagan sing paling penting, ternyata kanggo ngatur panyimpenan data sing lestari sampeyan kudu nggunakake perintah kasebut. fdatasync() utawa mbukak file nganggo gendera O_DSYNC. Yen sampeyan kasengsem sinau luwih lengkap babagan apa sing kedadeyan karo data saka kode menyang disk, delengen iki artikel.

Fitur nggunakake fungsi nulis ().

Panggilan sistem write() ditetepake ing standar IEEE POSIX minangka upaya nulis data menyang deskriptor file. Sawise rampung sukses write() Operasi maca data kudu ngasilake persis bita sing sadurunge ditulis, nindakake iki sanajan data kasebut diakses saka proses utawa benang liyane (lah bagean sing relevan saka standar POSIX). iku, ing bagean babagan carane utas sesambungan karo operasi file normal, ana cathetan sing nyatakake yen rong utas saben nelpon fungsi kasebut, mula saben telpon kudu ndeleng kabeh konsekuensi sing ditemtokake saka telpon liyane, utawa ora ana. jalaran. Iki ndadékaké kanggo kesimpulan sing kabeh file I / O operasi kudu terus kunci ing sumber sing lagi operasi ing.

Apa iki tegese operasi write() iku atom? Saka sudut pandang teknis, ya. Operasi maca data kudu ngasilake kabeh utawa ora ana sing ditulis write(). Nanging operasi write(), miturut standar, ora kudu mungkasi kanthi nulis kabeh sing dijaluk nulis. Dheweke diijini nulis mung bagean saka data. Contone, kita bisa uga duwe rong utas saben nambah 1024 bait menyang file sing diterangake dening deskriptor file sing padha. Saka sudut pandang standar, asil sing bisa ditampa yaiku nalika saben operasi nulis bisa nambah mung siji bait menyang file kasebut. Operasi kasebut bakal tetep atom, nanging sawise rampung, data sing ditulis ing file kasebut bakal dicampur. kene diskusi menarik banget ing topik iki ing Stack Overflow.

fungsi fsync() dan fdatasync().

Cara paling gampang kanggo siram data menyang disk yaiku nelpon fungsi kasebut fsync(). Fungsi iki njaluk sistem operasi nransfer kabeh blok sing diowahi saka cache menyang disk. Iki kalebu kabeh metadata file (wektu akses, wektu modifikasi file, lan liya-liyane). Aku percaya yen metadata iki arang banget dibutuhake, dadi yen sampeyan ngerti yen ora penting kanggo sampeyan, sampeyan bisa nggunakake fungsi kasebut. fdatasync(). ing bantuan ing fdatasync() Disebutake yen sajrone operasi fungsi iki, jumlah metadata kasebut disimpen ing disk sing "perlu kanggo eksekusi sing bener saka operasi maca data ing ngisor iki." Lan iki sing paling penting kanggo aplikasi.

Siji masalah sing bisa muncul ing kene yaiku mekanisme kasebut ora njamin yen file kasebut bakal ditemokake sawise gagal. Utamane, nalika nggawe file anyar, sampeyan kudu nelpon fsync() kanggo direktori sing ngemot. Yen ora, sawise gagal, bisa uga file iki ora ana. Alesan kanggo iki yaiku ing UNIX, amarga nggunakake tautan keras, file bisa ana ing pirang-pirang direktori. Mulane, nalika nelpon fsync() Ora ana cara kanggo file ngerti data direktori sing uga kudu disiram menyang disk (kene Sampeyan bisa maca liyane babagan iki). Katon kaya sistem file ext4 bisa kanthi otomatis nggunakake fsync() menyang direktori sing ngemot file sing cocog, nanging iki bisa uga ora kedadeyan karo sistem file liyane.

Mekanisme iki bisa ditindakake kanthi beda ing sistem file sing beda. tak nggo blktrace kanggo sinau babagan operasi disk apa sing digunakake ing sistem file ext4 lan XFS. Loro-lorone ngetokake printah nulis reguler menyang disk kanggo isi file lan jurnal sistem file, siram cache, lan metu kanthi nindakake FUA (Akses Unit Angkatan, nulis data langsung menyang disk, ngliwati cache) nulis menyang jurnal. Padha mbokmenawa nindakake iki kanggo konfirmasi sing transaksi wis kelakon. Ing drive sing ora ndhukung FUA, iki nyebabake rong cache siram. Eksperimenku nuduhake fdatasync() rada cepet fsync(). Utilitas blktrace nuduhake yen fdatasync() biasane nulis kurang data menyang disk (ing ext4 fsync() nyerat 20 KiB, lan fdatasync() - 16 KiB). Uga, aku ngerteni manawa XFS rada luwih cepet tinimbang ext4. Lan ing kene kanthi bantuan blktrace ngatur kanggo mangerteni sing fdatasync() flushes kurang data menyang disk (4 KiB ing XFS).

Kahanan ambigu sing muncul nalika nggunakake fsync()

Aku bisa mikir telung kahanan ambigu babagan fsync()kang daktemoni ing laku.

Kasus kasebut pisanan kedadeyan ing taun 2008. Banjur antarmuka Firefox 3 beku yen akeh file ditulis ing disk. Masalahe yaiku implementasine antarmuka nggunakake database SQLite kanggo nyimpen informasi babagan negarane. Sawise saben pangowahan sing kedadeyan ing antarmuka, fungsi kasebut diarani fsync(), sing menehi jaminan panyimpenan data sing stabil. Ing sistem file ext3 banjur digunakake, fungsi fsync() mbuwang kabeh kaca "reged" ing sistem menyang disk, lan ora mung sing ana hubungane karo file sing cocog. Iki tegese ngeklik tombol ing Firefox bisa micu data megabyte sing bakal ditulis menyang disk magnetik, sing butuh sawetara detik. Solusi kanggo masalah, minangka adoh aku ngerti saka iku materi iki kanggo nransfer karya karo database kanggo tugas latar mburi bedo. Iki tegese Firefox sadurunge ngetrapake syarat panyimpenan sing luwih ketat tinimbang sing dibutuhake, lan fitur sistem file ext3 mung nambah masalah iki.

Masalah kapindho kedadeyan ing 2009. Banjur, sawise kacilakan sistem, pangguna sistem file ext4 anyar ngadhepi kasunyatan manawa akeh file sing mentas digawe duwe dawa nol, nanging iki ora kedadeyan karo sistem file ext3 sing lawas. Ing paragraf sadurunge, aku ngedika bab carane ext3 flushed kakehan data menyang disk, kang kalem iku akeh. fsync(). Kanggo nambah kahanan, ing ext4 mung kaca-kaca kotor sing cocog karo file tartamtu sing disiram menyang disk. Lan data saka file liyane tetep ing memori kanggo wektu sing luwih suwe tinimbang karo ext3. Iki wis rampung kanggo nambah kinerja (kanthi standar, data tetep ing negara iki kanggo 30 detik, sampeyan bisa ngatur iki nggunakake dirty_expire_centisecs; kene Sampeyan bisa nemokake bahan tambahan babagan iki). Iki tegese jumlah gedhe saka data bisa irretrievably ilang sawise Gagal. Solusi kanggo masalah iki yaiku nggunakake fsync() ing aplikasi sing perlu kanggo mesthekake panyimpenan data stabil lan nglindhungi sabisa saka jalaran saka gagal. Fungsi fsync() luwih efisien nalika nggunakake ext4 tinimbang nggunakake ext3. Kerugian saka pendekatan iki yaiku panggunaane, kaya sadurunge, nyuda eksekusi sawetara operasi, kayata nginstal program. Deleng rincian babagan iki kene и kene.

Masalah katelu babagan fsync(), diwiwiti ing 2018. Banjur, ing kerangka proyek PostgreSQL, ditemokake yen fungsi kasebut fsync() nemoni kesalahan, menehi tandha kaca "reged" minangka "resik". Akibaté, telpon ing ngisor iki fsync() Dheweke ora nindakake apa-apa karo kaca kasebut. Amarga iki, kaca sing diowahi disimpen ing memori lan ora tau ditulis ing disk. Iki minangka bilai nyata, amarga aplikasi bakal mikir yen sawetara data ditulis ing disk, nanging nyatane ora bakal. Gagal kaya ngono fsync() langka, aplikasi ing kahanan kaya mengkono meh ora bisa kanggo pertempuran masalah. Dina iki, nalika kedadeyan kasebut, PostgreSQL lan aplikasi liyane kacilakan. iku, ing materi "Bisa Aplikasi Waras saka Gagal fsync?", Masalah iki ditliti kanthi rinci. Saiki solusi paling apik kanggo masalah iki yaiku nggunakake Direct I / O kanthi bendera O_SYNC utawa nganggo gendera O_DSYNC. Kanthi pendekatan iki, sistem bakal nglaporake kesalahan sing bisa kedadeyan sajrone operasi nulis tartamtu, nanging pendekatan iki mbutuhake aplikasi kanggo ngatur buffer kasebut. Waca liyane babagan iki kene и kene.

Mbukak file nggunakake flag O_SYNC lan O_DSYNC

Ayo bali menyang diskusi babagan mekanisme Linux sing nyedhiyakake panyimpenan data sing stabil. Yaiku, kita ngomong babagan nggunakake gendera O_SYNC utawa gendera O_DSYNC nalika mbukak file nggunakake panggilan sistem mbukak (). Kanthi pendekatan iki, saben operasi nulis data ditindakake kaya sawise saben printah write() sistem diwenehi printah miturut fsync() и fdatasync(). ing Spesifikasi POSIX iki diarani "Sinkronisasi I / O File Integritas Completion" lan "Data Integrity Completion". Kauntungan utama saka pendekatan iki yaiku kanggo mesthekake integritas data, sampeyan mung kudu nelpon siji sistem, tinimbang loro (contone - write() и fdatasync()). Kerugian utama pendekatan iki yaiku kabeh tulisan nggunakake deskriptor file sing cocog bakal disinkronake, sing bisa mbatesi kemampuan kanggo nyusun kode aplikasi.

Nggunakake Direct I / O karo flag O_DIRECT

Panggilan sistem open() ndhukung flag O_DIRECT, sing dirancang kanggo ngliwati cache sistem operasi kanggo nindakake operasi I/O kanthi sesambungan langsung karo disk. Iki, ing pirang-pirang kasus, tegese nulis printah sing ditanggepi dening program bakal langsung diterjemahake menyang printah sing dituju kanggo nggarap disk. Nanging, ing umum, mekanisme iki ora ngganti fungsi fsync() utawa fdatasync(). Kasunyatan iku disk dhewe bisa nundha utawa cache printah nulis data cocog. Lan, sing luwih elek, ing sawetara kasus khusus, operasi I/O ditindakake nalika nggunakake gendera O_DIRECT, siaran menyang operasi buffer tradisional. Cara paling gampang kanggo ngatasi masalah iki yaiku nggunakake gendera kanggo mbukak file O_DSYNC, sing tegese saben operasi nulis bakal diterusake kanthi telpon fdatasync().

Ternyata sistem file XFS bubar nambahake "path cepet" kanggo O_DIRECT|O_DSYNC- ngrekam data. Yen blok ditulis maneh nggunakake O_DIRECT|O_DSYNC, banjur XFS, tinimbang siram cache, bakal nglakokake printah nulis FUA yen piranti ndhukung. Aku verifikasi iki kanthi nggunakake sarana blktrace ing sistem Linux 5.4/Ubuntu 20.04. Pendekatan iki kudu luwih efisien, amarga nalika digunakake, jumlah minimal data ditulis ing disk lan siji operasi digunakake, tinimbang loro (nulis lan ngresiki cache). Aku nemokake link menyang tambalan 2018 kernel, sing ngleksanakake mekanisme iki. Ana sawetara rembugan ana bab nglamar Optimization iki kanggo sistem file liyane, nanging minangka adoh aku ngerti, XFS mung sistem file sing ndhukung iki nganti saiki.

sync_file_range() fungsi

Linux duwe panggilan sistem sync_file_range(), sing ngijini sampeyan kanggo siram mung bagean saka file menyang disk, tinimbang kabeh file. Telpon iki miwiti siram data asinkron lan ora ngenteni rampung. Nanging ing sertifikat sync_file_range() tim ngandika "banget mbebayani". Ora dianjurake kanggo nggunakake. Fitur lan bebaya sync_file_range() banget uga diterangake ing iki materi. Khusus, telpon iki katon nggunakake RocksDB kanggo ngontrol nalika kernel ngetokke data sing reged menyang disk. Nanging ing wektu sing padha, kanggo njamin panyimpenan data sing stabil, uga digunakake fdatasync(). ing kode RocksDB duwe sawetara komentar sing menarik babagan topik iki. Contone, katon yen telpon sync_file_range() Nalika nggunakake ZFS, iku ora flush data menyang disk. Pengalaman ngandhani yen kode sing jarang digunakake bisa uga ngemot bug. Mulane, aku bakal menehi saran supaya ora nggunakake telpon sistem iki kajaba pancen perlu.

Panggilan sistem sing mbantu njamin ketekunan data

Aku wis teka menyang kesimpulan sing ana telung pendekatan sing bisa digunakake kanggo nindakake I / O operasi sing njamin terus-terusan data. Kabeh mau mbutuhake telpon fungsi fsync() kanggo direktori ing ngendi file kasebut digawe. Iki minangka pendekatan:

  1. Nelpon fungsi fdatasync() utawa fsync() sawise fungsi write() (luwih becik nggunakake fdatasync()).
  2. Nggarap deskriptor file dibukak nganggo gendera O_DSYNC utawa O_SYNC (luwih apik - nganggo gendera O_DSYNC).
  3. Nggunakake printah pwritev2() karo gendera RWF_DSYNC utawa RWF_SYNC (luwih becik nganggo gendera RWF_DSYNC).

Cathetan Kinerja

Aku wis ora kasebut kanthi teliti, ngukur kinerja saka macem-macem mekanisme aku wis sinaoni. Bentenipun aku weruh ing kacepetan karya sing cilik banget. Iki tegese aku bisa uga salah, lan ing kahanan sing beda-beda perkara sing padha bisa ngasilake asil sing beda. Kaping pisanan, aku bakal ngomong babagan apa sing luwih mengaruhi kinerja, banjur apa sing mengaruhi kinerja sing kurang.

  1. Nimpa data file luwih cepet tinimbang nambahake data menyang file (manfaat kinerja bisa 2-100%). Nambah data menyang file mbutuhake owah-owahan tambahan ing metadata file, sanajan sawise telpon sistem fallocate(), nanging gedhene efek iki bisa beda-beda. Aku nyaranake, kanggo kinerja paling apik, nelpon fallocate() kanggo pra-nyedhiyakake papan sing dibutuhake. Banjur papan iki kudu diisi kanthi nul lan diarani fsync(). Iki bakal mesthekake yen pamblokiran sing cocog ing sistem file ditandhani minangka "diparengake" tinimbang "ora dialokasikan". Iki menehi dandan kinerja cilik (bab 2%). Kajaba iku, sawetara disk bisa uga duwe akses sing luwih alon menyang blok tinimbang liyane. Iki tegese ngisi spasi kanthi nul bisa nyebabake peningkatan kinerja sing signifikan (kira-kira 100%). Utamane, iki bisa kedadeyan karo disk AWS EBS (iki data ora resmi, aku ora bisa konfirmasi). Padha dadi kanggo panyimpenan GCP Persistent Disk (lan iki wis informasi resmi, dikonfirmasi dening tes). Pakar liyane uga nindakake perkara sing padha pengamatan, related kanggo macem-macem disk.
  2. Sing kurang panggilan sistem, sing luwih dhuwur kinerja (gain bisa kira-kira 5%). Katon kaya tantangan open() karo gendera O_DSYNC utawa nelpon pwritev2() karo gendera RWF_SYNC luwih cepet tinimbang telpon fdatasync(). Aku curiga yen titik ing kene yaiku pendekatan iki nduweni peran ing kasunyatan manawa telpon sistem luwih sithik kudu ditindakake kanggo ngatasi masalah sing padha (siji telpon tinimbang loro). Nanging prabédan ing kinerja cilik banget, supaya sampeyan bisa nglirwakake lan nggunakake soko ing aplikasi sing ora bakal complicate logika sawijining.

Yen sampeyan kasengsem ing topik panyimpenan data sing lestari, ing ngisor iki sawetara bahan sing migunani:

  • Metode Akses I/O - ringkesan dhasar saka mekanisme input / output.
  • Njamin data tekan disk — crita bab apa mengkono kanggo data ing cara saka aplikasi kanggo disk.
  • Nalika sampeyan kudu fsync direktori sing ngemot - jawaban kanggo pitakonan nalika nggunakake fsync() kanggo direktori. Kanggo nggawe iki kanthi ringkes, sampeyan kudu nindakake iki nalika nggawe file anyar, lan alasan kanggo rekomendasi iki yaiku ing Linux bisa uga ana akeh referensi kanggo file sing padha.
  • SQL Server ing Linux: FUA Internals — ing kene ana katrangan babagan cara panyimpenan data sing terus-terusan ditindakake ing SQL Server ing platform Linux. Ana sawetara perbandingan sing menarik antarane telpon sistem Windows lan Linux ing kene. Aku meh yakin yen amarga materi iki aku sinau babagan optimasi FUA XFS.

Apa sampeyan wis ilang data sing sampeyan pikir wis disimpen kanthi aman ing disk?

Panyimpenan Data Awet lan API File Linux

Panyimpenan Data Awet lan API File Linux

Source: www.habr.com