1 poin oleh GN⁺ 3 jam lalu | 1 komentar | Bagikan ke WhatsApp
  • 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, dan stddev, sambil harus mengatasi batasan kompatibilitas seperti tidak didukungnya unsigned bigint dan NOCASE yang 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, stddev yang 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 menerapkan NOCASE
    • NOCASE tidak mendukung case folding UTF penuh dan hanya memproses karakter ASCII
  • 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:migrate tetap berfungsi

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

 
GN⁺ 3 jam lalu
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=NORMAL dan semacamnya sebagai default, dan sepertinya masih ada default lain yang juga bisa diperbaiki

    • Saya samar-samar ingat ada bagian tentang cara perubahan disk dijadwalkan atau diformat yang menguntungkan HDD tetapi cukup tidak cocok untuk NVMe
  • Penasaran dengan strategi backup untuk database SQLite. Ingin tahu apakah memakai alat seperti litestream atau menggunakan cara lain

  • Penasaran bagaimana lobste.rs menangani pekerjaan update

    • Menggunakan pernyataan update milik SQLite. Jika yang dimaksud adalah jenis update lain, mohon diperjelas
  • 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 antrean

    • SQLite FAQ mungkin menjawab sebagian pertanyaan ini. Di banyak proses, banyak operasi baca bisa dilakukan, tetapi penulisan hanya bisa satu per satu, dan SQLite menjaminnya dengan file-system lock
      Untuk 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
    • Operasi tulis memang ditunggu sampai batas tertentu, tetapi pengaturan default-nya kurang bagus sehingga perlu disetel. Konfigurasi yang dipakai saat ini adalah sebagai berikut, dan mode transaksi immediate juga harus diaktifkan agar busy_timeout berfungsi
      "PRAGMA foreign_keys=ON;"  
      "PRAGMA journal_mode = WAL;"  
      "PRAGMA synchronous = NORMAL;"  
      "PRAGMA busy_timeout = 5000;"  
      "PRAGMA temp_store = MEMORY;"  
      "PRAGMA mmap_size = 134217728;"  
      "PRAGMA journal_size_limit = 67108864;"  
      "PRAGMA cache_size = 2000;"  
      
      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 bagian SQLITE_BUSY pada tautan kedua dan di tautan ketiga
  • Ini 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

    • Hasil pencarian menggunakan fitur pemeringkatan milik SQLite, jadi urutan hasilnya bisa berbeda dari MariaDB. Ada tes pencarian, tetapi verifikasi peringkatnya tidak banyak, jadi perubahan fungsional mungkin saja ada, meski belum ada bukti
      Ukuran file SQLite seingat saya pernah disebut sekitar 3.8GB