lobste.rs Beralih dari MariaDB ke SQLite
(lobste.rs)- Setelah beralih dari MariaDB ke SQLite, lobste.rs mampu menangani lonjakan trafik hari Senin dengan stabil, serta mengonfirmasi penurunan penggunaan CPU dan memori serta respons yang terasa lebih cepat
- Jika VPS MariaDB terpisah dimatikan, biaya VPS akan berkurang separuh, dan tugas migrasi yang dimulai pada 2019 juga selesai
- Pada deployment pertama, semua CPU mencapai 100% hanya dengan trafik read-only sehingga dilakukan rollback, tetapi setelah memperbaiki dua full table scan pada tabel besar dan masalah N+1, deployment ulang berhasil
- Dengan user-defined function SQLite, mereka mengimplementasikan
regexp,if, danstddev, sambil harus mengatasi batasan kompatibilitas seperti tidak didukungnya unsigned bigint danNOCASEyang hanya memproses ASCII - Untuk mengganti database dasar tanpa akses ke database produksi, dibutuhkan data uji berukuran realistis, test suite, checklist deployment dan rollback, serta kolaborasi yang erat
Dari diskusi 2019 hingga migrasi ke SQLite
- Diskusi migrasi dimulai pada 2019 di issue #539
- Saat itu MySQL diusulkan sebagai alternatif dengan mempertimbangkan kompatibilitas dengan MariaDB, tetapi diskusi migrasi ke PostgreSQL sudah berjalan
- Pada 2025, Rahul menyebut akuisisi MariaDB oleh K1, lalu diskusi detail migrasi PostgreSQL berlanjut
- Pada Februari, Rahul bertanya apakah lobsters bisa berjalan di SQLite, dan mulai Juni 2025 keterlibatan dalam proyek menjadi lebih serius
- PR pertama pada Agustus 2025 terhenti, lalu ditutup oleh GitHub sebagai PR lama sehingga tidak bisa dibuka kembali
- PR kedua mencakup pengujian performa, skrip migrasi antar-DB buatan sendiri, dan debugging terkait integritas data
- Karena tidak ada skrip konversi MariaDB/MySQL→SQLite yang ada yang memenuhi kebutuhan, mereka menulis skrip terpisah
Kegagalan deployment pertama dan perbaikan bottleneck performa
- Deployment pertama pada 21 Februari dilakukan dengan menyiapkan checklist deployment, tetapi segera setelah deployment, semua CPU mencapai 100% hanya dengan trafik dalam kondisi read-only
- Karena penyebabnya tidak ditemukan, mereka melakukan rollback
- Karena tidak bisa mengakses DB produksi, sulit mereproduksi masalah performa nyata sebelumnya
- Dua hari setelah kegagalan itu, mereka membuka PR ketiga sekaligus final untuk memperbaiki masalah terkait pencarian, dan menambahkan skrip pembuatan data massal yang membuat data lokal berukuran setengah dari data lobsters sebenarnya
- Pembuatan data memakan waktu satu minggu
- Bottleneck pada deployment pertama adalah full table scan yang dipicu dua query pada tabel besar serta satu masalah N+1 terpisah
- Mereka menerapkan perubahan 1, perubahan 2, dan perubahan 3 untuk mengatasinya
- Pada pagi hari deployment, mereka menambahkan slow query log agar masalah performa tambahan bisa dilacak
Hasil deployment ulang dan penghematan biaya operasional
- Pada deployment kedua tanggal 11 Juli, mereka kembali menyiapkan checklist deployment dan rollback, dan setelah migrasi situs tetap beroperasi normal sementara penggunaan CPU dan memori juga stabil
- Sambil memantau metrik situs dan IRC, mereka segera menangani masalah yang dilaporkan melalui perbaikan 1 dan perbaikan 2
- Lonjakan trafik hari Senin juga tidak menimbulkan masalah, dan mereka mengonfirmasi penggunaan CPU dan memori yang lebih rendah serta respons yang terasa lebih cepat
- Jika VPS MariaDB dihentikan, biaya VPS akan berkurang separuh, dan issue migrasi juga ditutup
Batasan SQLite yang berbeda dari MariaDB
- Dengan dukungan user-defined function (UDF) dari gem SQLite, mereka mengimplementasikan
regexp,if,stddevyang tidak ada di SQLite- Mereka tidak perlu menambahkan terlalu banyak workaround untuk migrasi SQL
- Karena SQLite tidak mendukung unsigned bigint yang digunakan MariaDB untuk beberapa ID, mereka mengubahnya menjadi bigint
- Aturan collation juga lebih terbatas dibanding MariaDB
- Di MariaDB mereka menggunakan
utf8mb4_general_ci, tetapi di SQLite mereka menerapkanNOCASE NOCASEtidak mendukung case folding UTF penuh dan hanya memproses karakter ASCII
- Di MariaDB mereka menggunakan
- Untuk tabel full-text search SQLite, Contentless-Delete Tables, yaitu cara yang direkomendasikan tetapi bukan default, cocok digunakan
- Pengaturan PRAGMA default Rails bekerja dengan baik di lobsters
- Migrasi database berbeda untuk tiap DB, sehingga migrasi lama dipindahkan ke direktori old_migrations agar
db:migratetetap berfungsi
- Migrasi database berbeda untuk tiap DB, sehingga migrasi lama dipindahkan ke direktori old_migrations agar
Pelajaran dari pengujian dan kolaborasi
- Di codebase lobsters, mereka menemukan parser pencarian dan heinous_inline_partials, sebuah hack untuk mempercepat rendering
- Berkat test suite, mereka dapat memverifikasi kebenaran migrasi ke SQLite tanpa banyak pengujian manual berskala besar
- Komunikasi yang lancar antarpartisipan menentukan keberhasilan migrasi
- Mengganti database dasar dalam kondisi tanpa akses ke DB produksi sangat sulit
- Jika melakukan pekerjaan yang sama lagi, mereka perlu menyiapkan skala data yang realistis sebelumnya
- Jika saat pengujian bisa diatur agar gagal ketika terjadi full table scan, masalah performa pada deployment pertama bisa ditemukan lebih awal
- Dibutuhkan alat yang dapat dengan mudah membuat dataset mirip produksi tanpa harus menulisnya sendiri atau menunggu hingga seminggu
1 komentar
Pendapat di Lobste.rs
@thomas0 menangani migrasi besar ini dengan sangat teliti, @355E3B membantu perencanaan dan operasional, dan berkat para kontributor terkait #539 serta #lobsters, masa mode hanya-baca juga bisa dilewati dengan menyenangkan
Awalnya di #539 yang direncanakan adalah PostgreSQL, tetapi karena relawan yang benar-benar mengerjakan migrasi menggunakan SQLite, dan karena ingin menghindari solusi yang lebih besar serta lebih kompleks daripada kebutuhan nyata, akhirnya dipilih SQLite. PostgreSQL biasanya menjadi pilihan default, tetapi ada beban tambahan untuk menjalankan, menyetel, dan memelihara layanan terpisah
Yang mengejutkan, setelah migrasi penggunaan CPU dan RAM sama-sama menurun, dan grafik detailnya ada di bagian akhir #539
Setiap kali melihat pengaturan default SQLite rasanya mengejutkan. Akan bagus jika ada mode untuk proyek baru yang menjadikan WAL, foreign key,
synchronous=NORMALdan semacamnya sebagai default, dan sepertinya masih ada default lain yang juga bisa diperbaikiPenasaran dengan strategi backup untuk database SQLite. Ingin tahu apakah memakai alat seperti litestream atau menggunakan cara lain
Penasaran bagaimana lobste.rs menangani pekerjaan update
SQLite sudah punya fungsi iif, tetapi menarik juga bahwa fungsi buatan pengguna dijalankan di area yang sama
Saya kira SQLite tidak mendukung konkurensi setara PostgreSQL atau MySQL, tetapi dari dokumen ringkasan, apakah sekarang pemahamannya adalah bisa dipakai oleh banyak proses namun lobste.rs tetap harus berjalan di satu server
Apakah proses-proses itu disinkronkan di dalam SQLite melalui shared memory atau
mmap, sehingga hanya satu penulisan yang bisa berlangsung pada saat yang sama sementara banyak pembacaan diizinkan, dan apakah operasi tulis yang menunggu juga menanti giliran di antreanUntuk penantian penulisan, tampaknya bukan antrean shared memory yang eksplisit, melainkan menunggu sebentar lalu mencoba lagi. Tidak sepenuhnya pasti apakah SQLite benar-benar mustahil dipakai di banyak mesin, tetapi pendekatan sederhana berbagi file lewat NFS secara eksplisit tidak disarankan, jadi memahami ini sebagai satu server adalah pendekatan yang masuk akal, dan akhir-akhir ini satu mesin pun bisa menangani skala yang cukup besar
busy_timeoutberfungsi Referensi: https://fractaledmind.github.io/2024/04/… serta https://kerkour.com/sqlite-for-servers dan https://www.sqlite.org/lang_transaction.html#immediate; detail lebih lanjut bisa dilihat di bagianSQLITE_BUSYpada tautan kedua dan di tautan ketigaIni peningkatan yang mengesankan, dengan detail yang sangat rapi di PR, issue, dan Gist. Saya penasaran apakah perubahan ini menimbulkan perbedaan fungsional seperti pencarian situs, dan berapa ukuran file SQLite di disk saat ini
Ukuran file SQLite seingat saya pernah disebut sekitar 3.8GB