# Upgrade Mayor PostgreSQL Tanpa Downtime dengan Logical Replication

> Cara memindahkan database PostgreSQL yang aktif ke versi mayor baru dengan downtime di bawah satu detik menggunakan publication dan subscription — serta celah sequence, large object, dan DDL yang akan menggigit saat cutover jika Anda lupa.

URL: https://www.matthewswong.com/id/blog/postgres-logical-replication-zero-downtime-upgrade/

- Author: Matthews Wong (https://www.matthewswong.com/id/about/)
- Published: 2026-07-14
- Updated: 2026-07-14
- Category: Backend

> **Key takeaway:** Untuk melakukan upgrade PostgreSQL antar versi mayor dengan downtime nyaris nol, replikasikan database yang sedang berjalan ke instance versi baru menggunakan logical replication: buat PUBLICATION di server lama, SUBSCRIPTION di server baru, tunggu sampai lag mencapai nol, lalu alihkan trafik. Jebakannya adalah logical replication menyalin baris tabel tetapi bukan sequence, large object, atau DDL, jadi Anda harus menyinkronkannya secara manual selama jendela cutover.

Cara klasik untuk upgrade versi mayor PostgreSQL adalah pg_upgrade, dan itu berfungsi baik sampai Anda punya database yang tidak boleh offline. pg_upgrade butuh server lama dihentikan saat me-relink direktori data, dan bahkan dalam mode --link Anda tetap menghadapi jendela pemeliharaan plus skenario rollback yang menakutkan kalau ada yang gagal di tengah jalan. Untuk sebuah layanan yang saya kelola dan diakses pelanggan sepanjang waktu, jendela itu tidak dapat diterima. Logical replication memberi bentuk yang berbeda sama sekali: server versi baru berjalan berdampingan dengan yang lama, tetap sinkron terus-menerus, dan satu-satunya downtime nyata adalah beberapa detik untuk memindahkan connection string aplikasi.

Berbeda dengan physical (streaming) replication, logical replication men-decode write-ahead log menjadi event perubahan tingkat baris dan memutarnya ulang sebagai statement INSERT, UPDATE, dan DELETE biasa di subscriber. Karena bekerja di tingkat baris logis bukan tingkat byte, publisher dan subscriber bisa menjalankan versi mayor yang berbeda. Properti tunggal itulah yang menjadikannya alat yang tepat untuk upgrade. Panduan ini mengasumsikan perpindahan dari primary Postgres 15 ke target Postgres 18, tetapi bentuknya identik untuk lompatan mayor-ke-mayor mana pun yang didukung logical decoding.

## Langkah 1: Siapkan publisher dan salin skema

Di server lama, atur wal_level ke logical dan sediakan cukup replication slot serta WAL sender. Ini membutuhkan restart, jadi lakukan saat pemeliharaan rutin jauh sebelum upgrade sesungguhnya. Lalu salin skema ke server baru lebih dulu, karena logical replication mereplikasi data tetapi tidak pernah DDL. Setiap tabel yang ingin Anda replikasi harus sudah ada di subscriber dengan definisi yang cocok, dan setiap tabel butuh primary key atau REPLICA IDENTITY yang diset eksplisit agar event UPDATE dan DELETE bisa menemukan baris targetnya.

## Langkah 2: Buat subscription dan biarkan salinan awal berjalan

Di server baru, buat SUBSCRIPTION yang menunjuk ke publisher. Secara default ia melakukan dua hal: salinan data awal (COPY paralel atas isi terkini setiap tabel) diikuti streaming perubahan baru secara terus-menerus. Untuk database besar, salinan awal adalah bagian yang lambat dan berjalan di bawah sebuah replication slot, jadi publisher akan menahan WAL selama itu. Pantau disk server lama di sini. Setelah salinan selesai, status setiap tabel berubah menjadi r (ready) di pg_subscription_rel dan streaming steady-state mengambil alih.

> Di PostgreSQL 17 ke atas Anda bisa melewati COPY awal yang mahal sepenuhnya dengan pg_createsubscriber, yang mengubah physical standby yang sudah ada menjadi logical subscriber dengan mencatat sebuah LSN dan memutar mundur posisi apply. PostgreSQL 18 menambahkan flag --all yang menyiapkan subscription untuk setiap database dalam instance dalam satu perintah. Kalau Anda sudah menjalankan streaming standby, ini mengubah salinan awal berjam-jam menjadi hitungan detik.

## Langkah 3: Waspadai celahnya — sequence, large object, dan DDL

Di sinilah orang sering terbakar. Logical replication menyalin angka yang ada di kolom serial dan identity Anda sebagai data biasa, tetapi tidak mereplikasi objek sequence yang menghasilkannya. Di subscriber, setiap sequence masih melaporkan nilai awalnya. Promosikan cluster baru tanpa memperbaiki ini dan insert pertama Anda langsung disambut deretan duplicate key violation. Large object (API pg_largeobject / lo) juga tidak pernah direplikasi — kalau Anda memakainya, butuh langkah salin terpisah. Dan karena DDL tidak direplikasi, Anda harus membekukan migrasi skema selama cutover atau menerapkan setiap perubahan ke kedua server secara manual.

Perbaikan sequence adalah sebuah skrip yang Anda hasilkan di publisher dan jalankan di subscriber, dan Anda menjalankannya selambat mungkin dalam cutover. Tambahkan buffer pengaman ke setiap nilai agar transaksi yang masih berjalan saat peralihan tidak bisa bertabrakan dengan sequence yang baru dipromosikan. Buffer seribu adalah asuransi murah; celah pada sequence tidak pernah jadi masalah.

> Jangan lupa menonaktifkan langkah migrasi skema aplikasi Anda sebelum jendela cutover dibuka. Satu ALTER TABLE yang dijalankan di primary lama saat replikasi aktif tidak akan sampai ke server baru, dan baris berikutnya yang bergantung pada perubahan kolom itu akan merusak replikasi dengan error yang menghentikan seluruh subscription sampai Anda memperbaiki skema secara manual.

## Langkah 4: Cutover

Cutover adalah satu-satunya momen dengan downtime nyata (di bawah satu detik), jadi buat skripnya dan latih di staging dulu. Tujuannya adalah memastikan subscriber telah menangkap setiap perubahan terakhir sebelum ada klien yang menulis ke sana.

1. Hentikan penulisan aplikasi ke primary lama (jadikan read-only, atau hentikan app / connection pool). Ini memulai hitungan downtime.
2. Tunggu lag replikasi mencapai nol — pastikan confirmed_flush_lsn di publisher sama dengan WAL LSN terkini dan pg_subscription tidak menunjukkan perubahan tertunda.
3. Jalankan statement setval yang telah dihasilkan di server baru untuk mempromosikan setiap sequence melewati nilai lama.
4. Arahkan connection string aplikasi ke server baru dan mulai menerima penulisan di sana.
5. Verifikasi dengan smoke test — sebuah insert yang menguji sequence, pembacaan baris terbaru — lalu DROP subscription di server baru untuk melepasnya dengan bersih.

> Biarkan primary lama tetap berjalan dan tidak disentuh selama satu dua hari setelah cutover. Itu adalah rollback instan Anda: kalau ada yang salah di versi baru, kembalikan saja connection string. Ingat saja bahwa server lama belum menerima penulisan yang masuk ke server baru, jadi rollback setelah trafik nyata berarti merekonsiliasi celah itu — itulah tepatnya alasan Anda melakukan smoke-test ketat di menit-menit pertama.

## Apa yang dibawa dan tidak dibawa logical replication

| Objek | Direplikasi otomatis? | Yang harus Anda lakukan |
| --- | --- | --- |
| Baris tabel (INSERT/UPDATE/DELETE) | Ya | Tidak ada — ini tugas intinya |
| Sequence (generator serial / identity) | Tidak | Jalankan setval dengan buffer saat cutover |
| Large object (lo / pg_largeobject) | Tidak | Salin terpisah, atau migrasikan ke bytea |
| Perubahan skema / DDL | Tidak | Salin skema dulu; bekukan migrasi |
| View, materialized view, foreign table | Tidak | Buat ulang di subscriber secara manual |
| TRUNCATE | Ya (dengan catatan) | Pastikan pengelompokan foreign-key cocok |

Tak satu pun dari ini eksotis begitu Anda pernah melakukannya sekali, tetapi setiap baris Tidak itu adalah insiden produksi yang menunggu orang yang mengira logical replication adalah clone penuh. Bukan — ia adalah stream perubahan baris, dan objek yang dilewatinya adalah yang Anda tangani secara sengaja saat cutover. Perlu dicatat: PostgreSQL 19 dijadwalkan akhirnya menambahkan sinkronisasi sequence native ke logical replication, yang menghapus satu snag paling menyebalkan di seluruh prosedur ini. Sampai Anda menjalankan 19, skrip setval tetap ada di checklist cutover Anda.

## Sources

- PostgreSQL 18 Documentation — Logical Replication Restrictions
- PostgreSQL 18 Documentation — pg_createsubscriber
- PostgreSQL 18 Documentation — Logical Replication

## Source links

- https://www.postgresql.org/docs/current/logical-replication-restrictions.html
- https://www.postgresql.org/docs/current/app-pgcreatesubscriber.html
- https://www.postgresql.org/docs/current/logical-replication.html

## FAQ

### Mengapa menggunakan logical replication alih-alih pg_upgrade untuk upgrade versi mayor?

pg_upgrade mengharuskan server lama dihentikan saat me-relink direktori data, yang berarti jendela pemeliharaan dan jalur rollback yang canggung. Logical replication menjalankan server versi baru berdampingan dengan yang lama dan menjaganya tetap sinkron terus-menerus, jadi satu-satunya downtime adalah beberapa detik untuk memindahkan connection string aplikasi. Ini pilihan tepat ketika database tidak boleh offline selama durasi pg_upgrade.

### Apakah logical replication PostgreSQL menyalin sequence secara otomatis?

Tidak. Angka yang tersimpan di kolom serial dan identity direplikasi sebagai data baris biasa, tetapi objek sequence yang menghasilkan nilai baru tidak. Di subscriber setiap sequence masih melaporkan nilai awalnya. Anda harus menjalankan setval di server baru saat cutover, idealnya dengan buffer ditambahkan, atau insert pertama Anda akan gagal dengan duplicate key violation.

### Apa itu pg_createsubscriber dan bagaimana ia membantu?

pg_createsubscriber, diperkenalkan di PostgreSQL 17, mengubah physical streaming standby yang sudah ada menjadi logical subscriber tanpa menyalin ulang data. Ia mencatat sebuah LSN dan memutar mundur posisi apply alih-alih menjalankan COPY awal penuh. PostgreSQL 18 menambahkan flag --all untuk menyiapkan subscription bagi setiap database dalam satu perintah, mengubah sinkronisasi awal berjam-jam menjadi hitungan detik.

### Berapa banyak downtime yang sebenarnya dibutuhkan upgrade dengan logical replication?

Hanya momen cutover yang memiliki downtime nyata, dan biasanya di bawah satu detik hingga beberapa detik. Anda menghentikan penulisan di primary lama, memastikan lag replikasi mencapai nol, mempromosikan sequence, dan mengarahkan aplikasi ke server baru. Semua sebelum itu — salin skema, salin data awal, streaming catch-up — terjadi saat database lama tetap sepenuhnya online.

### Apakah large object direplikasi oleh logical replication PostgreSQL?

Tidak. Large object yang diakses melalui API lo dan pg_largeobject tidak pernah direplikasi oleh logical replication. Kalau database Anda memakainya, Anda harus menyalinnya dengan langkah terpisah, atau memigrasikan datanya ke kolom bytea biasa sebelumnya. Ini salah satu celah yang menjebak tim yang mengira logical replication menghasilkan clone penuh.

---

- HTML version: https://www.matthewswong.com/id/blog/postgres-logical-replication-zero-downtime-upgrade/
- English: https://www.matthewswong.com/en/blog/postgres-logical-replication-zero-downtime-upgrade/
- Site index for agents: https://www.matthewswong.com/llms.txt
- Sitemap: https://www.matthewswong.com/sitemap.xml
- API description (OpenAPI): https://www.matthewswong.com/openapi.json
