Bulutli tizimlarda ma'lumotlarni saqlash barqarorligini o'rganar ekanman, men asosiy narsalarni tushunganimga ishonch hosil qilish uchun o'zimni sinab ko'rishga qaror qildim. I barqaror ma'lumotlarni saqlash bilan bog'liq qanday kafolatlar (ya'ni, tizim ishlamay qolgandan keyin ma'lumotlar mavjud bo'lishini kafolatlash) bizga NMVe disklarini berishini tushunish uchun. Men quyidagi asosiy xulosalar qildim: ma'lumotlarni yozish buyrug'i berilgan paytdan boshlab uni saqlash vositasiga yozilgunga qadar ma'lumotlar buzilgan deb hisoblanishi kerak. Biroq, ko'pgina dasturlar ma'lumotlarni yozib olish uchun tizim qo'ng'iroqlaridan mamnuniyat bilan foydalanadilar.
Ushbu maqolada men fayl API'lari tomonidan taqdim etiladigan doimiy ma'lumotlarni saqlash mexanizmlarini o'rganaman. LinuxBu yerda hamma narsa oddiy bo'lishi kerakga o'xshaydi: dastur buyruqni chaqiradi write(), va bu buyruq bajarilgandan so'ng, ma'lumotlar diskda xavfsiz tarzda saqlanadi. Lekin write() faqat dastur ma'lumotlarini RAMda joylashgan yadro keshiga ko'chiradi. Tizimni diskka ma'lumotlarni yozishga majbur qilish uchun siz ba'zi qo'shimcha mexanizmlardan foydalanishingiz kerak.
Umuman olganda, ushbu material meni qiziqtirgan mavzuda o'rgangan narsalarimga oid eslatmalar to'plamidir. Agar biz eng muhimi haqida qisqacha gapiradigan bo'lsak, barqaror ma'lumotlarni saqlashni tashkil qilish uchun buyruqni ishlatish kerak bo'ladi. fdatasync() yoki bayroq bilan fayllarni oching O_DSYNC. Agar siz koddan diskka o'tayotganda ma'lumotlar bilan nima sodir bo'lishi haqida ko'proq bilmoqchi bo'lsangiz, ko'rib chiqing maqola.
write() funksiyasidan foydalanish xususiyatlari
Tizim chaqiruvi write() standartda belgilangan fayl deskriptoriga ma'lumotlarni yozishga urinish sifatida. Muvaffaqiyatli tugagandan so'ng write() Ma'lumotlarni o'qish operatsiyalari ilgari yozilgan baytlarni qaytarishi kerak, hatto ma'lumotlarga boshqa jarayonlar yoki oqimlardan kirish bo'lsa ham ( POSIX standartining tegishli bo'limi). , mavzularning oddiy fayl operatsiyalari bilan oʻzaro taʼsiri boʻlimida eslatma mavjud boʻlib, unda aytilishicha, agar ikkita ipning har biri ushbu funksiyalarni chaqirsa, u holda har bir qoʻngʻiroq boshqa qoʻngʻiroqning barcha belgilangan oqibatlarini koʻrishi yoki umuman koʻrmasligi kerak. oqibatlari. Bu barcha fayl kiritish-chiqarish operatsiyalari ular ishlayotgan resursda qulfni ushlab turishi kerak degan xulosaga olib keladi.
Bu operatsiya degani write() atommi? Texnik nuqtai nazardan, ha. Ma'lumotlarni o'qish operatsiyalari yozilganlarning hammasini yoki hech narsasini qaytarishi kerak write(). Ammo operatsiya write(), standartga ko'ra, yozilishi so'ralgan hamma narsani yozib olish bilan yakunlanishi shart emas. Unga ma'lumotlarning faqat bir qismini yozishga ruxsat beriladi. Misol uchun, bizda bitta fayl identifikatori tomonidan tasvirlangan faylga har biri 1024 bayt qo'shadigan ikkita mavzu bo'lishi mumkin. Standart nuqtai nazardan, har bir yozish operatsiyasi faylga faqat bitta bayt qo'shishi mumkin bo'lgan natija maqbul bo'ladi. Bu operatsiyalar atomik bo'lib qoladi, lekin ular tugallangandan so'ng ular faylga yozgan ma'lumotlar aralashib ketadi. Stack Overflow-da ushbu mavzu bo'yicha juda qiziqarli muhokama.
fsync() va fdatasync() funksiyalari
Diskka ma'lumotlarni o'chirishning eng oson yo'li funksiyani chaqirishdir . Ushbu funktsiya operatsion tizimdan barcha o'zgartirilgan bloklarni keshdan diskka o'tkazishni so'raydi. Bunga barcha fayl metama'lumotlari (kirish vaqti, faylni o'zgartirish vaqti va boshqalar) kiradi. Menimcha, bu metadata kamdan-kam hollarda kerak, shuning uchun agar bu siz uchun muhim emasligini bilsangiz, funksiyadan foydalanishingiz mumkin. fdatasync(). The haqida fdatasync() Aytishlaricha, ushbu funktsiyaning ishlashi davomida "quyidagi ma'lumotlarni o'qish operatsiyalarini to'g'ri bajarish uchun zarur bo'lgan" metama'lumotlarning shunday miqdori diskda saqlanadi. Va bu ko'pchilik ilovalar haqida qayg'uradi.
Bu erda paydo bo'lishi mumkin bo'lgan muammolardan biri shundaki, bu mexanizmlar faylni mumkin bo'lgan nosozlikdan keyin topishga kafolat bermaydi. Xususan, yangi fayl yaratishda siz qo'ng'iroq qilishingiz kerak fsync() uni o'z ichiga olgan katalog uchun. Aks holda, muvaffaqiyatsizlikdan so'ng, bu fayl mavjud emasligi aniqlanishi mumkin. Buning sababi shundaki, UNIX da qattiq havolalardan foydalanish tufayli fayl bir nechta kataloglarda mavjud bo'lishi mumkin. Shuning uchun, qo'ng'iroq qilganda fsync() Fayl qaysi katalog ma'lumotlarini diskka o'tkazish kerakligini bilishning hech qanday usuli yo'q ( Bu haqda ko'proq o'qishingiz mumkin). ext4 fayl tizimi bunga qodir ekan foydalanish fsync() tegishli fayllarni o'z ichiga olgan kataloglarga, lekin boshqa fayl tizimlarida bunday bo'lmasligi mumkin.
Ushbu mexanizm turli fayl tizimlarida turlicha amalga oshirilishi mumkin. foydalandim ext4 va XFS fayl tizimlarida qanday disk operatsiyalari ishlatilishi haqida ma'lumot olish uchun. Ikkalasi ham fayl mazmuni, ham fayl tizimi jurnali uchun diskka muntazam yozish buyruqlarini chiqaradi, keshni tozalaydi va jurnalga yozishni FUA (Force Unit Access, to'g'ridan-to'g'ri diskka ma'lumotlarni yozish, keshni chetlab o'tish) amalga oshirish orqali chiqadi. Ular, ehtimol, tranzaksiya amalga oshirilganligini tasdiqlash uchun buni qilishadi. FUA-ni qo'llab-quvvatlamaydigan drayvlarda bu ikkita keshni tozalashga olib keladi. Mening tajribalarim shuni ko'rsatdi fdatasync() biroz tezroq fsync(). Qulaylik blktrace shuni bildiradi fdatasync() Odatda diskka kamroq ma'lumot yozadi (ext4 fsync() 20 KiB yozadi va fdatasync() - 16 Kb). Bundan tashqari, men XFS ext4 dan biroz tezroq ekanligini bilib oldim. Va bu erda yordam bilan blktrace buni aniqlashga muvaffaq bo'ldi fdatasync() diskka kamroq ma'lumotlarni o'chiradi (XFSda 4 KiB).
fsync() dan foydalanishda yuzaga keladigan noaniq vaziyatlar
Men uchta noaniq vaziyat haqida o'ylashim mumkin fsync()Men amalda duch kelganman.
Birinchi bunday holat 2008 yilda sodir bo'lgan. Keyin Firefox 3 interfeysi diskka ko'p sonli fayllar yozilgan bo'lsa, muzlatib qo'ydi. Muammo shundaki, interfeysni amalga oshirishda uning holati haqidagi ma'lumotlarni saqlash uchun SQLite ma'lumotlar bazasidan foydalanilgan. Interfeysda sodir bo'lgan har bir o'zgarishdan so'ng, funktsiya chaqirildi fsync(), bu barqaror ma'lumotlarni saqlashning yaxshi kafolatlarini berdi. Keyinchalik ishlatiladigan ext3 fayl tizimida funksiya fsync() tizimdagi barcha "iflos" sahifalarni diskka tashladi, faqat tegishli fayl bilan bog'liq bo'lgan sahifalarni emas. Bu shuni anglatadiki, Firefox-da tugmani bosish magnit diskga yoziladigan megabayt ma'lumotlarni ishga tushirishi mumkin, bu ko'p soniyalarni oladi. Muammoning yechimi, men tushunganimdek material ma'lumotlar bazasi bilan ishlashni asinxron fon vazifalariga o'tkazish edi. Bu shuni anglatadiki, Firefox ilgari zarur bo'lgandan ko'ra qattiqroq saqlash talablarini amalga oshirgan va ext3 fayl tizimining xususiyatlari bu muammoni yanada kuchaytirgan.
Ikkinchi muammo 2009 yilda yuz berdi. Keyin, tizimning ishdan chiqishidan so'ng, yangi ext4 fayl tizimining foydalanuvchilari ko'plab yangi yaratilgan fayllar nol uzunlikka ega ekanligi bilan duch kelishdi, ammo bu eski ext3 fayl tizimida sodir bo'lmadi. Oldingi xatboshida men ext3 diskka juda ko'p ma'lumotni qanday yuvganligi haqida gapirgan edim, bu esa ishlarni juda sekinlashtirdi. fsync(). Vaziyatni yaxshilash uchun ext4-da faqat ma'lum bir faylga tegishli bo'lgan iflos sahifalar diskka tozalanadi. Va boshqa fayllardan olingan ma'lumotlar ext3-ga qaraganda ancha uzoq vaqt xotirada qoladi. Bu samaradorlikni oshirish uchun qilingan (sukut bo'yicha, ma'lumotlar 30 soniya davomida shu holatda qoladi, siz buni yordamida sozlashingiz mumkin. ; Bu haqda qo'shimcha materiallarni topishingiz mumkin). Bu shuni anglatadiki, katta hajmdagi ma'lumotlar muvaffaqiyatsizlikdan keyin qaytarib bo'lmaydigan darajada yo'qolishi mumkin. Ushbu muammoning echimi foydalanishdir fsync() ma'lumotlarning barqaror saqlanishini ta'minlash va ularni nosozliklar oqibatlaridan iloji boricha himoya qilish kerak bo'lgan ilovalarda. Funktsiya fsync() ext4 dan foydalanganda ext3 dan foydalanishga qaraganda ancha samarali ishlaydi. Ushbu yondashuvning kamchiligi shundaki, uni qo'llash, avvalgidek, dasturlarni o'rnatish kabi ba'zi operatsiyalarning bajarilishini sekinlashtiradi. Bu haqda tafsilotlarni ko'ring и .
Tegishli uchinchi muammo fsync(), 2018 yilda paydo bo'lgan. Keyin, PostgreSQL loyihasi doirasida, agar funktsiya aniqlandi fsync() xatoga duch kelsa, u "iflos" sahifalarni "toza" deb belgilaydi. Natijada, quyidagi qo'ng'iroqlar fsync() Ular bunday sahifalar bilan hech narsa qilmaydi. Shu sababli, o'zgartirilgan sahifalar xotirada saqlanadi va hech qachon diskka yozilmaydi. Bu haqiqiy falokat, chunki dastur ba'zi ma'lumotlar diskka yozilgan deb o'ylaydi, lekin aslida bunday bo'lmaydi. Bunday muvaffaqiyatsizliklar fsync() kamdan-kam uchraydi, bunday vaziyatlarda dastur muammoga qarshi kurashish uchun deyarli hech narsa qila olmaydi. Shu kunlarda, bu sodir bo'lganda, PostgreSQL va boshqa ilovalar ishdan chiqadi. , "Ilovalar fsync xatoliklaridan tiklana oladimi?" Materialida bu muammo batafsil o'rganilgan. Hozirgi vaqtda ushbu muammoning eng yaxshi yechimi bayroq bilan to'g'ridan-to'g'ri kiritish-chiqarishdan foydalanishdir O_SYNC yoki bayroq bilan O_DSYNC. Ushbu yondashuv yordamida tizim maxsus yozish operatsiyalari paytida yuzaga kelishi mumkin bo'lgan xatolar haqida xabar beradi, ammo bu yondashuv dasturdan buferlarni o'zi boshqarishini talab qiladi. Bu haqda ko'proq o'qing и .
O_SYNC va O_DSYNC bayroqlari yordamida fayllarni ochish
Keling, mexanizmlar muhokamasiga qaytaylik Linux, ma'lumotlarning barqaror saqlanishini ta'minlaydi. Xususan, biz bayroqdan foydalanish haqida gapiramiz O_SYNC yoki bayroq O_DSYNC tizim chaqiruvi yordamida fayllarni ochishda . Ushbu yondashuv bilan har bir ma'lumot yozish operatsiyasi har bir buyruqdan keyin bajariladi write() tizimga mos ravishda buyruqlar beriladi fsync() и fdatasync(). The bu "Sinxronlashtirilgan kiritish-chiqarish fayli yaxlitligini yakunlash" va "Ma'lumotlar yaxlitligini yakunlash" deb ataladi. Ushbu yondashuvning asosiy afzalligi shundaki, ma'lumotlar yaxlitligini ta'minlash uchun siz ikkita emas, balki faqat bitta tizim qo'ng'irog'ini qilishingiz kerak (masalan, - write() и fdatasync()). Ushbu yondashuvning asosiy kamchiligi shundaki, tegishli fayl deskriptoridan foydalangan holda barcha yozishlar sinxronlashtiriladi, bu esa dastur kodini tuzish imkoniyatini cheklashi mumkin.
O_DIRECT bayrog'i bilan Direct I/U dan foydalanish
Tizim chaqiruvi open() bayroqni qo'llab-quvvatlaydi O_DIRECT, bu disk bilan to'g'ridan-to'g'ri o'zaro ta'sir qilish orqali kiritish-chiqarish operatsiyalarini bajarish uchun operatsion tizim keshini chetlab o'tish uchun mo'ljallangan. Bu, ko'p hollarda, dastur tomonidan berilgan yozish buyruqlari to'g'ridan-to'g'ri disk bilan ishlashga qaratilgan buyruqlarga tarjima qilinishini anglatadi. Ammo, umuman olganda, bu mexanizm funktsiyalarni almashtirmaydi fsync() yoki fdatasync(). Haqiqat shundaki, diskning o'zi ham mumkin tegishli ma'lumotlarni yozish buyruqlari. Va bundan ham yomoni, ba'zi bir maxsus holatlarda bayroqdan foydalanishda I/U operatsiyalari bajariladi O_DIRECT, an'anaviy bufer operatsiyalariga. Ushbu muammoni hal qilishning eng oson yo'li fayllarni ochish uchun bayroqdan foydalanishdir O_DSYNC, bu har bir yozish operatsiyasidan keyin qo'ng'iroq bo'lishini anglatadi fdatasync().
Ma'lum bo'lishicha, XFS fayl tizimi yaqinda uchun "tezkor yo'l" qo'shgan O_DIRECT|O_DSYNC-ma'lumotlarni yozib olish. Agar blok yordamida qayta yozilsa O_DIRECT|O_DSYNC, keyin XFS keshni tozalash o'rniga, agar qurilma uni qo'llab-quvvatlasa, FUA yozish buyrug'ini bajaradi. Men buni yordamchi dastur yordamida tasdiqladim blktrace tizimda Linux 5.4 /Ubuntu 20.04. Bu yondashuv samaraliroq bo'lishi kerak, chunki u diskka minimal miqdordagi ma'lumotlarni yozadi va ikkita operatsiya o'rniga bitta operatsiyadan foydalanadi (keshni yozish va tozalash). Men havola topdim Ushbu mexanizmni amalga oshiradigan 2018 yadrosi. Ushbu optimallashtirishni boshqa fayl tizimlariga qo'llash haqida ba'zi munozaralar mavjud, ammo men bilganimdek, XFS hozirgacha buni qo'llab-quvvatlaydigan yagona fayl tizimidir.
sync_file_range() funktsiyasi
В Linux tizim chaqiruvi mavjud , bu butun faylni emas, balki faylning faqat bir qismini diskka tushirish imkonini beradi. Ushbu qo'ng'iroq ma'lumotlarni asinxron tozalashni boshlaydi va uning tugashini kutmaydi. Ammo sertifikatda sync_file_range() jamoa "juda xavfli" ekani aytiladi. Uni ishlatish tavsiya etilmaydi. Xususiyatlari va xavf-xatarlari sync_file_range() ichida juda yaxshi tasvirlangan material. Xususan, bu qo'ng'iroq RocksDB-dan yadro iflos ma'lumotlarni diskka qachon tozalashini nazorat qilish uchun ishlatadi. Shu bilan birga, barqaror ma'lumotlarni saqlashni ta'minlash uchun u ham qo'llaniladi fdatasync(). The RocksDB ushbu mavzu bo'yicha ba'zi qiziqarli sharhlarga ega. Misol uchun, bu qo'ng'iroq paydo bo'ladi sync_file_range() ZFS dan foydalanganda u ma'lumotlarni diskka o'tkazmaydi. Tajriba shuni ko'rsatadiki, kamdan-kam ishlatiladigan kodda xatolar bo'lishi mumkin. Shuning uchun, agar zarurat bo'lmasa, ushbu tizim chaqiruvidan foydalanishni maslahat beraman.
Ma'lumotlarning barqarorligini ta'minlashga yordam beradigan tizim qo'ng'iroqlari
Men ma'lumotlarning barqarorligini ta'minlaydigan kiritish-chiqarish operatsiyalarini bajarish uchun uchta yondashuvdan foydalanish mumkin degan xulosaga keldim. Ularning barchasi funksiya chaqiruvini talab qiladi fsync() fayl yaratilgan katalog uchun. Bu yondashuvlar:
- Funktsiyani chaqirish
fdatasync()yokifsync()funktsiyadan keyinwrite()(foydalanish yaxshiroqfdatasync()). - Bayroq bilan ochilgan fayl deskriptori bilan ishlash
O_DSYNCyokiO_SYNC(yaxshisi - bayroq bilanO_DSYNC). - Buyruqdan foydalanish
pwritev2()bayroq bilanRWF_DSYNCyokiRWF_SYNC(afzal bayroq bilanRWF_DSYNC).
Ishlash qaydlari
Men tekshirgan turli mexanizmlarning ishlashini diqqat bilan o'lchamaganman. Ularning ish tezligida men sezgan farqlar juda kichik. Bu shuni anglatadiki, men noto'g'ri bo'lishim mumkin va turli sharoitlarda bir xil narsa turli natijalar berishi mumkin. Birinchidan, men ishlashga ko'proq ta'sir qiladigan narsa haqida gapiraman, keyin esa unumdorlikka nima ta'sir qiladi.
- Fayl ma'lumotlarini qayta yozish faylga ma'lumot qo'shishdan ko'ra tezroq (ish samaradorligi 2-100% bo'lishi mumkin). Faylga ma'lumotlarni qo'shish tizim chaqiruvidan keyin ham faylning metama'lumotlariga qo'shimcha o'zgartirishlarni talab qiladi
fallocate(), lekin bu ta'sirning kattaligi farq qilishi mumkin. Men eng yaxshi ishlash uchun qo'ng'iroq qilishni tavsiya qilamanfallocate()kerakli joyni oldindan ajratish uchun. Keyin bu bo'shliq aniq nol bilan to'ldirilishi va chaqirilishi kerakfsync(). Bu fayl tizimidagi tegishli bloklarning "ajratilmagan" emas, balki "ajratilgan" deb belgilanishini ta'minlaydi. Bu unumdorlikni kichik (taxminan 2%) oshiradi. Bundan tashqari, ba'zi disklar blokga birinchi kirishni boshqalarga qaraganda sekinroq bo'lishi mumkin. Bu shuni anglatadiki, bo'sh joyni nol bilan to'ldirish ishlashning sezilarli (taxminan 100%) yaxshilanishiga olib kelishi mumkin. Xususan, bu disklar bilan sodir bo'lishi mumkin (bu norasmiy ma'lumotlar, tasdiqlay olmadim). Xuddi shu narsa saqlash uchun ham amal qiladi (va bu allaqachon rasmiy ma'lumot, sinovlar bilan tasdiqlangan). Boshqa mutaxassislar ham xuddi shunday qilishdi , turli disklar bilan bog'liq. - Tizim qo'ng'iroqlari qanchalik kam bo'lsa, unumdorlik shunchalik yuqori bo'ladi (daromad taxminan 5% bo'lishi mumkin). Qiyinchilikka o'xshaydi
open()bayroq bilanO_DSYNCyoki qo'ng'iroq qilingpwritev2()bayroq bilanRWF_SYNCqo'ng'iroqdan tezroqfdatasync(). O'ylaymanki, bu erda gap shundaki, bu yondashuv bir xil muammoni hal qilish uchun kamroq tizim qo'ng'iroqlari bajarilishi kerakligida rol o'ynaydi (ikkita o'rniga bitta qo'ng'iroq). Ammo ishlashdagi farq juda kichik, shuning uchun siz uni butunlay e'tiborsiz qoldirishingiz va dasturda uning mantig'ini murakkablashtirmaydigan biror narsadan foydalanishingiz mumkin.
Agar siz barqaror ma'lumotlarni saqlash mavzusiga qiziqsangiz, bu erda bir nechta foydali materiallar mavjud:
- — kiritish/chiqarish mexanizmlari asoslariga umumiy nuqtai.
- — dasturdan diskka o'tish yo'lida ma'lumotlar bilan nima sodir bo'lishi haqida hikoya.
- - qachon foydalanish kerakligi haqidagi savolga javob
fsync()kataloglar uchun. Qisqacha aytganda, yangi fayl yaratishda buni qilish kerak ekan va bu tavsiyaning sababi shundaki Linux Bitta faylga bir nechta havolalar bo'lishi mumkin. - — bu yerda platformada SQL Serverda doimiy ma'lumotlarni saqlash qanday amalga oshirilishining tavsifi keltirilgan. LinuxBu yerda tizim chaqiruvlari o'rtasida qiziqarli taqqoslashlar mavjud. Windows и LinuxMen deyarli aminmanki, aynan shu material tufayli XFS ning FUA optimallashtirishi haqida bilib oldim.
Diskda xavfsiz saqlangan deb o'ylagan ma'lumotlarni yo'qotdingizmi?
Manba: www.habr.com
