CDC: ma'lumotlar bazasi o'zgarishlarini ushlash
Bir mijozning telefon qo'ng'irog'i
Dushanba. RostUy da uy egasi Chilonzorda kvartira e'lon qildi: 5 million so'm.
Seshanba. Uyni ko'rgani ikki kishi keldi, ikkalasi ham rozi. Ega narxni ko'tardi: 6 million.
Chorshanba. Uy ijaraga berildi. Ega e'lonni o'chirdi.
Payshanba ertalab sizning telefoningiz jiringlaydi. Mijoz jahlda:
— Saytingizda Chilonzorda 5 millionlik uy turibdi. Qo'ng'iroq qildim, "u allaqachon berilgan" deyishdi. Nega saytda turibdi?
Siz omboringizni ochasiz. Haqiqatan ham: e'lon bor, holati faol, narxi 5 million.
Uch xato bitta qatorda. Qanday qilib?
Har kecha ishlaydigan "ishonchli" skript
Aybdorni topish qiyin emas. Har kecha soat 2 da shu so'rov ishlaydi:
SELECT * FROM elon WHERE yangilandi > '<oxirgi tekshiruv>';
Bu usul polling deyiladi — "so'rab-surishtirish". Mantiq oddiy: "oxirgi marta tekshirganimdan keyin o'zgargan qatorlarni ber".
Nega u uchala xatoni ham qildi:
Narx 5 million qolgani. Dushanba kechasi skript ishladi va 5 millionlik e'lonni ko'chirdi. To'g'ri ishladi. Lekin seshanba kuni narx 6 ga ko'tarilganda... yo'q, seshanba kechasi ham ishlashi kerak edi. Ishladi ham. Demak muammo boshqa joyda.
E'lon hali "faol" turgani. Mana asosiy sabab. Chorshanba kuni ega e'lonni o'chirdi.
Endi so'rovni o'ylang: SELECT ... WHERE yangilandi > .... O'chirilgan qator jadvalda
yo'q. Yo'q qatorni SELECT qanday topsin?
Javob: hech qanday. O'chirish — polling uchun ko'rinmas hodisa. E'lon omborda abadiy "faol" bo'lib qoladi.
Narx tarixi yo'qolgani. Agar ega seshanba kuni narxni ikki marta o'zgartirgan bo'lsa (5 → 5.5 → 6), kechasi ishlagan skript faqat oxirgi qiymatni ko'radi: 6. Oraliq qadam hech qachon qayd etilmaydi. "Narx qanday o'zgarib bordi?" degan savolga javob yo'q.
Bu uchtasi jim o'tadi. Xato xabari yo'q, log da qizil qator yo'q. Faqat bir kuni mijoz qo'ng'iroq qiladi.
Postgres allaqachon hammasini yozib turibdi
Endi yaxshi xabar.
Do'kondagi kassirni tasavvur qiling. U har sotuvni avval daftarga yozadi, keyin pulni kassaga soladi. Nega shunday? Chunki svet o'chsa, kassa yopilsa, daftar qoladi — ertaga hammasini tiklash mumkin.
Postgres ham aynan shunday ishlaydi. Har bir o'zgarish avval WAL ga yoziladi (Write-Ahead Log — "oldindan yozish jurnali"), keyin jadvalga qo'llanadi. Sabab bir xil: server qulasa, Postgres WAL ni o'qib o'zini tiklaydi.
Mana eng muhim jumla: bu jurnal allaqachon mavjud. Siz uni yaratmaysiz, yoqmaysiz, qo'shimcha kod yozmaysiz. U hozir ham yozilmoqda.
CDC (Change Data Capture — "o'zgarishlarni ushlash") shunchaki o'sha jurnalni o'qiydi.
Shuning uchun CDC polling dan ustun: polling jadvalning hozirgi holatiga qaraydi, CDC esa nima sodir bo'lganiga. O'chirilgan qator jadvalda yo'q, lekin jurnalda "DELETE" yozuvi turibdi. Ikki marta o'zgargan narx jadvalda bitta qiymat, jurnalda esa ikkita yozuv.
Shu bobda ikkala usulni ham ishga tushiramiz va nechta o'zgarishni ko'rganini sanaymiz.
diagramma( { "Postgres\n(RostUy)": (0, 1.6, 2.2, 1.1, "manba"), "WAL\n(tranzaksiya jurnali)": (3.0, 1.6, 2.4, 1.1, "qayta"), "Replikatsiya\nsloti": (6.2, 1.6, 2.2, 1.1, "qayta"), "Kafka\n(10-bob)": (9.2, 1.6, 2.0, 1.1, "saqlash"), "Polling\n(SELECT ...)": (3.0, -0.2, 2.4, 1.0, "xizmat"), }, [ ("Postgres\n(RostUy)", "WAL\n(tranzaksiya jurnali)", "har commit"), ("WAL\n(tranzaksiya jurnali)", "Replikatsiya\nsloti"), ("Replikatsiya\nsloti", "Kafka\n(10-bob)"), ("Postgres\n(RostUy)", "Polling\n(SELECT ...)", "har N daqiqa"), ], nom="cdc_yol.png", kenglik=13, izoh="Ikki yo'l: pastdagisi oson va kamchilikli, yuqoridagisi WAL ni to'g'ridan o'qiydi.", )

Ikki yo'l: pastdagisi oson va kamchilikli, yuqoridagisi WAL ni to'g'ridan o'qiydi.
Bazani ko'taramiz
15455-port — sizdagi boshqa Postgres larga tegmaslik uchun.
docker rm -f kitob-pg > /dev/null 2>&1 docker run -d --name kitob-pg -p 15455:5432 \ -e POSTGRES_PASSWORD=kitob -e POSTGRES_DB=rostuy \ postgres:16 -c wal_level=logical -c max_replication_slots=4 -c max_wal_senders=4 > /dev/null echo "konteyner ishga tushdi" for i in $(seq 1 60); do docker exec kitob-pg pg_isready -U postgres > /dev/null 2>&1 && { echo "baza ${i} soniyada tayyor"; break; } sleep 1 done docker exec kitob-pg psql -U postgres -d rostuy -tAc "SHOW wal_level;" | sed 's/^/wal_level: /'
konteyner ishga tushdi baza 2 soniyada tayyor wal_level: logical
`wal_level=logical` bo'lmasa CDC yo'q
Postgres ning standart sozlamasi replica. Bu rejimda WAL da faqat "qaysi blok o'zgardi" yoziladi
— qaysi qator va qanday qiymat emas.
logical ga o'tkazish uchun serverni qayta ishga tushirish kerak va WAL hajmi ortadi. Ishlab
chiqarishda buni DBA bilan kelishmasdan qilmang; lekin bu qadamsiz hech qanday CDC vositasi
(Debezium ham) ishlamaydi.
Jadval va boshlang'ich ma'lumot
Haqiqiy RostUy e'lonlaridan 2000 tasini yuklaymiz. elon_id birlamchi kalit bo'lgani uchun
takroriy id larni oldindan tashlaymiz — aks holda INSERT duplicate key bilan to'xtaydi.
python3 -c " import psycopg2, pandas as pd d = pd.read_csv('../datasets/ijara.csv').drop_duplicates('elon_id').head(2000) c = psycopg2.connect(host='localhost', port=15455, user='postgres', password='kitob', dbname='rostuy') c.autocommit = True k = c.cursor() k.execute(''' DROP TABLE IF EXISTS elon; CREATE TABLE elon ( elon_id text PRIMARY KEY, tuman text, narx_mln numeric, xonalar int, holat text DEFAULT 'faol', yangilandi timestamp DEFAULT now() );''') qatorlar = [(r.elon_id, r.tuman, float(r.narx_mln), int(r.xonalar)) for r in d.itertuples()] k.executemany('INSERT INTO elon (elon_id,tuman,narx_mln,xonalar) VALUES (%s,%s,%s,%s)', qatorlar) k.execute('SELECT count(*) FROM elon') print('jadvaldagi e\\'lonlar:', k.fetchone()[0]) c.close() "
jadvaldagi e'lonlar: 2000
Slot ochamiz
Bitta muammo bor va uni hal qilmasak, butun g'oya ishlamaydi.
WAL cheksiz o'smaydi. Postgres uni vaqti-vaqti bilan tozalab turadi — aks holda disk to'lib qolardi. Mantiq oddiy: "bu qism allaqachon jadvalga qo'llangan, endi kerak emas, o'chiraman".
Lekin bizga kerak. Biz uni hali o'qimadik.
Gazeta obunasini tasavvur qiling. Kioskda gazetalar bir hafta turadi, keyin tashlab yuboriladi. Siz ta'tilga chiqsangiz, qaytganingizda eski sonlar yo'q.
Yechim — obuna ochish: "menga saqlab turing, men kelib olaman". Kioskchi endi sizning nomingizga qo'yib boradi.
Postgres da bu obuna replikatsiya sloti deb ataladi. U aytadi: "men shu nuqtadan o'qiyapman — mendan oldingi WAL ni o'chirma".
Ikki natija:
- Siz xotirjam o'qiysiz, hech narsa yo'qolmaydi.
- Postgres endi sizni kutadi — va bu keyinroq xavfli bo'lib chiqadi (bob oxirida ko'rasiz).
Muhim nozik joy: slot ochilgandan keyingi o'zgarishlar saqlanadi. Undan oldingisi yo'q — siz obunani bugun ochsangiz, kechagi gazeta baribir yo'q.
python3 -c " import psycopg2 c = psycopg2.connect(host='localhost', port=15455, user='postgres', password='kitob', dbname='rostuy') c.autocommit = True k = c.cursor() k.execute(\"SELECT count(*) FROM pg_replication_slots WHERE slot_name='kitob_slot'\") if k.fetchone()[0] == 0: k.execute(\"SELECT pg_create_logical_replication_slot('kitob_slot','test_decoding')\") print('slot yaratildi:', k.fetchone()[0]) else: print('slot allaqachon bor') k.execute('SELECT slot_name, plugin, active FROM pg_replication_slots') print('slotlar:', k.fetchall()) c.close() "
slot yaratildi: (kitob_slot,0/19B9258)
slotlar: [('kitob_slot', 'test_decoding', False)]
test_decoding — Postgres ichiga qurilgan, o'qishga qulay plagin. Ishlab chiqarishda pgoutput
yoki Debezium ishlatiladi, lekin mexanizm aynan shu.
Polling nimani o'tkazib yuboradi
Endi asosiy tajriba. Ikki "tekshiruv" orasida tipik kun bo'ladi: yangi e'lonlar qo'shiladi, narxlar o'zgaradi, ba'zilari o'chiriladi. Ba'zi e'lon ikki marta yangilanadi.
Keyin ikkala usulni ham ishlatamiz va nechta o'zgarishni ko'rganini sanaymiz.
python3 -c " import psycopg2, collections c = psycopg2.connect(host='localhost', port=15455, user='postgres', password='kitob', dbname='rostuy') c.autocommit = True k = c.cursor() k.execute('SELECT now()') oxirgi_tekshiruv = k.fetchone()[0] # --- ikki tekshiruv orasidagi kun --- k.execute('''INSERT INTO elon (elon_id,tuman,narx_mln,xonalar) SELECT 'Y'||g, 'Yunusobod', 5.0, 2 FROM generate_series(1,50) g''') k.execute(\"UPDATE elon SET narx_mln=narx_mln*1.1, yangilandi=now() WHERE elon_id IN (SELECT elon_id FROM elon ORDER BY elon_id LIMIT 30)\") k.execute(\"UPDATE elon SET narx_mln=narx_mln*1.2, yangilandi=now() WHERE elon_id IN (SELECT elon_id FROM elon ORDER BY elon_id LIMIT 30)\") k.execute(\"DELETE FROM elon WHERE elon_id IN (SELECT elon_id FROM elon ORDER BY elon_id DESC LIMIT 20)\") haqiqiy = 50 + 30 + 30 + 20 print(f'haqiqatda sodir bo\\'lgan o\\'zgarishlar: {haqiqiy}') print(' 50 INSERT, 30 UPDATE, yana 30 UPDATE (bir xil qatorlar), 20 DELETE') print() # --- 1-usul: polling --- k.execute('SELECT count(*) FROM elon WHERE yangilandi > %s', (oxirgi_tekshiruv,)) polling = k.fetchone()[0] print(f'POLLING ko\\'rdi : {polling} qator') # --- 2-usul: CDC --- k.execute(\"SELECT data FROM pg_logical_slot_get_changes('kitob_slot',NULL,NULL)\") hodisalar = [d for (d,) in k.fetchall()] tur = collections.Counter() for h in hodisalar: for t in ('INSERT','UPDATE','DELETE'): if f': {t}:' in h: tur[t] += 1 print(f'CDC ko\\'rdi : {sum(tur.values())} o\\'zgarish -> {dict(tur)}') print() print(f'polling o\\'tkazib yuborgan: {haqiqiy - polling} ta o\\'zgarish') c.close() "
haqiqatda sodir bo'lgan o'zgarishlar: 130
50 INSERT, 30 UPDATE, yana 30 UPDATE (bir xil qatorlar), 20 DELETE
POLLING ko'rdi : 60 qator
CDC ko'rdi : 130 o'zgarish -> {'INSERT': 50, 'UPDATE': 60, 'DELETE': 20}
polling o'tkazib yuborgan: 70 ta o'zgarish
Endi bob boshidagi telefon qo'ng'irog'iga qayting. Mijoz nega jahli chiqqanini raqamlar tushuntiradi.
Polling uchta narsani boy berdi:
- DELETE lar butunlay ko'rinmaydi. O'chirilgan qator yo'q — uni
SELECTtopa olmaydi. Omborda o'sha e'lon abadiy "faol" bo'lib qoladi. - Oraliq UPDATE lar yo'qoladi. Bir qator ikki marta yangilangan bo'lsa, polling faqat oxirgi holatni ko'radi. Narx 5.0 → 5.5 → 6.6 bo'lgani bilinmaydi.
- Polling qator sanaydi, CDC esa o'zgarish sanaydi. Tahlil uchun farqi katta.
Chilonzordagi kvartira aynan 1-sabab tufayli omborda qolib ketgan edi. Ega uni o'chirgan,
lekin SELECT o'chirilgan qatorni ko'rmaydi — shuning uchun ombor uni hech qachon
"berilgan" deb belgilamagan. CDC da esa o'sha o'chirish DELETE hodisasi bo'lib turibdi.
"Biz soft-delete ishlatamiz, muammo yo'q"
To'g'ri, holat='ochirildi' qo'yish DELETE muammosini hal qiladi. Lekin qolgan ikkitasi
qoladi: oraliq o'zgarishlar baribir yo'qoladi, va endi butun jamoa hech qachon DELETE
yozmasligiga ishonasiz. Bitta DELETE yetadi.
Soft-delete — intizom talab qiladigan kelishuv. CDC — mexanizm. Mexanizm ishonchliroq.
O'zgarishlarni Kafka ga uzatamiz
Hozir CDC ishlayapti, lekin quvur hali tugamagan. Bitta muhim savol qoldi:
O'qilgan o'zgarish qayerga boradi?
Hozircha u ekranga chiqmoqda. Lekin omborga, hisobotga va modelga ham kerak — ya'ni bir nechta iste'molchiga.
10-bobdagi rasmni eslang: uchta manba, to'rtta iste'molchi, o'n ikkita chiziq. Aynan o'sha muammo shu yerda qaytadi.
Va bundan tashqari, CDC ning o'z xususiyati bor: slotdan o'qilgan o'zgarish yo'qoladi.
pg_logical_slot_get_changes — bu "o'qi va o'chir" degani. Ikkinchi marta chaqirsangiz,
o'sha hodisalar qaytmaydi.
Demak agar siz WAL dan to'g'ridan-to'g'ri omborga yozsangiz va yozish paytida xato bo'lsa — hodisa butunlay yo'qoladi. Uni hech qayerdan tiklab bo'lmaydi.
Shuning uchun CDC deyarli har doim Kafka bilan juftlanadi:
- CDC slotdan bir marta o'qiydi va darhol Kafka ga yozadi;
- Kafka esa uni saqlab turadi (10-bob: jurnal, navbat emas);
- iste'molchilar o'z tezligida o'qiydi, kerak bo'lsa qaytadan.
Ya'ni Kafka bu yerda "bufer" emas — u xavfsizlik to'ri. Endi ikkalasini ulaymiz.
docker rm -f kitob-kafka > /dev/null 2>&1 docker run -d --name kitob-kafka -p 19092:9092 \ -e KAFKA_NODE_ID=1 -e KAFKA_PROCESS_ROLES=broker,controller \ -e KAFKA_LISTENERS=PLAINTEXT://:9092,CONTROLLER://:9093 \ -e KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://localhost:19092 \ -e KAFKA_CONTROLLER_LISTENER_NAMES=CONTROLLER \ -e KAFKA_LISTENER_SECURITY_PROTOCOL_MAP=CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT \ -e KAFKA_CONTROLLER_QUORUM_VOTERS=1@localhost:9093 \ -e KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR=1 \ -e KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR=1 \ -e KAFKA_TRANSACTION_STATE_LOG_MIN_ISR=1 \ -e KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS=0 \ apache/kafka:3.9.0 > /dev/null for i in $(seq 1 60); do python3 -c "from kafka import KafkaAdminClient; KafkaAdminClient(bootstrap_servers='localhost:19092')" > /dev/null 2>&1 \ && { echo "kafka ${i} soniyada tayyor"; break; } sleep 1 done
kafka 1 soniyada tayyor
Quvurni yozamiz: WAL dan o'qib, tahlil qilib, Kafka ga yuboradi.
shu faylni yaratingsrc/quvur/cdc.py
"""Postgres WAL -> Kafka. Minimal, lekin haqiqiy CDC quvuri.""" import json import re from typing import Any, Iterator QATOR = re.compile(r"table (\S+): (INSERT|UPDATE|DELETE): (.*)") MAYDON = re.compile(r"(\w+)\[[\w ]+\]:('(?:[^']|'')*'|\S+)") def tahlil(qator: str) -> dict[str, Any] | None: """test_decoding matnini dict ga aylantiradi. BEGIN/COMMIT -> None.""" m = QATOR.match(qator) if not m: return None jadval, amal, qolgan = m.groups() qiymat = {} for nom, xom in MAYDON.findall(qolgan): if xom.startswith("'"): qiymat[nom] = xom[1:-1].replace("''", "'") elif xom == "null": qiymat[nom] = None else: qiymat[nom] = xom return {"jadval": jadval, "amal": amal, "qiymat": qiymat} def oqim(kursor, slot: str, limit: int | None = None) -> Iterator[dict[str, Any]]: """Slotdagi o'zgarishlarni o'qiydi va tahlil qilib beradi.""" kursor.execute( "SELECT data FROM pg_logical_slot_get_changes(%s, NULL, %s)", (slot, limit) ) for (xom,) in kursor.fetchall(): h = tahlil(xom) if h: yield h def kafka_xabari(hodisa: dict[str, Any]) -> tuple[str, bytes]: """Kalit = birlamchi kalit, shuning uchun bir e'lon bitta partitionda qoladi.""" kalit = hodisa["qiymat"].get("elon_id", "") return kalit, json.dumps(hodisa, ensure_ascii=False).encode()
python3 -c " import sys, collections; sys.path.insert(0, 'src') import psycopg2 from kafka import KafkaProducer from quvur.cdc import oqim, kafka_xabari c = psycopg2.connect(host='localhost', port=15455, user='postgres', password='kitob', dbname='rostuy') c.autocommit = True k = c.cursor() # yangi o'zgarishlar yaratamiz k.execute(\"UPDATE elon SET holat='sotildi' WHERE tuman='Chilonzor'\") k.execute(\"DELETE FROM elon WHERE elon_id LIKE 'Y%'\") p = KafkaProducer(bootstrap_servers='localhost:19092') tur = collections.Counter() for h in oqim(k, 'kitob_slot'): kalit, qiymat = kafka_xabari(h) p.send('elon-cdc', key=kalit.encode(), value=qiymat) tur[h['amal']] += 1 p.flush() print('Kafka ga yuborildi:', dict(tur), '-> jami', sum(tur.values())) c.close() " 2>&1 | grep -v Warning
Kafka ga yuborildi: {'UPDATE': 185, 'DELETE': 30} -> jami 215
O'qib ko'ramiz — o'zgarishlar haqiqatan yetib borganmi:
python3 -c " import json, collections from kafka import KafkaConsumer c = KafkaConsumer('elon-cdc', bootstrap_servers='localhost:19092', auto_offset_reset='earliest', group_id='ombor', consumer_timeout_ms=5000) tur = collections.Counter() namuna = {} for m in c: h = json.loads(m.value) tur[h['amal']] += 1 namuna.setdefault(h['amal'], h) c.close() print('Kafka dan o\\'qildi:', dict(tur)) print() for amal in ('UPDATE', 'DELETE'): if amal in namuna: q = namuna[amal]['qiymat'] print(f'{amal:7s} namuna: {dict(list(q.items())[:4])}') " 2>&1 | grep -v Warning
Kafka dan o'qildi: {'UPDATE': 185, 'DELETE': 30}
UPDATE namuna: {'elon_id': 'E345049', 'tuman': 'Chilonzor', 'narx_mln': '5.69', 'xonalar': '2'}
DELETE namuna: {'elon_id': 'Y14'}
DELETE hodisasida faqat birlamchi kalit borligiga e'tibor bering — Postgres o'chirilgan qatorning
qolgan ustunlarini WAL ga yozmaydi (agar REPLICA IDENTITY FULL qo'yilmagan bo'lsa).
Snapshot va oqim
Bitta savol qoladi: slot ochilgunga qadar jadvalda turgan e'lonlar-chi? Ular WAL da yo'q.
Javob — ikki bosqich:
import pandas as pd show(pd.DataFrame([ {"Bosqich": "1. Snapshot", "Nima qiladi": "Jadvalni to'liq o'qib ko'chiradi", "Qachon": "Bir marta, boshida", "Manba": "SELECT *"}, {"Bosqich": "2. Oqim", "Nima qiladi": "Faqat o'zgarishlarni uzatadi", "Qachon": "Doimiy", "Manba": "WAL sloti"}, ]))
| Bosqich | Nima qiladi | Qachon | Manba |
|---|---|---|---|
| 1. Snapshot | Jadvalni to'liq o'qib ko'chiradi | Bir marta, boshida | SELECT * |
| 2. Oqim | Faqat o'zgarishlarni uzatadi | Doimiy | WAL sloti |
Tartib muhim: avval slot ochiladi, keyin snapshot olinadi. Teskari qilsangiz, ikkalasi orasidagi o'zgarishlar yo'qoladi. Biz ham shu tartibda ishladik.
Debezium nima qiladi
Bu bobda quvurni qo'lda yozdik, chunki mexanizmni ko'rish kerak edi. Ishlab chiqarishda Debezium ishlatiladi va u xuddi shu ishni qiladi: slot ochadi, snapshot oladi, WAL ni o'qiydi, Kafka ga yozadi.
Debezium qo'shadigan narsa — qulash va qayta tiklanish (offset saqlash), sxema o'zgarishini
kuzatish, ko'p jadval, va pgoutput plaginidan foydalanish. Ya'ni bu bobdagi 40 qator kod
ishlab chiqarishga tayyor emas, lekin u nima bo'layotganini ko'rsatadi.
Tozalash
python3 -c " import psycopg2 c = psycopg2.connect(host='localhost', port=15455, user='postgres', password='kitob', dbname='rostuy') c.autocommit = True c.cursor().execute(\"SELECT pg_drop_replication_slot('kitob_slot')\") c.close() print('slot o\\'chirildi') " 2>/dev/null || echo "slot allaqachon yo'q" docker rm -f kitob-pg kitob-kafka > /dev/null 2>&1 && echo "konteynerlar o'chirildi" docker ps --format '{{.Names}}'
slot o'chirildi konteynerlar o'chirildi novavivo-postgres novavivo-redis stratix-med-frontend-1
Slotni o'chirishni unutmang
Bu eng qimmat xato. Faol bo'lmagan slot Postgres ga "WAL ni saqlab tur" deb turaveradi. Iste'molchi o'chgan bo'lsa ham.
Natija: disk asta-sekin to'ladi va bir kuni baza yozishni to'xtatadi. Sabab topilguncha
soatlar ketadi. pg_replication_slots dagi active=false slotlarni muntazam tekshiring.
Xulosa
| Tushuncha | Asosiy fikr |
|---|---|
| Polling | Oson, lekin DELETE va oraliq o'zgarishlarni boy beradi |
| WAL | Har commit yoziladigan tranzaksiya jurnali |
wal_level=logical |
Qatorlar va qiymatlar WAL ga yozilsin (restart kerak) |
| Replikatsiya sloti | O'qish o'rnini saqlaydi; WAL o'chirilmaydi |
| Kalit | Birlamchi kalit → bir qator bitta partitionda |
| DELETE hodisasi | Faqat kalit keladi (REPLICA IDENTITY ga bog'liq) |
| Tartib | Avval slot, keyin snapshot — aks holda bo'shliq qoladi |
| Debezium | Shu mexanizm + qulashga chidamlilik + sxema kuzatuvi |
| Unutilgan slot | Diskni to'ldiradi va bazani to'xtatadi |
Talaba ishi
ALTER TABLE elon REPLICA IDENTITY FULLqo'ying va DELETE ni qayta o'lchang. Hodisada endi nima bor?- Slotni ochmasdan 100 ta o'zgarish qiling, keyin slot oching. Nechta hodisa keladi? Nega?
pg_logical_slot_peek_changesni sinab ko'ring.getdan farqi nima va qachon kerak?- Ikki jadval qo'shing va quvurni ikkalasini ham uzatadigan qiling. Kafka topiclarini qanday ajratasiz?
Bu bobni bepul o'qidingiz.
Kitob o'rgatadi, lekin sizning kodingiz nega ishlamaganini ayta olmaydi. Kursda uy vazifangiz tekshiriladi.