IlmHamroh
JavaScript Full-stack/27-qism. Ma'lumotlar bazasi chuqur: Postgres, ORM, Mongo, Redis14/65-dars20 daqiqa
Mundarija (38)

Backup va restore: pg_dump, pg_restore, PITR va 3-2-1 qoidasi

Qisqacha: PostgreSQL'da ikki xil zaxira bor. Mantiqiy — pg_dump bazani SQL buyruqlar yoki siqilgan arxiv qilib yozadi, pg_restore uni qaytaradi. Fizik — pg_basebackup klaster 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 (--clean jonli bazada).

Bu darsda

  • pg_dump ning to'rt formatini taqqoslaysiz va custom formatni nega tanlashni tushuntirasiz.
  • pg_restore bilan 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-only nima uchun kerakligini izohlaysiz.
  • WAL arxivi va pg_basebackup bilan 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:

sql
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, katta bazasida (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 --> P

Diagrammaga 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):

bash
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.

pg_dump: fayl hajmi (baza 417 MB)
  • 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
  1. 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:

bash
pg_restore -l /tmp/zaxira/katta.dump | grep -E 'TABLE DATA|TRIGGER'

Kanondagi chiqishdan bir qism:

text
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 postgres

Har 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

bash
createdb -U postgres tiklash
pg_restore -U postgres -d tiklash -j 4 /tmp/zaxira/katta.dump

Kanon 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):

text
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: 2

Tarjimasi: "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:

bash
pg_restore -U postgres -d tiklash2 -t foydalanuvchilar \
  /tmp/zaxira/katta.dump

Kanon 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 foydalanuvchilar bilan 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:

bash
pg_dumpall -U postgres --globals-only > rollar.sql

Kanon chiqishidan:

text
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):

sql
SELECT rolname, rolcanlogin, rolconnlimit
FROM pg_roles
WHERE rolname LIKE 'vazifalar%'
ORDER BY rolname;

Natija:

text
       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:

  1. Zaxira 10:00 da olingan.
  2. 10:05 da yangi@example.com foydalanuvchisi ro'yxatdan o'tdi (bazada 1 ta).
  3. 10:10 da kimdir "faqat foydalanuvchilarni" qaytarmoqchi bo'ldi.
bash
pg_restore -U postgres -d tiklash --clean --if-exists \
  -t foydalanuvchilar --data-only /tmp/zaxira/katta.dump
text
pg_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:

bash
pg_restore -U postgres -d tiklash --clean --if-exists \
  /tmp/zaxira/katta.dump

Natija: 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:

  1. Zaxirani yangi, alohida bazaga tiklang (tiklash).
  2. Unda kerakli qatorlarni toping.
  3. 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):

text
\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:

bash
psql -X -v ON_ERROR_STOP=1 -1 -d tiklash -f zaxira.sql

ON_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):

text
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. 1 000 vazifa yozildi.
  2. pg_basebackup -D /zaxira/asos -Fp -X stream -c fast — 40 MB, 8.4 s. -X stream — zaxira paytidagi WAL ham birga olinadi.
  3. Zaxiradan keyin yana 500 vazifa — ular faqat WAL arxivida.
  4. 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:

text
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):

text
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 connections

O'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:

text
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 -j bilan parallel dump qiladi).
  • -l — list; natijani tahrirlab, -L bilan qaytarish mumkin.
  • --exit-on-error — sukut bo'yicha pg_restore xatoni sanab davom etadi.
  • --globals-only — rollar va tablespace'lar; ular pg_dump ga 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
js
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:

text
{ '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
js
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:

text
11 ta qoladi: 2026-09-27 2026-10-04 2026-10-11 2026-10-18
29 ta o'chadi: 2026-09-16 ... 2026-10-17

40 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):

bash
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_dump va pg_basebackup farqi?", "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, -j uni qisqartiradi.
  • -t indeks va kalitsiz jadval beradi; rollar dump'da yo'q — pg_dumpall --globals-only.
  • Jonli bazaga --clean bilan tiklash zaxiradan keyingi ma'lumotni o'chiradi — alohida bazaga tiklang.
  • PITR: archive_command + asosiy zaxira + recovery_target_time; noto'g'ri maqsadda server pause da 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

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
Backup va restore: pgdump, pgrestore, PITR va 3-2-1 qoidasi — IlmHamroh