Mundarija (38)
- Bu darsda
- 1. Nega bu kerak?
- 2. Ikki xil zaxira
- 2.1 Mantiqiy va fizik
- 2.2 pg_dump bazani to'xtatadimi?
- 3. pg_dump formatlari
- 3.1 To'rt format
- 3.2 Qaysi birini tanlash
- 4. pg_restore: tiklash
- 4.1 Avval mundarija
- 4.2 To'liq tiklash va -j
- 4.3 Xato bo'lsa, pg_restore to'xtamaydi
- 4.4 Bitta jadval: -t tuzog'i
- 5. Rollar dump'da yo'q
- 5.1 Nega
- 5.2 pg_dumpall --globals-only
- 6. --clean xavfi
- 6.1 Tajriba
- 6.2 To'g'ri yo'l
- 7. Plain dump va psql
- 8. Fizik zaxira va PITR
- 8.1 Muammo: dump — bitta lahza
- 8.2 Sozlash
- 8.3 Kanon tajribasi
- 8.4 Maqsad noto'g'ri bo'lsa
- 9. Professional vositalar va 3-2-1 qoidasi
- 9.1 pgBackRest va WAL-G
- 9.2 3-2-1 qoidasi
- 9.3 RPO va RTO
- 10. Ko'p uchraydigan xatolar
- 11. Mashqlar
- 1-mashq (oson): bayroqni tanlang
- 2-mashq (o'rta): mundarijani sanash
- 3-mashq (qiyin): qaysi zaxirani saqlash
- 12. Loyiha qadami: kanon tajribasi
- 13. Real ishda
- Xulosa
- Manbalar
Backup va restore: pg_dump, pg_restore, PITR va 3-2-1 qoidasi
Qisqacha: PostgreSQL'da ikki xil zaxira bor. Mantiqiy —
pg_dumpbazani SQL buyruqlar yoki siqilgan arxiv qilib yozadi,pg_restoreuni qaytaradi. Fizik —pg_basebackupklaster fayllarini nusxalaydi, WAL arxivi esa keyingi har o'zgarishni saqlaydi: shu ikkisi bilan istalgan soniyaga qaytish (PITR) mumkin. Ikki qoida: zaxira faqat tiklab ko'rilgan bo'lsa zaxira; tiklash ham ma'lumotni o'chirishi mumkin (--cleanjonli bazada).
Bu darsda
pg_dumpning to'rt formatini taqqoslaysiz va custom formatni nega tanlashni tushuntirasiz.pg_restorebilan butun bazani, bitta jadvalni va faqat ma'lumotni tiklaysiz — va har birining tuzog'ini bilasiz.- Rollar nega dump'da yo'qligini va
pg_dumpall --globals-onlynima uchun kerakligini izohlaysiz. - WAL arxivi va
pg_basebackupbilan PITR qanday ishlashini kanon tajribasidan o'qiysiz. - 3-2-1 qoidasi, RPO va RTO bo'yicha zaxira rejasini tuza olasiz.
Oldin bilishingiz kerak: Rollar va huquqlar, Postgres arxitekturasi va asosiy sozlamalar, Volume va bind mount, UPDATE va DELETE xavfsiz.
1. Nega bu kerak?
Juma, kechki soat 18:40. Dasturchi Sardor prod bazada "eski test vazifalarni" o'chirmoqchi edi. Buyruqni yozdi, Enter bosdi — WHERE qatori nusxaga tushmay qolgan ekan:
DELETE FROM vazifalar;UPDATE va DELETE xavfsiz darsida bunday xatodan saqlanish yo'llarini ko'rgan edik (BEGIN, avval SELECT). Lekin xato baribir bo'ladi: odam charchaydi, disk buziladi, server ijarachisi bankrot bo'ladi. O'shanda bitta savol qoladi: qaytara olamizmi va qaysi daqiqagacha?
Bu darsda ikkita achchiq haqiqatni ham ko'ramiz. Birinchisi: ko'p jamoalarda zaxira bor, lekin uni hech kim tiklab ko'rmagan — kerak bo'lgan kuni fayl buzuq yoki rollarsiz chiqadi. Ikkinchisi: tiklashning o'zi ham ma'lumot o'chiradi. Zaxira 10:00 da olingan, 10:05 da yangi foydalanuvchi ro'yxatdan o'tgan bo'lsa, 10:10 dagi "to'liq tiklash" uni yo'q qiladi.
O'xshatish: zaxira — uyning kalitining nusxasi. Nusxa yasatib, eshikka urinib ko'rmasangiz, u kerak bo'lgan kecha qulfga tushmasligi mumkin.
Diqqat: Bu darsdagi raqamlar — kanon tajribasidan: PostgreSQL 18.6 Docker konteynerida,
kattabazasida (417 MB, 500 000 vazifa), 2026-10-24. Kichik o'z misollarimiz — "biz ishga tushirdik" (PostgreSQL 17.6, Windows 11). pgBackRest, WAL-G va bulutli saqlash — sinalmagan, hujjat bo'yicha.
2. Ikki xil zaxira
2.1 Mantiqiy va fizik
Mantiqiy zaxira (logical backup) — bazaning mazmuni: "shunday jadval yarat, unga shu qatorlarni yoz, shu indeksni qur". pg_dump shuni yozadi. Uni boshqa Postgres versiyasiga ham, boshqa mashinaga ham tiklasa bo'ladi.
Fizik zaxira (physical backup) — klasterning fayllari, baytma-bayt: pg_basebackup Postgres arxitekturasi darsidagi ma'lumotlar papkasini nusxalaydi. U faqat aynan shu major versiyada ishlaydi, lekin WAL bilan birga istalgan lahzaga qaytishga imkon beradi.
Mantiqiy (pg_dump) |
Fizik (pg_basebackup + WAL) |
|
|---|---|---|
| Nima saqlanadi | SQL buyruqlar / arxiv | ma'lumotlar fayllari |
| Qaysi lahza | dump boshlangan lahza | istalgan lahza (PITR) |
| Boshqa versiyaga | ha | yo'q, faqat o'sha major |
| Bitta jadvalni olish | ha (-t) |
yo'q, butun klaster |
flowchart LR
B[(Postgres)] -->|pg_dump| D[dump fayl]
D -->|pg_restore| N[(yangi baza)]
B -->|pg_basebackup| F[fayllar nusxasi]
B -->|archive_command| W[WAL arxivi]
F --> P[(PITR: istalgan soniya)]
W --> PDiagrammaga qarang: yuqori yo'l — bitta "surat" (dump olingan payt). Pastki yo'l — surat va undan keyingi barcha o'zgarishlar jurnali.
2.2 pg_dump bazani to'xtatadimi?
Yo'q. pg_dump bitta tranzaksiya ichida, MVCC snapshot'i bilan o'qiydi: dump davomida boshqalar yozishda davom etadi, dump esa boshlangan lahzadagi izchil holatni ko'radi. Jadvallarga faqat ACCESS SHARE qulfi qo'yiladi — u oddiy yozishga xalaqit bermaydi, lekin ALTER TABLE kabi sxema o'zgarishini dump tugaguncha kutdiradi.
Tekshirib ko'ring: Dump 14:00:00 da boshlandi va 14:03 da tugadi. 14:01 da qo'shilgan vazifa dump'ga tushadimi?
Javob
Yo'q. pg_dump snapshot'i 14:00:00 dagi holatni ko'radi — keyin COMMIT bo'lgan o'zgarishlar unga ko'rinmaydi. Shuning uchun dump izchil: yarim yozilgan holat bo'lmaydi.
3. pg_dump formatlari
3.1 To'rt format
-F (format) bayrog'i dump qanday ko'rinishda yozilishini tanlaydi:
| Bayroq | Format | Tiklash vositasi |
|---|---|---|
-Fp (sukut) |
plain — oddiy .sql matn |
psql -f |
-Fc |
custom — siqilgan arxiv | pg_restore |
-Fd |
directory — papka, har jadval alohida fayl | pg_restore |
-Ft |
tar — siqilmagan arxiv | pg_restore |
Kanon katta bazasini (417 MB) besh xil yo'l bilan yozdi. Buyruqlar konteyner ichida bajarildi (dump va server bir xil versiya — 18):
pg_dump -U postgres -Fp -f /tmp/zaxira/katta.sql katta
pg_dump -U postgres -Fc -f /tmp/zaxira/katta.dump katta
pg_dump -U postgres -Fc -Z zstd:3 -f /tmp/zaxira/katta-zstd.dump katta
pg_dump -U postgres -Fd -j 4 -f /tmp/zaxira/katta.dir katta
pg_dump -U postgres -Ft -f /tmp/zaxira/katta.tar katta-Z zstd:3 — siqish usuli va darajasi (sukut gzip). -j 4 — 4 ta jadvalni parallel yozish, faqat directory formatida.
- plain -Fp2.8 s87 MB
- custom -Fc7.3 s21 MB
- custom zstd:33.4 s23 MB
- directory -j 46.5 s21 MB
- tar -Ft3.8 s87 MB
Manba: Kanon o'lchovi, PostgreSQL 18.6, baza katta, 2026-10-24 (bitta o'lchov)
Grafikda nimaga qarash kerak: dump fayli bazadan ancha kichik. Sababi — indekslar dump'ga ma'lumot sifatida tushmaydi, faqat CREATE INDEX buyrug'i yoziladi; tiklashda ular qaytadan quriladi. Custom va directory siqilgani uchun plain'dan 4 marta kichik.
Vaqtga ham qarang: gzip bilan custom — 7.3 s, zstd bilan — 3.4 s (hajmi deyarli bir xil). Siqish protsessor vaqtini oladi. Bu bitta o'lchov, band mashinada; xulosa umumiy: zstd odatda tezroq.
Maslahat: Kichik bazada siqish deyarli foyda bermaydi. Biz holat 11 namuna bazasini (48 vazifa) dump qildik (PostgreSQL 17.6): plain — 44 188 bayt, custom — 47 879 bayt. Arxiv mundarijasi siqilgan ma'lumotdan og'irroq chiqdi.
3.2 Qaysi birini tanlash
Kundalik zaxira uchun odatiy tanlov — custom (-Fc): siqilgan, bitta fayl, pg_restore bilan tanlab tiklanadi va -j bilan parallel tiklanadi. Juda katta bazada — directory (-Fd -j N): dump'ning o'zi ham parallel.
Plain format o'qish uchun qulay (less bilan ochib ko'rasiz), lekin undan bitta jadvalni ajratib olish qiyin va tiklash faqat ketma-ket.
Tekshirib ko'ring: Nega 417 MB baza 21 MB lik faylga sig'di? Ikki sabab ayting.
Javob
- Indekslar va materialized view ma'lumoti saqlanmaydi — faqat ularni yaratish buyrug'i. 2) Custom format ma'lumotni siqadi; vazifa matnlari kabi takrorlanuvchi matn yaxshi siqiladi. Bundan tashqari bazadagi bo'sh joy (bloat, VACUUM darsi) dump'ga tushmaydi.
4. pg_restore: tiklash
4.1 Avval mundarija
Custom arxiv ichida nima borligini tiklamasdan ko'rish mumkin:
pg_restore -l /tmp/zaxira/katta.dump | grep -E 'TABLE DATA|TRIGGER'Kanondagi chiqishdan bir qism:
3611; 0 18517 TABLE DATA public foydalanuvchilar postgres
3618; 0 18612 TABLE DATA public izohlar postgres
3613; 0 18533 TABLE DATA public vazifalar postgres
3446; 2620 18669 TRIGGER public vazifalar vazifa_tarixi_trg postgres
3448; 2620 18675 TRIGGER public vazifalar vazifalar_tartib_trg postgresHar qator — arxivdagi bitta element: tartib raqami, turi (TABLE DATA, INDEX, TRIGGER, POLICY …), sxema, nomi va egasi. Kanon arxivida jami 129 element bor edi. Bu ro'yxatni faylga yozib, keraksiz qatorlarni o'chirib, pg_restore -L ro'yxat.txt bilan faqat qolganlarini tiklash mumkin.
4.2 To'liq tiklash va -j
createdb -U postgres tiklash
pg_restore -U postgres -d tiklash -j 4 /tmp/zaxira/katta.dumpKanon o'lchovi: ketma-ket tiklash 33.3 s, -j 4 bilan — 19.8 s. Vaqtning katta qismi ma'lumotni yozish emas, indeks qurish va cheklovlarni tekshirish — ular parallel qilinadi. Tiklangan bazada 500 000 vazifa, 125 000 izoh va 5 000 qatorli materialized view bor edi.
Dump fayl kichik edi, tiklash esa 20–33 soniya. Bu nisbat katta bazada ham saqlanadi: tiklash vaqti — dump vaqtidan ancha ko'p. Zaxira rejasida aynan tiklash vaqtini hisoblash kerak.
4.3 Xato bo'lsa, pg_restore to'xtamaydi
Sukut bo'yicha pg_restore xatoni yozadi va davom etadi. Biz holat 11 bazasiga teglar jadvalini ikkinchi marta tiklab ko'rdik (PostgreSQL 17.6):
pg_restore: error: COPY failed for table "teglar": ERROR: duplicate key value violates unique constraint "teglar_pkey"
DETAIL: Key (id)=(1) already exists.
CONTEXT: COPY teglar, line 1
pg_restore: warning: errors ignored on restore: 2Tarjimasi: "teglar uchun COPY muvaffaqiyatsiz: takror kalit… Tiklashda 2 ta xato e'tiborsiz qoldirildi". Jarayon chiqish kodi — 1. Skriptda shu kodni tekshirmasangiz, yarim tiklangan bazani "tayyor" deb o'ylaysiz. Birinchi xatoda to'xtatish — --exit-on-error, hammasini bitta tranzaksiyada bajarish — -1 (--single-transaction).
4.4 Bitta jadval: -t tuzog'i
Faqat foydalanuvchilar kerak bo'lsa:
pg_restore -U postgres -d tiklash2 -t foydalanuvchilar \
/tmp/zaxira/katta.dumpKanon natijasi: jadval va 5 000 qator keldi, CHECK cheklovlari ham bor. Lekin \d foydalanuvchilar da birlamchi kalit, indekslar, tashqi kalitlar va trigger'lar yo'q edi. -t faqat jadvalning o'zini va ma'lumotini oladi; indeks va cheklovlar arxivda alohida element.
Shuning uchun -t bilan tiklangan jadval — "ma'lumotni ko'rib olish" uchun, prod'ga qaytarish uchun emas. Buning to'g'ri yo'li — keyingi darsda.
Tekshirib ko'ring:
-t foydalanuvchilarbilan tiklangan jadvalga bir xil emailli ikkinchi qatorni yozish mumkinmi?
Javob
Ha. Emailning noyobligi foydalanuvchilar_email_key indeksi orqali ta'minlanadi, -t esa indeksni tiklamadi. CHECK (email shakli) esa jadvalning bir qismi — u ishlaydi. Natija: tashqi ko'rinishi to'g'ri, lekin himoyasiz jadval.
5. Rollar dump'da yo'q
5.1 Nega
Rol (vazifalar_api, vazifalar_hisobot) — bitta bazaga emas, butun klasterga tegishli (Rollar va huquqlar). pg_dump esa bitta bazani yozadi. Natija: dump ichida GRANT … TO vazifalar_ilova va RLS siyosatlari bor (kanon arxivida 19 ta ACL/POLICY elementi), lekin rolning o'zi yo'q. Toza serverga tiklasangiz, bu buyruqlar "rol mavjud emas" xatosi bilan yiqiladi va pg_restore ularni sanab davom etadi — ilova keyin ulana olmaydi.
5.2 pg_dumpall --globals-only
Klaster darajasidagi narsalarni (rollar, tablespace'lar) alohida yozing:
pg_dumpall -U postgres --globals-only > rollar.sqlKanon chiqishidan:
CREATE ROLE vazifalar_api;
ALTER ROLE vazifalar_api WITH NOSUPERUSER INHERIT NOCREATEROLE NOCREATEDB LOGIN NOREPLICATION NOBYPASSRLS CONNECTION LIMIT 40;
ALTER ROLE vazifalar_hisobot SET statement_timeout TO '30s';
ALTER ROLE vazifalar_hisobot SET default_transaction_read_only TO 'on';Rolning CONNECTION LIMIT i ham, rolga bog'langan sozlamalar ham saqlandi. Tiklash tartibi: avval psql -f rollar.sql, keyin pg_restore. Parollar ham shu faylga (hash ko'rinishida) tushadi — demak rollar.sql dump'ning o'zidek maxfiy.
Rollar haqiqatan klasterda turganini SQL bilan tekshirish mumkin (holat 11 bazasi, rollarni 105 va 106 migratsiyalari yaratgan):
SELECT rolname, rolcanlogin, rolconnlimit
FROM pg_roles
WHERE rolname LIKE 'vazifalar%'
ORDER BY rolname;Natija:
rolname | rolcanlogin | rolconnlimit
----------------------+-------------+--------------
vazifalar_api | t | 40
vazifalar_hisobot | t | 5
vazifalar_ilova | f | -1
vazifalar_migratsiya | t | -1
(4 rows)pg_roles — klaster katalogi: siz qaysi bazaga ulangan bo'lsangiz ham, ro'yxat bir xil. -1 — cheklovsiz.
6. --clean xavfi
6.1 Tajriba
--clean (-c) — tiklashdan oldin har obyektni DROP qiladi. Eski bazani "zaxira holatiga qaytarish" uchun qulay ko'rinadi. Kanon tajribasi aynan real vaziyatni takrorladi:
- Zaxira 10:00 da olingan.
- 10:05 da
yangi@example.comfoydalanuvchisi ro'yxatdan o'tdi (bazada 1 ta). - 10:10 da kimdir "faqat foydalanuvchilarni" qaytarmoqchi bo'ldi.
pg_restore -U postgres -d tiklash --clean --if-exists \
-t foydalanuvchilar --data-only /tmp/zaxira/katta.dumppg_restore: error: options -c/--clean and -a/--data-only cannot be used together"--clean va --data-only birga ishlatilmaydi" — --data-only jadvalni o'chirmaydi, --clean esa aynan o'chiradi; bu ikki niyat zid. Keyin to'liq --clean bilan tiklandi:
pg_restore -U postgres -d tiklash --clean --if-exists \
/tmp/zaxira/katta.dumpNatija: clean dan keyin yangi foydalanuvchi: 0. 10:05 dagi foydalanuvchi, uning vazifalari va izohlari — yo'q. Zaxira "muvaffaqiyatli tiklandi", va shu bilan jonli ma'lumot o'chdi.
6.2 To'g'ri yo'l
Jonli bazaga hech qachon to'liq --clean tiklash qilmang. Buning o'rniga:
- Zaxirani yangi, alohida bazaga tiklang (
tiklash). - Unda kerakli qatorlarni toping.
- Faqat o'sha qatorlarni jonli bazaga ko'chiring — bitta tranzaksiyada.
Uchinchi qadam — keyingi darsning mavzusi: Ma'lumotni qisman ko'chirish.
7. Plain dump va psql
Plain dump — oddiy SQL. Uni ochsangiz (PostgreSQL 17.6 pg_dump, biz ishga tushirdik), boshida shunday qatorlar turadi (kalit qisqartirildi):
\restrict JqzLbTWxvPmgflBGaO4w...
SET statement_timeout = 0;
SET lock_timeout = 0;
SET client_encoding = 'UTF8';
SELECT pg_catalog.set_config('search_path', '', false);
SET row_security = off;
CREATE EXTENSION IF NOT EXISTS pg_trgm WITH SCHEMA public;\restrict — psql meta-buyrug'i: fayl oxiridagi \unrestrict gacha boshqa meta-buyruqlarni taqiqlaydi. U 2025-yil avgust tuzatish relizlarida (17.6, 18 va boshqalar) qo'shilgan: buzg'unchi o'z ma'lumoti ichiga \! (shell buyrug'i) yashirib, tiklayotgan admin kompyuterida ishga tushirmasin. search_path bo'sh — dump hamma nomni sxema bilan yozadi (public.vazifalar).
Plain dump'ni tiklash:
psql -X -v ON_ERROR_STOP=1 -1 -d tiklash -f zaxira.sqlON_ERROR_STOP=1 — birinchi xatoda to'xtash (sukut bo'yicha psql ham davom etadi!), -1 — butun fayl bitta tranzaksiyada: yo hammasi, yo hech narsa.
8. Fizik zaxira va PITR
8.1 Muammo: dump — bitta lahza
Har kecha 03:00 da dump olsangiz, juma 18:40 dagi xatodan keyin eng yaxshi holatda 03:00 ga qaytasiz — kun bo'yi kiritilgan hamma narsa yo'qoladi. Har soatda dump? Katta bazada dump o'zi bir soat yurishi mumkin.
Yechim Postgres arxitekturasi darsidagi WAL (write-ahead log) da. Postgres har o'zgarishni avval WAL'ga yozadi. WAL fayllarini (har biri 16 MB) to'lishi bilan arxivga ko'chirib borsak, bizda bazaning to'liq "kundaligi" bo'ladi. Bitta asosiy zaxira (base backup) + undan keyingi WAL = istalgan soniyaga qaytish. Bu — PITR (point-in-time recovery), aniq vaqtga tiklash.
flowchart LR
A[base backup<br/>1000 qator] --> W1[WAL 3]
W1 --> W2[WAL 4:<br/>+500 qator]
W2 --> T((maqsad<br/>vaqti))
T --> X[DELETE<br/>WHERE'siz]Diagrammada tiklash chapdan o'ngga yuradi: asosiy zaxira, keyin WAL'lar qayta o'ynaladi va maqsad vaqtida to'xtaydi — DELETE ga yetmasdan.
8.2 Sozlash
Uch sozlama (postgresql.conf yoki ALTER SYSTEM; birinchisi qayta ishga tushirishni talab qiladi):
wal_level = replica
archive_mode = on
archive_command = 'test ! -f /arxiv/%f && cp %p /arxiv/%f'%p — WAL faylining yo'li, %f — nomi. test ! -f — arxivda shu nomli fayl bo'lsa, ustiga yozmaydi va xato qaytaradi (Postgres keyin qayta urinadi). Haqiqiy serverda /arxiv boshqa disk yoki boshqa mashina bo'lishi shart — aks holda disk bilan birga arxiv ham ketadi.
8.3 Kanon tajribasi
Vaqtinchalik konteynerda (postgres:18) kanon to'liq ssenariyni o'ynadi:
- 1 000 vazifa yozildi.
pg_basebackup -D /zaxira/asos -Fp -X stream -c fast— 40 MB, 8.4 s.-X stream— zaxira paytidagi WAL ham birga olinadi.- Zaxiradan keyin yana 500 vazifa — ular faqat WAL arxivida.
- Maqsad vaqti yozib qo'yildi, keyin
DELETE(WHERE'siz) — 1 500 qator o'chdi.
Tiklash uchun zaxira nusxasiga recovery.signal bo'sh fayli va uchta sozlama qo'shildi:
restore_command = 'cp /arxiv/%f %p'
recovery_target_time = '2026-10-24 14:23:53.084792+00'
recovery_target_action = 'promote'Server ishga tushganda log'ida (sana va PID qismi olib tashlandi):
LOG: starting point-in-time recovery to 2026-10-24 14:23:53.084792+00
LOG: restored log file "000000010000000000000004" from archive
LOG: recovery stopping before commit of transaction 756, time 2026-10-24 14:23:55.581248+00
LOG: selected new timeline ID: 2
LOG: archive recovery complete
LOG: database system is ready to accept connectionsO'qiymiz: "aniq vaqtga tiklash boshlandi" → "arxivdan WAL fayli tiklandi" → "756-tranzaksiya COMMIT'idan oldin to'xtadi" (bu aynan DELETE edi) → "yangi vaqt chizig'i (timeline) 2 tanlandi". Natija — 1 500 qator, shundan 500 tasi faqat WAL'dan kelgan. Butun tiklash 11.6 s.
Timeline — tiklashdan keyingi tarix yangi tarmoq bo'lib davom etadi. Eski 1-chiziqda DELETE bor, 2-chiziqda yo'q. WAL fayl nomidagi birinchi 8 belgi (00000001) — shu raqam.
8.4 Maqsad noto'g'ri bo'lsa
Kanon ataylab maqsadni 2020-01-01 qilib qo'ydi — zaxiradan ancha oldin. Postgres zaxirani "yarim" holatda ocha olmaydi: u zaxira oxirigacha (izchil nuqta, consistent state) o'ynadi va to'xtadi:
LOG: consistent recovery state reached at 0/3000120
LOG: pausing at the end of recovery
HINT: Execute pg_wal_replay_resume() to promote.recovery_target_action sukut bo'yicha pause: server faqat o'qish rejimida ochiladi, 1 000 qator ko'rinadi (zaxira holati). Ko'rib chiqib, rozi bo'lsangiz — pg_wal_replay_resume(). Bu xavfsiz sukut: noto'g'ri vaqtni ko'rsatsangiz, server o'zi yangi tarixni boshlab yubormaydi.
Tekshirib ko'ring: Kecha 03:00 dagi asosiy zaxira bor, WAL arxivi esa bugun 11:00 da (disk to'lib) to'xtab qolgan. 18:40 dagi xatodan oldingi 18:39 ga qaytish mumkinmi?
Javob
Yo'q, eng ko'pi 11:00 gacha. PITR WAL zanjiriga tayanadi: bitta fayl yo'q bo'lsa, undan keyingisini o'ynab bo'lmaydi. Shuning uchun arxivlash xatosini kuzatish kerak — pg_stat_archiver ko'rinishidagi failed_count va last_failed_wal (Monitoring va favqulodda vaziyatlar darsida).
9. Professional vositalar va 3-2-1 qoidasi
9.1 pgBackRest va WAL-G
Qo'lda archive_command va cp — tushunish uchun. Real serverda bu ishni maxsus vositalar qiladi (ikkalasi sinalmagan, rasmiy hujjat bo'yicha, 2026-10-25):
- pgBackRest — to'liq, differensial (oxirgi to'liq zaxiradan beri o'zgargan fayllar) va inkremental (oxirgi istalgan zaxiradan beri o'zgarganlar) zaxira, parallel siqish, S3 kabi bulut omboriga yozish, shifrlash, zaxirani tekshirish.
- WAL-G — WAL va asosiy zaxirani to'g'ridan bulutga (S3, GCS, Azure) siqib yuboradi; konfiguratsiyasi soddaroq.
Ular aynan shu darsdagi mexanizmni (asosiy zaxira + WAL) avtomatlashtiradi — tushuncha o'zgarmaydi.
9.2 3-2-1 qoidasi
Zaxiraning klassik qoidasi:
- 3 nusxa ma'lumot (asl + 2 zaxira);
- 2 xil saqlash vositasida (masalan server diski va obyekt ombori);
- 1 nusxa boshqa joyda (boshqa shahar yoki provayder).
Nega: zaxira asl bazaning yonida tursa, server yonib ketganda (yoki ijarachi hisobini yopganda) ikkalasi birga yo'qoladi. Hozir ko'p jamoalar "1" ga yana bitta shart qo'shadi: o'zgartirib bo'lmaydigan (immutable) nusxa — shifrlovchi zararli dastur zaxirani ham o'chira olmasin.
9.3 RPO va RTO
Zaxira rejasini ikki savol belgilaydi:
- RPO (Recovery Point Objective) — qancha ma'lumot yo'qotishga tayyormiz? Kunlik dump → RPO 24 soatgacha. WAL arxivi → bir necha daqiqa yoki soniya.
- RTO (Recovery Time Objective) — qancha vaqtda qayta ishlay olishimiz kerak? Kanonda 417 MB baza 20–33 s da tiklandi; 400 GB baza soatlab tiklanadi.
Ikkala raqam ham o'lchanadi, taxmin qilinmaydi: oyda bir marta zaxirani boshqa serverga tiklab, vaqtini yozib qo'yish — eng foydali odat.
10. Ko'p uchraydigan xatolar
| Belgi | Sabab | Davosi |
|---|---|---|
role "vazifalar_ilova" does not exist |
rollar dump'da yo'q | avval pg_dumpall --globals-only |
| tiklangan jadvalda PK, indeks yo'q | pg_restore -t |
to'liq tiklash yoki -L ro'yxat |
| zaxiradan keyingi ma'lumot yo'qoldi | jonli bazaga --clean |
alohida bazaga tiklab, qisman ko'chirish |
| skript "OK", baza yarim | pg_restore xatoda davom etdi |
chiqish kodini tekshirish, --exit-on-error |
| PITR ma'lum soatdan oldinga o'tmaydi | WAL arxivida uzilish | arxivlash xatosini kuzatish |
| dump bor, tiklab ko'rilmagan | — | muntazam tiklash mashqi |
11. Mashqlar
Mashqlar kurs/mashqlar/27/14-backup/ da. 2- va 3-mashq yechimlari Node 24 da tekshirilgan (biz ishga tushirdik).
1-mashq (oson): bayroqni tanlang
- Siqilgan, bitta faylli, tanlab tiklanadigan format —
-F - Dump'ni 4 ta jarayonda parallel yozish uchun format —
-F - Arxiv mundarijasini ko'rish —
pg_restore - - Birinchi xatoda to'xtatish —
pg_restore -- - Rollarni yozish —
pg_dumpall --
Yechim
-Fc— custom;-Fd— directory (faqat u-jbilan parallel dump qiladi).-l— list; natijani tahrirlab,-Lbilan qaytarish mumkin.--exit-on-error— sukut bo'yichapg_restorexatoni sanab davom etadi.--globals-only— rollar va tablespace'lar; ularpg_dumpga tushmaydi.
2-mashq (o'rta): mundarijani sanash
pg_restore -l chiqishini oladigan mundarijaniSana(matn) funksiyasini yozing. U har tur (TABLE DATA, INDEX, TRIGGER, …) nechta ekanini obyekt qilib qaytarsin. ; bilan boshlanadigan izoh qatorlarini va bo'sh qatorlarni o'tkazib yuboring.
Ishora: qatorda turdan oldin uchta bo'lak bor (3611;, 0, 18517), turdan keyin esa public keladi. Satrni split(" ") bilan bo'ling (satr metodlari); tur — 4-bo'lakdan public gacha bo'lgan so'zlar.
Yechim
function mundarijaniSana(matn) {
const soni = {};
for (const qator of matn.split("\n")) {
if (qator.trim() === "" || qator.startsWith(";")) continue;
const bolaklar = qator.split(" ");
const oxiri = bolaklar.indexOf("public", 3);
const tur = bolaklar.slice(3, oxiri).join(" ");
soni[tur] = (soni[tur] ?? 0) + 1;
}
return soni;
}
const matn = `;
; Archive created at 2026-10-24
3611; 0 18517 TABLE DATA public foydalanuvchilar postgres
3618; 0 18612 TABLE DATA public izohlar postgres
3438; 1259 18698 INDEX public foydalanuvchi_statistikasi_pkey postgres
3409; 1259 18531 INDEX public foydalanuvchilar_email_key postgres
3450; 2620 18641 TRIGGER public izohlar izohlar_soni_trg postgres
`;
console.log(mundarijaniSana(matn));Konsolda:
{ 'TABLE DATA': 2, INDEX: 2, TRIGGER: 1 }Nega indexOf("public", 3): tur bir so'zli (INDEX) ham, ikki so'zli (TABLE DATA) ham bo'ladi — chegarani public belgilaydi. Bizning bazada hamma obyekt public sxemasida; boshqa sxemali arxivda bu ishora yetmaydi.
3-mashq (qiyin): qaysi zaxirani saqlash
Zaxiralar har kuni olinadi, fayl nomi — sana ("2026-10-25"). Saqlash siyosati: oxirgi 7 kunlik zaxira va undan eskilari ichidan yakshanba kunlari olingan oxirgi 4 tasi. ochiriladiganlar(sanalar) funksiyasi o'chirilishi kerak bo'lgan sanalarni o'sish tartibida qaytarsin.
Ishora: sanalarni kamayish tartibida saralang; yakshanbani new Date(sana + "T00:00:00Z").getUTCDay() === 0 bilan aniqlang (UTC — vaqt zonasi kunni siljitmasin).
Yechim
function ochiriladiganlar(sanalar) {
const yangidan = [...sanalar].sort().reverse();
const saqla = new Set(yangidan.slice(0, 7));
const yakshanbalar = yangidan.slice(7).filter(
(s) => new Date(s + "T00:00:00Z").getUTCDay() === 0,
);
for (const s of yakshanbalar.slice(0, 4)) saqla.add(s);
return sanalar.filter((s) => !saqla.has(s)).sort();
}
const sanalar = [];
for (let kun = 1; kun <= 40; kun++) {
const d = new Date(Date.UTC(2026, 8, 15 + kun));
sanalar.push(d.toISOString().slice(0, 10));
}
const ochir = ochiriladiganlar(sanalar);
const qoldi = sanalar.filter((s) => !ochir.includes(s));
console.log(qoldi.length, "ta qoladi:", qoldi.slice(0, 4).join(" "));
const [birinchi, oxirgi] = [ochir[0], ochir.at(-1)];
console.log(ochir.length, "ta o'chadi:", birinchi, "...", oxirgi);Konsolda:
11 ta qoladi: 2026-09-27 2026-10-04 2026-10-11 2026-10-18
29 ta o'chadi: 2026-09-16 ... 2026-10-1740 kunlik zaxira (16 sentyabr – 25 oktyabr): oxirgi 7 kun (19–25 oktyabr) va undan oldingi 4 ta yakshanba qoladi — birinchi qatorda aynan o'sha yakshanbalar. O'chiriladiganlarning oxirgisi — 17 oktyabr (shanba); 18 oktyabr yakshanba bo'lgani uchun saqlandi. [...sanalar] — asl massivni buzmaslik uchun nusxa: sort() massivning o'zini o'zgartiradi.
12. Loyiha qadami: kanon tajribasi
Bu darsda vazifalar-api kodi o'zgarmaydi va commit yo'q. Zaxira — ilovaning emas, serverning ishi: uni cron yoki provayder xizmati bajaradi, ilova kodi esa bundan bexabar. Serverga chiqarish — 33-qism mavzusi; o'shanda zaxira rejasi deploy bilan birga quriladi.
Hozir o'z kompyuteringizda kanon tajribasining qisqa variantini takrorlang (kanon27-pg konteyneri, holat 11 bazasi):
docker exec kanon27-pg sh -c \
"pg_dump -U postgres -Fc -f /tmp/v.dump vazifalar"
docker exec kanon27-pg createdb -U postgres tiklash
docker exec kanon27-pg sh -c \
"pg_restore -U postgres -d tiklash -j 4 /tmp/v.dump"
docker exec kanon27-pg psql -U postgres -d tiklash \
-c "SELECT count(*) FROM vazifalar"Oxirgi so'rov namuna bazasidagidek 48 ni ko'rsatishi kerak. Keyin tiklash bazasini dropdb bilan o'chiring. Shu to'rt qatorni oyda bir marta bajarish — "zaxira tiklab ko'rilgan" degani.
13. Real ishda
- Managed Postgres (RDS, Neon, Supabase) avtomatik zaxira va PITR'ni xizmat sifatida beradi — lekin rollar, saqlash muddati va tiklash vaqti baribir sizning javobgarligingiz (Managed va serverless Postgres).
- O'z serveringizda — pgBackRest yoki WAL-G, arxiv boshqa joyda, va tiklash mashqi kalendarda.
- Intervyuda: "
pg_dumpvapg_basebackupfarqi?", "PITR qanday ishlaydi?", "RPO va RTO nima?", "Zaxirangiz ishlashini qayerdan bilasiz?"
Xulosa
- Mantiqiy zaxira (
pg_dump) — bitta lahza, ko'chma; fizik (pg_basebackup+ WAL) — istalgan soniya, faqat o'sha versiya. - Kundalik tanlov — custom format; tiklash dump'dan ancha uzoq,
-juni qisqartiradi. -tindeks va kalitsiz jadval beradi; rollar dump'da yo'q —pg_dumpall --globals-only.- Jonli bazaga
--cleanbilan tiklash zaxiradan keyingi ma'lumotni o'chiradi — alohida bazaga tiklang. - PITR:
archive_command+ asosiy zaxira +recovery_target_time; noto'g'ri maqsadda serverpauseda kutadi. - 3-2-1, RPO/RTO — va eng muhimi, muntazam tiklab ko'rish.
Keyingi dars: Ma'lumotni qisman ko'chirish — butun bazani emas, faqat kerakli qatorlarni: \copy, jarrohlik tranzaksiyasi va CRLF tuzog'i.
Manbalar
- PostgreSQL 18 hujjati — Backup and Restore (SQL dump, continuous archiving, PITR): https://www.postgresql.org/docs/18/backup.html
pg_dump,pg_restore,pg_dumpall,pg_basebackup: https://www.postgresql.org/docs/18/app-pgdump.html, https://www.postgresql.org/docs/18/app-pgrestore.html, https://www.postgresql.org/docs/18/app-pg-dumpall.html, https://www.postgresql.org/docs/18/app-pgbasebackup.html- Recovery sozlamalari (
recovery_target_time,recovery_target_action): https://www.postgresql.org/docs/18/runtime-config-wal.html - PostgreSQL 17.6 va boshqa tuzatish relizlari (2025-08-14,
\restrict): https://www.postgresql.org/about/news/postgresql-176-1610-1514-1419-1322-and-18-beta-3-released-3118/ - pgBackRest: https://pgbackrest.org/user-guide.html; WAL-G: https://github.com/wal-g/wal-g
- O'qilgan sana — 2026-10-25. Kanon o'lchovi (IlmHamroh, 2026-10): formatlar,
-l,-j,-t,--globals-only,--cleanva PITR (timeline,pause), PostgreSQL 18.6. Biz ishga tushirdik (PostgreSQL 17.6):pg_restorexatoda davom etishi va chiqish kodi, kichik bazada dump hajmi, plain dump boshi,pg_rolesso'rovi, 2–3-mashqlar (Node 24).
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!