JavaRush /Kurslar /All lectures for UZ purposes /ACIDni dasturning ichiga qanday kiritish mumkin: amaliyot...

ACIDni dasturning ichiga qanday kiritish mumkin: amaliyot

All lectures for UZ purposes
Daraja, Dars
Mavjud

8.1 Tranzaktsiya IDlari

U XID yoki TxID deb belgilanadi (agar farqi bo'lsa - ayting). TxID sifatida timestamp'larni ishlatish mumkin, agar biz muayyan vaqtga barcha harakatlarni tiklashni xohlasak kerak bo'ladi. Muammo, agar timestamp yetarli darajada aniqlikda bo'lmasa, tranzaktsiyalar bitta ID olishlari mumkin.

Shuning uchun, eng ishonchli variant - bu UUID yordamida noyob IDlar yaratish.


import java.util.UUID;

public class GenerateUUID {
    public static void main(String[] args) {
        System.out.println(UUID.randomUUID().toString()); // Misol: f50ec0b7-f960-400d-91f0-c42a6d44e3d0
        System.out.println(UUID.randomUUID().toString()); // Misol: d15bed89-c0a5-4a72-98d9-5507ea7bc0ba
    }
}

Shuningdek, tranzaktsiyani aniqlovchi ma'lumotlarni хэшlash va bu хэшni TxID sifatida ishlatish mumkin.

8.2 Qayta urinishlar ("retries")

Agar biz bilsak, funksiya yoki dastur idempotent bo'lsa, demak xato paytida ularni qayta chaqirishimiz mumkin va kerak. Biz zamonaviy ilovalar tarmoq va texnika bo'ylab tarqatilganligini hisobga olsak, ba'zi operatsiyalar muvaffaqiyatsiz tugashi mumkinligiga tayyor bo'lishimiz kerak. Xato serverning qulashi, tarmoqdagi xatolar yoki uzoq ilovaning ortiqcha yuklanishi tufayli yuzaga kelishi mumkin. Ilovamiz qanday harakat qilishi kerak? To'g'ri, operatsiyani qayta sinab ko'rish.

Bir bo'lak kod butun bir sahifa so'zlardan ko'proq məlumat bera olishini hisobga olib, keling, naive retrying ruhidagi operatsiyani qayta sinash mexanizmining qanday ishlashini ko'rib chiqaylik.


import java.util.logging.Level;
import java.util.logging.Logger;

import io.github.resilience4j.retry.Retry;
import io.github.resilience4j.retry.RetryConfig;
import io.github.resilience4j.retry.RetryRegistry;

public class DoSomethingUnreliable {

    private static final Logger LOGGER = Logger.getLogger(DoSomethingUnreliable.class.getName());

    private static final RetryRegistry RETRY_REGISTRY = RetryRegistry.ofDefaults();

    private static final Retry DO_SOMETHING_UNRELIABLE_RETRY = RETRY_REGISTRY.retry("doSomethingUnreliableRetry", RetryConfig.custom()
            .maxAttempts(5)
            .waitDuration(RetryConfig.exponentialWait(1, 4, 10))
            .retryOnException(IOException.class)
            .onRetry((retryContext) -> LOGGER.log(Level.DEBUG, "doSomethingUnreliable: {0} urinish {1} dan", new Object[]{retryContext.getAttemptCount(), retryContext.getNumberOfAttempts()}))
            .build());

    public static void main(String[] args) throws IOException {
        String result = doSomethingUnreliable();
        System.out.println(result);
        System.out.println(DO_SOMETHING_UNRELIABLE_RETRY.getMetrics().toString());
    }

    @Retry(name = "doSomethingUnreliableRetry")
    private static String doSomethingUnreliable() throws IOException {
        if (random.nextInt(10) > 1) {
            throw new IOException("Yoriq sous, hamma narsa buzilgan!");
        } else {
            return "Ajoyib sous!";
        }
    }
}

Ajoyib sous!
Statistika:
  nomi: doSomethingUnreliableRetry
  muvaffaqiyatli chaqiruvlar soni: 1
  xato bilan chaqiruvlar soni: 0
  qayta urinishlar soni: 0

Kurganimizdek, qayta urinishlarni kreativ tarzda tuzish mumkin.

  • Urinishlarni vaqt (10 soniya) yoki miqdor bo'yicha (5) chegaralash mumkin.
  • Shuningdek, urinishlar orasidagi vaqtni eksponential (ya'ni 2 ** ba'zi o'suvchi raqam n) yoki fiksirlangan tarzda oshirish mumkin (bu "congestion collapse" deyiladi).
  • Urinni faqat ba'zi xatolar uchun takrorlash mumkin.
  • Qayta urinishlarni maxsus log yozuvlari bilan boshlash yoki yakunlash mumkin.

Tranzaktsiyalar bilan ishlashning asosiy tushunchalarini o'rganganingizdan so'ng, keling, taqsimlangan tizimlarda tranzaktsiyalarni amalga oshirishga yordam beradigan ikki metod bilan tanishamiz.

8.3 Tranzaksiya ichki asboblari uchun ilg'or asboblar

Ushbu mavzuni ko'proq qamrab oladigan umumiy ta'riflarni beraman.

Two-phase commit (2pc). 2pc ikki bosqichdan iborat: tayyorgarlik va qat'iylik. Tayyorlanish vaqtida mikroxizmatlar ma'lumotlarni atomar o'zgartirishga tayyorlanadi. Shundan so'ng, yakuniy bosqichda haqiqiy o'zgarishlar amalga oshiriladi. Sinxronizatsiya uchun global koordinatsion talab etiladi, u kerakli obyektlarni bloklaydi. Agar biror mikroxizmat o'zgarishlarga tayyor bo'lmasa, koordinatr tranzaktsiyani to'xtatadi va qaytga o'tadi.

Ushbu protokol nima qilib beradi? U atomarlikni ta'minlaydi. Shuningdek, u yozishda va o'qishda izolyatsiyani kafolatlaydi. Bu shuni anglatadiki, bitta tranzaktsiyaning o'zgarishlari boshqa tranzaktsiyalarga koordinatr ularni ma'qullamaguncha ko'rinmaydi. Ammo bu xususiyatlar kamchilikka ega: protokol sinxron (bloklaydigan) bo'lgani uchun, u tizim ishini sekinlashtiradi (garchi RPC chaqiruvi o'zi sekin bo'lsa ham). O'zaro hibsga olish xavfi ham mavjud.

Saga shabloni barcha bog'langan mikroxizmatlarda asinxron lokal tranzaktsiyalarni ishlatadi. Mikroxizmatlar bir-biriga hodisalar shinasi orqali bog'langan. Agar bitta mikroxizmat o'z tranzaktsiyasini yakunlay olmasa, boshqa mikroxizmatlar kompensatsion tranzaktsiyalar yordamida o'zgarishlarni rollback qiladi.

Saganing afzalligi shundaki, hech qanday obyekt bloklanmaydi. Ammo, kamchiliklari ham bor.

Saganing debuggingi qiyin, ayniqsa ko'p mikroxizmatlar bo'lsa. Yana bir muammo Saga bilan - unda o'qish izolyatsiyasi yo'q. Ya'ni, agar ACID xususiyatlari muhim bo'lsa, Saga juda mos emas.

Nima kuzatyapmiz? Taqqoslangan tizimlarda va ACID kafolatlari bermaydigan BDlarda, ilova atomarlik va izolyatsiya uchun javobgar bo'lishi kerak. Demak, ishlab chiquvchi ziddiyatlarni hal qilish, qayt qilish, commit qilish va joyni bo'shatish kerak bo'ladi.

8.4 Qanday tushunish mumkin, qachon ACID kafolatlari kerak?

Bir nechta foydalanuvchi yoki jarayon bir vaqtning o'zida bitta va aynan bir ma'lumotlar bilan ishlashi ehtimoli juda katta.

Kechirasiz, lekin tipik misol bu moliyaviy tranzaktsiyalar.

Tranzaktsiyalar ketma-ketligi muhim bo'lgan holda.

Tasavvur qiling, sizning kompaniyangiz FunnyYellowChatdan FunnyRedChatga o'tishga qaror qildi, chunki unda giflarni yuborish mumkin. Ammo siz shunchaki messengerni almashtirmaysiz — siz kompaniyaningizning suhbatlarini boshqa messengerga ko'chirishingiz kerak.

Buni qilayotganingiz sabab, dasturchilar dasturlar va jarayonlarni markazlashtirilgan holda hujjatlashtirmagan, balki ularni messenjerning turli kanallarida joylashtirgan. Va sotuvchilar muzokaralar va kelishuvlar tafsilotlarini ham shu erda joylashtirgan. Shu sababli kompaniyaning butun hayoti u erda bo'lgan va hech kim ularning hammasini biror hujjatlash xizmatiga ko'chirish uchun vaqtlari yo'q edi, messenjerlarda qidiruv yaxshi ishlaganligi sababli, shunchaki hamma xabarlarni yangi joyga ko'chirishga qaror qildingiz.

Xabarlar ketma-ketligi muhim, chunki aks holda hamma narsa aralashib ketishi mumkin va siz qaysi savolga javob qaysi bo'lganini tushunolmaysiz.

Aytgancha, messenjerda yozishmalarning ketma-ketligini saqlash muhim, lekin agar ikki kishi bir chatda bir vaqtda yozayotgan bo'lsa, qaysi xabar birinchi kelishini farqi yo'q. Shu sababli, bu senariya uchun ACIDdan foydalanish talab etilmaydi.

Boshqa mumkin bo'lgan misol - bioinformatika. Men bu sohada ekspert emasman, lekin inson genomini dekodlashda ketma-ketlik muhimligini taxmin qilaman. Bioinformatika asboblarini va BDlarini ishlatadi, deb eshitdim.

Foydalanuvchiga yoki jarayonga eskirgan ma'lumotlarni bera olmaydigan holatda.

Moliyaviy tranzaktsiyalar. Boshqa misol o'ylay olmasdim.

Tugallanmagan tranzaktsiyalar katta xarajatlar bilan bog'liq bo'lgan holatda. Tasavvur qiling, agar shifokor va hamshira bir vaqtning o'zida bemorning kartasini yangilashsa va bir-birlarining o'zgarishlarini ustiga yozsa, chunki BD tranzaktsiyalarni izolyatsiya qila olmaydi. Sog'liqni saqlash tizimi - bu yana bir soha, unda ACID kafolatlari odatda juda muhimdir.

8.5 Qanday holatlarda ACID kerak emas?

Foydalanuvchilar faqat o'z shaxsiy ma'lumotlarini yangilayotgan holatda. Masalan, foydalanuvchi izoh qoldiradi yoki veb-sahifadagi eslatmalarini joylashtiradi. Yoki o'zining shaxsiy kabinetida xizmat ko'rsatuvchi provayderdagi shaxsiy ma'lumotlarini tahrirlaydi.

Foydalanuvchilar umuman ma'lumotlarni yangilashmaydi, balki faqat yangi ma'lumotlar qo'shishadi (append). Masalan, yugurish dasturi, sizning yugurishlaringiz haqidagi ma'lumotlarni saqlaydigan dasturni olib ko'ring: qancha yugurdingiz, qancha vaqt ichida, yo'l va h.k. Har yangi yugurish - yangi ma'lumotlar, eski ma'lumotlar tahrirlanmaydi. Ehtimol, ushbu ma'lumotlar asosida siz tahlil olasiz - va ushbu senariy uchun NoSQL BD mukammal mos keladi.

Biznes-loyihalar tranzaktsiyalarni bajarish tartibini belgilaydigan holatda muhim emas. YouTubedagi blogger uchun, yangi material ishlab chiqarish uchun jonli efirda xayriya oladi, kim va qaysi tartibda pul xayriya qilishi muhim emas.

Foydalanuvchilar bir veb-sahifa yoki ilova oynasida bir necha soniya yoki hatto daqiqa vaqt davomida bo'lishsa, ular eskirgan ma'lumotlarni ko'rishlari mumkin. Bunday holatlar onlayn yangiliklar media, YouTube yoki Habrni ko'rishda paydo bo'lishi mumkin. Agar siz uchun tizimda vaqtincha to'liq bo'lmagan tranzaktsiyalar saqlanib qolishi muhim bo'lmasa, ularni yo'qotmasdan e'tiborsiz qoldirishingiz mumkin.

Agar siz bir nechta manbalardan ma'lumotlar yig'ayotgan bo'lsangiz va ular tez-tez yangilansa, masalan, shahardagi bo'sh to'xtash joylari haqidagi ma'lumotlar, har 5 daqiqada o'zgarishlar bo'lsa, siz uchun bir vaqtda tranzaktsiya o'tmay qolsa muammo bo'lmaydi. Ammo, albatta, hammasi ushbu ma'lumotlar bilan nima qilmoqchi ekanligingizga bog'liq...


Tranzaktsiyalar, ACID va CAP

Izohlar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION