Migrasi database PostgreSQL selesai dengan downtime 11 detik
(gds.blog.gov.uk)- GOV.UK Notify menurunkan downtime menjadi sekitar 11 detik saat memindahkan database 400GB PostgreSQL 11 ke PostgreSQL 15 RDS di akun AWS mereka sendiri seiring penghentian PaaS
- Pada DB tujuan, mula-mula hanya tabel yang dibuat lalu data disalin dengan DMS full load, kemudian indeks dan batasan kunci diterapkan belakangan untuk mengurangi waktu pemuatan skala besar
- DB sumber berukuran sekitar 1,3 miliar baris, 85 tabel, 185 indeks, dan 120 foreign key, serta pada hari kerja menerima sekitar 1.000 operasi insert·update per detik dan jumlah pembacaan yang serupa
- Karena redeploy aplikasi memerlukan sekitar 5 menit, mereka lebih dulu menyiapkan kredensial yang sama dan peralihan bobot DNS Route53 untuk mempersingkat waktu cutover sebenarnya
- DMS dipilih karena mudah mendapat dukungan dari PaaS dan AWS, tetapi untuk migrasi antarsesama PostgreSQL, alternatif seperti pglogical mungkin sebenarnya lebih sederhana
Migrasi database Notify seiring penghentian PaaS
- GOV.UK Notify di-host di GOV.UK Platform as a Service, dan karena PaaS dihentikan, seluruh infrastrukturnya harus dipindahkan ke akun AWS mereka sendiri
- Database Notify adalah AWS RDS PostgreSQL yang berada di akun AWS PaaS, dan menyimpan data pengiriman notifikasi hingga isi ratusan ribu templat yang digunakan tim layanan
- Database lama dibedakan sebagai source database, dan database baru sebagai target database selama proses migrasi
- Tantangan utamanya bukan membuat database PostgreSQL baru, melainkan meminimalkan downtime saat memindahkan seluruh data dan mengganti tujuan koneksi aplikasi
Skala database sumber dan batasan layanan
- Database sumber adalah PostgreSQL 11 berukuran sekitar 400GB
- sekitar 1,3 miliar baris
- 85 tabel
- 185 indeks
- 120 foreign key
- Pada hari kerja biasa, terjadi sekitar 1.000 operasi insert atau update per detik, beserta jumlah pembacaan yang kurang lebih sama
- GOV.UK Notify mengirim jutaan notifikasi penting dan sensitif waktu setiap hari, seperti peringatan banjir dan perkembangan pengajuan paspor
- Karena semua pengiriman notifikasi memerlukan akses database, waktu henti layanan harus dijaga tetap singkat
Struktur pemuatan awal dan replikasi berkelanjutan dengan DMS
- Tim PaaS menyediakan metode migrasi database menggunakan AWS Database Migration Service
- DMS bertugas memindahkan data dari database sumber ke database tujuan, dan bisa dijalankan di akun AWS sumber maupun tujuan
- Tugas DMS dibagi menjadi dua tahap
- full load: menyalin semua data yang ada hingga titik waktu tertentu per tabel
- replikasi berkelanjutan: memutar ulang transaksi baru dari database sumber ke database tujuan agar keduanya tetap sinkron
- Pekerjaan mengalihkan aplikasi agar menggunakan database tujuan alih-alih database sumber ditangani langsung oleh tim Notify
Menyiapkan database tujuan dan full load
- Instance DMS dibuat di akun AWS sumber
- Tim PaaS sudah lebih dulu menyiapkan instance DMS di dalam akun, sehingga persiapan bisa dilakukan dengan cepat
- Instance DMS memerlukan kredensial untuk terhubung ke database PostgreSQL sumber dan tujuan
- Karena instance DMS dan database tujuan berada di VPC yang berbeda, mereka menyiapkan VPC peering agar trafik DMS dari VPC PaaS dirutekan ke VPC mereka sendiri tanpa melewati internet publik
- Instance RDS tujuan dibuat di akun AWS mereka sendiri, dan karena dukungan PostgreSQL 11 mendekati akhir masa pakai, database baru dikonfigurasi sebagai PostgreSQL 15
- Skema database sumber didump dengan
pg_dumpuntuk membuat berkas SQL pembuatan ulang skema, dan pada awalnya hanya deklarasi tabel yang diterapkan ke database tujuan - Foreign key tidak diterapkan pada saat full load
- karena DMS full load tidak menyalin data sesuai urutan batasan foreign key
- Primary key dan indeks juga tidak dibuat sebelum full load
- karena setiap insert akan memerlukan pembaruan indeks, yang bisa sangat menambah total waktu saat memasukkan miliaran baris
- menyalin semua data terlebih dahulu lalu menambahkan indeks terbukti lebih cepat
- Tugas full load menyalin data yang ada pada saat tombol start ditekan
- data baru atau pembaruan yang terjadi setelah itu tidak termasuk dalam full load
- full load memerlukan sekitar 6 jam untuk selesai
- Setelah full load, sisa berkas skema diterapkan untuk menambahkan indeks dan batasan kunci, dan pekerjaan ini memerlukan sekitar 3 jam
Menjaga replikasi selama 10 hari lalu mengalihkan trafik
- Setelah full load selesai, database tujuan cocok dengan data sumber pada saat full load dimulai, tetapi setelah itu insert, update, dan delete tetap terus terjadi di sumber
- Mereka memulai replikasi berkelanjutan DMS, yaitu change data capture, untuk mengirim transaksi transaction log dari database sumber sejak awal full load ke database tujuan
- Proses replikasi memerlukan beberapa jam untuk menyusul ketertinggalan, dan setelah itu mereka memantau waktu lag replikasi DMS untuk memastikan status sinkronisasi
- Replikasi DMS berjalan di latar belakang selama sekitar 10 hari, menjaga kedua database tetap sinkron hingga waktu migrasi trafik yang telah diumumkan sebelumnya kepada pengguna
- Prosedur cutover trafik ditulis lebih dulu dalam skrip Python
- menghentikan trafik aplikasi ke database sumber
- memeriksa apakah replikasi sudah sepenuhnya menyusul
- mengizinkan aplikasi terhubung ke database tujuan
- Mereka harus menghindari kondisi ketika sebagian aplikasi memakai DB sumber dan sisanya memakai DB tujuan
- karena perubahan yang terjadi di DB tujuan tidak direfleksikan kembali ke DB sumber, sehingga pengguna bisa melihat data yang tidak konsisten
- Skrip dibuat agar lebih eksplisit, dapat diulang, dan berjalan lebih cepat daripada pekerjaan manual, serta digunakan sedikitnya 40 kali dalam pengujian dan latihan sebelumnya
- Target downtime adalah kurang dari 5 menit, dan waktu migrasi dipilih pada Sabtu malam yang relatif sepi namun tidak larut malam
Peralihan DNS yang menghasilkan downtime 11 detik
- Penghentian trafik database sumber dilakukan dengan memanggil
pg_terminate_backendpada koneksi aplikasi, dan memerlukan waktu kurang dari 1 detik - Untuk mencegah aplikasi tersambung kembali ke DB sumber, kata sandi pengguna PostgreSQL juga diubah agar upaya reconnect menghasilkan error autentikasi
- DMS membuat tabel status replikasi di database tujuan dan memperbaruinya setiap menit, dan skrip migrasi menggunakan tabel ini untuk memeriksa lag antara sumber dan tujuan
- Sebagai lapisan pengaman tambahan, setelah aplikasi berhenti mengakses DB sumber, skrip menulis satu record ke DB sumber lalu menunggu hingga record itu tiba di DB tujuan
- Informasi koneksi database aplikasi diberikan melalui variabel lingkungan
SQLALCHEMY_DATABASE_URI- bentuk sebelumnya adalah format
postgresql://...@random-identifier.eu-west-1.rds.amazonaws.com:5432yang memuat nama pengguna, kata sandi, dan lokasi RDS - mengubah lokasi database atau kredensial memerlukan redeploy aplikasi, dan redeploy memerlukan sekitar 5 menit
- bentuk sebelumnya adalah format
- Untuk menghindari downtime tambahan akibat redeploy, sebelum migrasi mereka menyiapkan dua hal
- membuat pengguna dengan nama pengguna dan kata sandi yang sama di database sumber dan tujuan
- membuat record DNS
database.notifications.service.gov.ukdi AWS Route53 dan mengatur TTL menjadi 1 detik
- Record DNS awalnya diberi bobot sumber 100% dan tujuan 0%
- URI aplikasi lebih dulu diubah agar menggunakan nama pengguna, kata sandi, dan nama domain baru yang sama
- Saat cutover sebenarnya, skrip mengubah bobot DNS AWS menjadi 100% ke tujuan lalu menunggu TTL 1 detik kedaluwarsa
- Pada saat cutover Sabtu malam 4 November 2023, lag antara database tujuan dan database sumber berada di kisaran beberapa detik
- Hasil eksekusi skrip migrasi menunjukkan aplikasi berhenti mengakses DB sumber dan mulai menggunakan DB tujuan baru, dengan downtime sekitar 11 detik
Evaluasi pemilihan DMS dan pekerjaan selanjutnya
- DMS dipilih karena didukung dengan baik di GOV.UK PaaS dan memungkinkan mereka memperoleh dukungan AWS
- Jika kelak melakukan migrasi database PostgreSQL ke PostgreSQL lagi, mereka berencana mempertimbangkan lebih serius alat alternatif seperti pglogical
- DMS mungkin menambah kompleksitas dan proses replikasi yang kurang familier dibanding alat lain
- Setelah migrasi database, langkah berikutnya adalah migrasi aplikasi
- Aplikasi GOV.UK Notify akan dipindahkan ke AWS Elastic Container Service, dan prosesnya akan dibagikan kemudian
1 komentar
Komentar Hacker News
Kami juga melakukan migrasi serupa dengan AWS RDS Blue-Green Deployments. Database-nya sedikit lebih besar, tetapi downtime sekitar 20 detik dan pekerjaannya jauh lebih sedikit. Agak mengejutkan ini belum disebutkan di thread ini.
Pada dasarnya, jika Anda membuat deployment Blue/Green baru dengan perubahan yang diinginkan, AWS akan menyinkronkan deployment green melalui replikasi logis sementara konfigurasi blue yang lama tetap menangani trafik.
Di green, selama tidak melakukan write, Anda bisa melakukan perubahan, pengujian, bahkan load test; write tetap masuk ke blue yang live lalu direplikasi ke green.
Saat sudah siap, Anda menjalankan perintah switch, lalu AWS menangani pemeriksaan sinkronisasi, menghentikan write dan koneksi, menunggu replikasi mengejar ketertinggalan, mengganti nama database, serta melanjutkan koneksi dan write.
Dalam kasus kami, downtime kurang dari 20 detik, dan seluruh konfigurasi termasuk primary serta beberapa read replica berhasil beralih tanpa masalah. AWS juga mengganti URL database, jadi tidak perlu mengubah konfigurasi; green menjadi blue, blue lama menjadi old blue, lalu bisa dihapus nanti.
Sangat direkomendasikan, tetapi ada batasan, misalnya mungkin tidak bisa untuk perpindahan antar-akun: https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/blue-...
Dokumentasi, khususnya bagian batasan, harus dibaca berulang-ulang. Sebaiknya jalankan pengujian dengan beban di lingkungan development, lalu coba lagi di staging.
Atau masukkan saja ke production dengan gaya YOLO, mungkin juga baik-baik saja.
Namun saya belajar dengan cara yang sulit bahwa RDS Blue/Green tidak bisa digunakan untuk perubahan sembarang. Dalam kasus kami, ternyata hanya bisa dipakai untuk menaikkan versi engine, bukan menurunkannya.
Di MySQL 8.0 ada satu stored procedure yang sangat sesekali gagal, jadi kami mempertimbangkan opsi rollback ke 5.7, tetapi itu tidak mungkin.
Trade-off-nya adalah sebagian request menjadi lambat selama beberapa detik.
Kombinasi DNS Groups dan retry adalah mekanisme yang cukup berguna untuk pekerjaan seperti ini.
Tool yang digunakan: https://github.com/shayonj/pg_easy_replicate
Ada beberapa cara untuk “menjeda” query Postgres yang masuk; misalnya menggunakan pgbouncer agar query tidak gagal, melainkan ditunda sampai replikasi mengejar ketertinggalan, lalu dilanjutkan di database baru.
Jika ada yang salah dan replikasi tidak bisa mengejar, Anda bisa melepas jeda dan membiarkan query-query itu berjalan di database lama.
Dengan begitu, downtime 11 detik berubah menjadi tambahan waktu muat halaman 0–11 detik. Yang lebih penting, collateral damage jauh berkurang bagi ribuan pengguna database yang belum pernah melihat query gagal sejauh ini, tetapi mungkin memiliki jalur penanganan error yang bug, atau batch job yang seluruhnya rusak hanya karena satu query gagal.
Menarik jika dibandingkan dengan https://knock.app/blog/zero-downtime-postgres-upgrades. Diskusi terkait ada di https://news.ycombinator.com/item?id=38616181
Saat itu, sebagian besar diskusinya berujung pada “bukankah ini terlalu rumit hanya untuk menghindari downtime beberapa menit?” Kasus kali ini tampak seperti pembuktian, dan arahnya terlihat bahwa cukup memakai AWS Data Migration Service, mengubah entri DNS, mengalihkannya ke produksi, lalu menerima downtime 11 detik
Beberapa tipe data khusus bahkan mungkin tidak bisa diproses sama sekali. Setelah migrasi, sequence juga harus diperbarui; jika tidak, bisa terjadi error primary key duplikat
Jika tidak ada primary key yang sesuai, masalah juga bisa muncul karena tidak selalu menyalin seluruh baris sekaligus
Jika database berada dalam akun AWS yang sama dan Anda bisa menerima downtime 4–5 menit, replikasi tingkat perangkat keras menggunakan global database atau snapshot kemungkinan besar lebih mudah
Baru-baru ini kami memindahkan database PostgreSQL 3TB yang di-host sendiri dari 12 ke 16, sekaligus beralih dari Ubuntu 18 ke Ubuntu 22. Pada saat yang sama kami juga harus meng-upgrade beberapa ekstensi, terutama Timescale yang tidak memiliki versi kompatibel yang memenuhi semua kombinasi
Kami melakukannya dengan meng-upgrade replika read-only: awalnya PG12, Ubuntu 18, TS2.9, lalu pertama-tama membuat replika read-only di Ubuntu 22 dengan tetap memakai PG12 dan TS2.9
Setelah itu kami masuk ke mode maintenance, menghentikan semua layanan, memisahkan replika read-only, lalu di Ubuntu 22 menaikkan PG12 ke PG15 sambil tetap memakai TS2.9
Berikutnya, dari PG15 dan TS2.9 kami naik ke TS2.13, dan terakhir menaikkan PG15 ke PG16 di Ubuntu 22 sambil tetap memakai TS2.13
Akhirnya kami menghubungkan kembali layanan ke server database baru, melanjutkan semua layanan, lalu keluar dari mode maintenance
Semua tahap upgrade database sudah cukup diuji dan diotomatisasi dengan Ansible, tetapi ada satu masalah yang tidak muncul saat pengujian sehingga downtime bertambah menjadi sekitar 30 menit. Untuk penggunaan kami, itu masih sepenuhnya dapat diterima
Jika memakai replikasi logis, mungkin masalah tak terduga di saat terakhir bisa dikurangi, dan pada siklus upgrade berikutnya kami berencana meninjau pendekatan ini
Kami juga meninjau replikasi logis untuk mengurangi downtime upgrade, tetapi karena skema database dan perintah DDL tidak direplikasi, sepertinya tidak direkomendasikan jika ada Timescale
Perubahan skema dasar yang perlu dilakukan Timescale secara internal kemungkinan besar merupakan fungsi dari ukuran chunk hypertable dan pola write yang masuk, jadi mungkin bisa direncanakan atau diatur waktunya. Namun kami menilai kompleksitas dan risikonya terlalu besar dibandingkan mengambil jendela maintenance singkat selama pg_upgrade selesai
Musuh migrasi low-downtime atau tanpa downtime seperti ini adalah query yang berjalan lama
Misalnya jika ada satu query update yang memakan waktu 30 menit, Anda harus membunuh query itu lalu melakukan rollback, atau menerima hilangnya ketersediaan selama 30 menit
Sejauh yang saya tahu, saat ini tidak ada cara untuk memigrasikan query yang sedang berjalan
statement_timeoutadalah teman AndaJika ada transaksi yang sangat panjang, kemungkinan besar Anda bisa melakukan peralihan dengan menghindari waktu transaksi itu berjalan. Semoga itu hasil dari pekerjaan terjadwal, bukan kejadian acak
Dengan menggabungkan batas waktu transaksi dan konfigurasi failover, misalnya membuat primary lama gagal, serta sesuatu seperti pgbouncer, Anda bisa mengendalikan periode melambat sebagai pengganti downtime dengan cukup presisi
Sejujurnya, yang lebih saya khawatirkan adalah apakah seluruh stack dan server DNS cache eksternal yang menjadi dependensinya benar-benar mematuhi DNS TTL
Namun biasanya menghindari downtime sekitar belasan detik pada aplikasi tidaklah krusial, jadi pilihlah solusi yang lebih sederhana bagi Anda
Tentu saja yang pertama itu memang banyak terjadi. Saya cukup sering menikmati mengubah pekerjaan berdurasi menit atau jam menjadi milidetik
Saya penasaran data seperti apa dan orang-orang seperti apa yang menangani write database semacam itu, sampai harus bergantung pada DB engine untuk bekerja selama itu alih-alih memecahnya menjadi bagian lebih kecil lewat queue di lapisan atas
Bagian tentang membuat record DNS AWS Route53 untuk
database.notifications.service.gov.ukdengan TTL 1 detik, lalu skrip migrasi mengubah bobot DNS AWS agar 100% mengarah ke lokasi database target dan menunggu 1 detik sampai TTL kedaluwarsa, terasa anehMereka bilang setelah itu, saat aplikasi berikutnya mencoba melakukan kueri ke database, aplikasi akan mengkueri database target. Apakah ini berarti ORM mereka atau perilaku bawaan Python melakukan lookup DNS pada setiap kueri lalu terblokir?
Apakah mereka sama sekali tidak meng-cache alamat yang sudah di-resolve untuk jangka waktu tertentu, dan juga tidak memakai connection pooling atau reuse koneksi?
getaddrinfoataugethostnamedi OS yang melakukan perilaku ini. Python hampir tidak mengimplementasikan ulang pemanggilan level sistem, jadi bergantung pada konfigurasi sistemJika TTL 1 detik dipatuhi, seharusnya di-cache selama 1 detik, tetapi library lookup DNS dan terutama server DNS caching tidak selalu sepenuhnya mematuhi TTL. Sejujurnya, itu mungkin bisa menjelaskan sebagian downtime yang teramati
Bagus. Kami baru saja memigrasikan 3 cluster Postgres di RDS yang berisi sekitar 2TB data dan 8 database, dari Postgres 14 ke 16. Layanan down dari 00:00 sampai 04:00
Pertama kami menyalakan “mode pemeliharaan”, yaitu situs pengganti yang sangat ringan dan berjalan di Cloudflare Workers, lalu dengan Terraform kami men-scale down semua aplikasi yang memakai DB menjadi 0
Di UI web AWS, kami menekan tombol upgrade untuk menjalankan
pg_upgradedari 14→15, menunggu sampai selesai, lalu menekannya lagi untuk 15→16Kami menunggu sampai database mulai menerima koneksi; tampaknya koneksi sudah diterima bahkan sebelum ditandai ready, dan sepertinya AWS melakukan hal lain selain
pg_upgradeSetelah itu kami memulai
VACUUM ANALYZE; REINDEX DATABASE CONCURRENTLY. Tujuannya menghindari isu performa antarversi dan memanfaatkan peningkatan performa di versi baruKami mulai menyalakan kembali aplikasi, menunggu sampai semua aplikasi punya beberapa container yang berjalan, lalu mulai menerima trafik, mematikan situs pemeliharaan, dan pergi tidur
REINDEX CONCURRENTLYmasih berjalan 18 jam lagi di DB terbesar, tetapi tidak memblokir apa punLain kali kami berencana memakai AWS Blue/Green deployment untuk menghindari downtime. Kali ini tidak bisa dipakai karena versi kami belum 14.9, minor version minimum 14 yang didukung Blue/Green
Kalau saya melakukannya sendiri, saya tidak akan membayar biaya AWS, melainkan menyusun Blue/Green sendiri dengan logical replication dan load balancer
pg_upgrade --hardlinksDi instance Postgres on-premise milik sendiri, saya pernah memproses DB 2TB dalam kurang dari 1 menit
GOV.UK Notify adalah bagian dari kumpulan layanan yang disediakan GDS untuk lembaga publik Inggris. Ada juga GOV.UK Pay dan GOV.UK PaaS, dan awalnya dikenal sebagai Government As A Platform
DMS adalah alat migrasi yang buruk. Setelah hampir sebulan bergelut dengan berbagai masalah migrasi, kami menyerah
Ia tidak bisa memigrasikan tipe text dan json, dan dukungan AWS juga tidak bisa menawarkan solusi
Kami mencoba AWS Blue/Green pada tahap pengujian awal, dan berkat itu upgrade yang nyaris tanpa downtime menjadi realistis
Benar-benar rusak
Menarik, tapi saya tidak mengerti kenapa pemerintah sejak awal memakai AWS. Ini bukan startup yang sedang mengutak-atik sesuatu untuk mencari product-market fit, dan bukan pula situasi merespons lonjakan trafik akibat pemasaran yang tidak terprediksi
Mereka tahu layanan seperti ini dibutuhkan dalam jangka panjang, dan pola penggunaannya juga bisa diprediksi dengan cukup baik
Mereka bisa membangun cloud sektor publik atau mengadopsi pendekatan on-premise yang masuk akal. Memang perlu dana, koordinasi, dan kepemimpinan teknis, tetapi dalam jangka panjang itu akan menghemat biaya sangat besar bagi pembayar pajak
IT sektor publik umumnya berantakan, tetapi saya tahu ada juga engineer bagus yang bekerja di dalamnya
Satu jam yang dihabiskan mondar-mandir mengurus hard disk dan driver, atau versi cloud-nya seperti storage dan Ansible, adalah satu jam yang tidak dipakai untuk membuat hal yang dibutuhkan pelanggan
Kenapa pemerintah harus berbeda?
Kita tidak berharap pemerintah membuat mobil sendiri; kita berharap mereka membelinya dari Volkswagen atau Renault. Bahkan jika pemerintah jelas punya kebutuhan transportasi. Jadi saya tidak mengerti kenapa untuk infrastruktur IT orang bersikeras mereka harus membangunnya sendiri
Lalu ada juga hal yang muncul benar-benar di luar dugaan, seperti pandemi. Kemampuan untuk melakukan scaling sesuai permintaan selama pandemi adalah salah satu contoh demonstrasi utama kenapa sektor publik harus memakai cloud publik komersial
Saya sarankan menonton presentasi bulan September tentang berbagai iterasi Gov.UK dan migrasi antar-cloud: https://youtube.com/watch?v=mpY1lxkikqM&pp=ygUOUmljaGFyZCB0b...
Setidaknya di pemerintah Inggris, karena persyaratan pengadaan, setiap beberapa tahun mereka harus kembali melempar estimasi berbasis penggunaan ke pasar
Misalnya, jika Oracle Cloud harganya sepersepuluh, kemungkinan besar mereka akan memenangkan kontrak, lalu selama masa kontrak harus bermigrasi ke Oracle, dan setelah itu mungkin harus pindah lagi jika ada cloud lain yang lebih murah
Itu hal terburuk yang pernah saya lihat dalam hidup. Padahal saya pernah banyak berurusan dengan legacy seperti VB.NET, Web Forms, SharePoint lama, Basic, bahkan aplikasi yang seluruhnya berupa gumpalan besar stored procedure
AWS, Azure, Google Cloud setidaknya dibuat dengan mempertimbangkan pengguna akhir, yaitu developer. Sebaliknya, cloud pemerintah dirancang dan dibangun oleh penawar termurah yang tujuan pertamanya adalah memangkas biaya di setiap tempat yang memungkinkan
Sebaliknya, saya juga pernah bertemu orang-orang infrastruktur dan operasi yang benar-benar hebat yang menjalankan data center internal lembaga kesehatan pemerintah Jerman. Masalah di sana 100% bukan teknologi atau orangnya, melainkan manajemen dan proses yang selalu menjadi bottleneck dalam setiap interaksi antara tim infrastruktur dan tim engineering