Monolit muvaffaqiyatsizlik emas. Muvaffaqiyatli mahsulotlarning aksariyati monolit sifatida boshlanadi, chunki bitta ma’lumotlar bazasiga ega bitta kod bazasi mijozlar nimani xohlashini bilib olishning eng tez yo‘li. Muammo keyinroq boshlanadi: relizlar sekinlashadi, billingdagi o‘zgarish qidiruvni buzadi va buyurtmalar moduliga hech kim tegishni istamaydi. Shu paytda kimdir migratsiyani taklif qiladi va xavf shundaki, davo kasallikning o‘zidan ko‘proq zarar keltirishi mumkin.
Bu maqolada migratsiya qilish-qilmaslikni qanday hal qilish, qayerdan kesishni qanday topish va jonli tizimni unga tayanadigan biznesni to‘xtatmasdan qismma-qism qanday ko‘chirish haqida so‘z boradi.
Migratsiya kerakmi, shuni hal qiling
Arxitekturadan emas, muammodan boshlang. “Bizga mikroservislar kerak” degani yechim. Muammo esa odatda quyidagilardan biri bo‘ladi:
- Relizlar sekin yoki xavfli, chunki har bir o‘zgarish hamma narsaga tegadi.
- Tizimning bir qismi qolganidan butunlay boshqacha masshtablanishi kerak.
- Jamoalar bir-birini to‘sib qo‘yadi, chunki hammasi bitta kodda ishlaydi.
- Stekning bir qismi endi qo‘llab-quvvatlanmaydi va uni joyida yangilab bo‘lmaydi.
Muammoni yozib qo‘ying va uni tuzatishning eng arzon yo‘li qaysi ekanini so‘rang. Sekin relizlar ko‘pincha arxitektura emas, yig‘ish konveyeri (build pipeline) va testlar muammosi. Bitta qizib ketgan endpointni ko‘pincha kesh, navbat yoki o‘qish uchun replika bilan masshtablash mumkin. Eskirgan freymvorkni ba’zan o‘sha kod bazasi ichida modulma-modul yangilasa bo‘ladi.
Arzon yechimlar sinab ko‘rilgan bo‘lsa yoki ular yetarli bo‘lmasligi aniq bo‘lsa, migratsiya o‘zini oqlaydi. Shunda ham uning muhandis bo‘lmagan odam tekshira oladigan aniq maqsadi bo‘lishi kerak: “yangi arxitekturaga o‘tdik” emas, masalan, “buyurtmani rasmiylashtirish qismini to‘liq regression sinovisiz chiqara olamiz”.
Kesishdan oldin choklarni toping
Chok bu tizimni eng kam bezovtalik bilan ajratish mumkin bo‘lgan joy. Yaxshi choklar papkalar tuzilishiga emas, biznesga ergashadi. Quyidagi qismlarni qidiring:
- O‘z lug‘atiga ega. Agar ombor jamoasi “jo‘natma”, savdo jamoasi esa “buyurtma” deb bir-biriga bog‘liq, lekin turli narsalarni atasa, shu farq chegara bo‘ladi.
- O‘z sabablariga ko‘ra o‘zgaradi. Doim birga tahrirlanadigan kod birga turishi kerak. Boshqa ritmda o‘zgaradigan kod ko‘chirishga nomzod.
- Tizimning qolgan qismi bilan o‘nlab umumiy jadvallar orqali emas, bir nechta aniq chaqiruvlar orqali bog‘lanadi.
Bunda versiyalar tarixi yordam beradi. Bir xil commitlarda birga o‘zgaradigan fayllar haqiqiy bog‘liqlikni ko‘rsatadi va u ko‘pincha rejalashtirilgan dizayndan farq qiladi. Birinchi qismni tanlashdan oldin topgan bog‘liqliklaringizni, jumladan ma’lumotlar bazasidagilarini ham chizib chiqing.
Birinchi ko‘chiriladigan qism ahamiyatga ega bo‘lishi uchun yetarlicha qimmatli, lekin oxiriga yetkazish uchun yetarlicha kichik bo‘lishi kerak. Bildirishnomalar, hisobotlar, qidiruv va fayllar bilan ishlash ko‘pincha birinchi nomzodlar bo‘ladi, chunki ular chekkada joylashgan. Asosiy domen, ya’ni mahsulotni aynan shu mahsulot qiladigan qism, odatda keyinroq, jamoa kamroq muhim narsada mashq qilib olgach ko‘chiriladi.
Eski tizimni marshrutma-marshrut siqib chiqaring
Eng xavfsiz umumiy yondashuv “bo‘g‘uvchi anjir” (strangler fig) patterni. Martin Fowler uni mezbon daraxt atrofida o‘sadigan o‘simlik nomi bilan atagan. Siz monolitni qayta yozmaysiz. Uning oldiga nimadir qo‘yasiz va trafikni undan qismma-qism olib ketasiz.
Amalda bu quyidagicha kechadi:
- Monolit oldiga marshrutlash qatlamini qo‘ying. Bu teskari proksi (reverse proxy), API shlyuz yoki ilovaning o‘zidagi yupqa fasad bo‘lishi mumkin.
- Shu qatlam ortida bitta imkoniyatning yangi versiyasini yarating.
- Trafikning kichik ulushini yoki bitta foydalanuvchilar guruhini yangi versiyaga yuboring va natijalarni eskisi bilan solishtiring.
- Eski kod yo‘liga hech narsa kelmay qolguncha ulushni oshiring, so‘ng uni o‘chirib tashlang.
Oxirgi qadam eng muhimi. Eski kodni o‘chirmasdan yangi kod qo‘shadigan migratsiya sizga yuritish kerak bo‘lgan ikkita tizim qoldiradi. Har bir bo‘lak eski yo‘l olib tashlanishi va marshrutlash qoidasi soddalashishi bilan tugashi kerak.
Yangi va eski versiyalar bir xil ishlashi kerak bo‘lgan joyda ularni bir muddat yonma-yon yurgizing. Har bir so‘rovni ikkalasiga yuboring, foydalanuvchiga eski javobni qaytaring va har qanday farqni logga yozing. Bu soya davri har bir eski tizimda bo‘ladigan hujjatlashtirilmagan xatti-harakatlarni topadi.
Ma’lumotlarga kim egalik qilishini hal qiling
Kod oson qismi. Ko‘p migratsiyalar umumiy ma’lumotlar bazasida to‘xtab qoladi. Agar yangi komponent ham, monolit ham bir xil jadvallarni o‘qib-yozsa, siz hech narsani ajratmagansiz: endi hech kim o‘zgartira olmaydigan sxemaga ikkinchi yozuvchini qo‘shgansiz, xolos.
Intilish kerak bo‘lgan qoida shu: har bir ma’lumot bo‘lagining bitta egasi bor. Uni faqat egasi yozadi. Boshqalar egasidan API orqali yoki u e’lon qiladigan hodisalarni tinglash orqali so‘raydi.
Bunga asta-sekin erishiladi:
- Kim nimani yozishini xaritaga tushiring. Har bir jadvalni va unga yozadigan har bir kod qismini ro‘yxatga oling. Ko‘p joydan yoziladigan jadvallar tashvishlanishga arziydi.
- Avval yozuvlarni bitta joy orqali o‘tkazing. Ma’lumotlarni ko‘chirishdan oldin monolitning o‘zi har bir jadvalga bitta modul orqali yozadigan qiling. Ko‘pincha shuning o‘zi bog‘liqlikning yarmini yo‘qotadi.
- Avval nusxalang, keyin almashtiring. Yangi komponentga o‘z omborini bering, uni eskisi bilan sinxron ushlang (change data capture yoki ikki joyga yozib, natijalarni solishtirish orqali) va yozuvlardan oldin o‘qishlarni yangisiga o‘tkazing.
- Nusxalar mosligini tekshiring. Eski va yangi ma’lumotlarni solishtirib, farqlarni ko‘rsatadigan fon vazifasini ishga tushiring. U bir muddat hech qanday farq ko‘rsatmay turmaguncha to‘liq o‘tmang.
Hisobotlar va analitika ko‘pincha hamma joydan o‘qiydi. Ularga hodisalar yoki replikatsiya orqali to‘ldiriladigan o‘z o‘qish modelini bering, shunda ular eski sxemani saqlab qolish uchun sabab bo‘lmay qoladi.