SQLite dalam pengeluaran pada VPS: Bila ia sesuai
Ketahui bila SQLite sesuai untuk aplikasi kecil pada satu VPS, dengan WAL, busy_timeout, replikasi Litestream dan had satu penulis yang perlu diperhatikan.
Apabila SQLite ialah pangkalan data pengeluaran yang sesuai pada VPS
Menjalankan SQLite dalam persekitaran pengeluaran pada VPS ialah pilihan yang tepat untuk kebanyakan aplikasi kecil. Sebabnya mudah: satu proses pada satu mesin yang menulis ke satu fail tidak memerlukan pelayan pangkalan data. Tiada daemon untuk diselia, tiada port untuk dikonfigurasikan dalam firewall, tiada kata laluan untuk diputar ganti, dan tiada mesin kedua untuk terus beroperasi. Pertanyaan ialah panggilan fungsi, bukannya perjalanan pergi balik melalui rangkaian. Oleh itu, halaman yang menjalankan empat puluh pertanyaan menggunakan empat puluh panggilan fungsi.
Kosnya adalah terhad tetapi nyata. SQLite membenarkan hanya seorang penulis pada satu masa bagi keseluruhan fail pangkalan data, dan fail itu tidak boleh dikongsi antara dua mesin. Kedua-dua had ini tidak menjadi masalah bagi satu VPS yang menjalankan satu aplikasi. Namun, kedua-duanya menjadi penghalang apabila anda melebihi bentuk penggunaan tersebut. Panduan ini menerangkan tetapan yang menjadikan SQLite selamat pada pelayan, sandaran berterusan menggunakan Litestream, serta keadaan apabila anda patut berhenti menggunakan SQLite.
Pasang alat baris perintah terlebih dahulu. Semua langkah di bawah dijalankan pada Ubuntu 24.04.
sudo apt update
sudo apt install -y sqlite3
sqlite3 --versionPerintah itu memaparkan versi yang bermula dengan 3., diikuti tarikh binaan dan cincangan sumber. Ubuntu 24.04 menyediakan SQLite 3.45.1 setakat July 2026. Aplikasi anda mungkin tidak menggunakan perduaan ini. Kebanyakan runtime bahasa pengaturcaraan menyertakan salinan sendiri bagi pustaka SQLite, dan salinan itu selalunya lebih baharu. Oleh itu, semak versi yang dilaporkan oleh pemacu pangkalan data anda sebelum bergantung pada ciri terbaharu.
Mengapa mod WAL ialah perkara pertama yang anda ubah
Secara lalai, SQLite menggunakan jurnal rollback. Sebelum mengubah halaman, SQLite menyalin halaman asal ke dalam fail -journal, kemudian mengedit pangkalan data secara terus. Untuk melakukannya dengan selamat, SQLite mengunci seluruh fail secara eksklusif. Oleh itu, setiap pembaca perlu menunggu selagi terdapat operasi tulis yang sedang berjalan. Pada komputer riba, perkara ini biasanya tidak disedari. Pada pelayan web, satu operasi tulis yang perlahan boleh melambatkan setiap permintaan yang mengakses pangkalan data.
Mod WAL (write-ahead log) membalikkan urutan ini. Penulis menambahkan halaman baharu ke dalam fail -wal yang berasingan dan membiarkan pangkalan data utama tanpa perubahan. Pembaca terus membaca fail utama berdasarkan snapshot yang tersedia ketika pembaca bermula. Oleh itu, pembaca tidak menyekat penulis dan penulis tidak menyekat pembaca. Kemudian, checkpoint menyalin halaman WAL yang terkumpul kembali ke dalam pangkalan data utama. Perubahan ini merupakan faktor utama yang membolehkan SQLite digunakan di belakang aplikasi web.
Hidupkan mod WAL dan sahkan bahawa ia kekal
mkdir -p ~/app
sqlite3 ~/app/app.db "PRAGMA journal_mode=WAL;"Perintah ini mencetak wal. Output itu bukan hiasan. PRAGMA journal_mode mengembalikan mod sebenar pangkalan data, jadi respons delete bermaksud perubahan gagal dan anda masih menggunakan jurnal rollback.
Mod WAL bersifat kekal. Mod ini ialah bendera dalam pengepala pangkalan data, bukan tetapan sambungan. Oleh itu, anda hanya perlu menjalankannya sekali bagi setiap fail pangkalan data. Semua sambungan selepas itu akan mewarisinya, termasuk selepas but semula. Buktikan perkara ini dengan sambungan baharu.
sqlite3 ~/app/app.db "PRAGMA journal_mode;"Sekarang, cipta jadual dan lihat perkara yang muncul pada cakera.
sqlite3 ~/app/app.db <<'SQL'
CREATE TABLE IF NOT EXISTS notes (id INTEGER PRIMARY KEY, body TEXT NOT NULL);
INSERT INTO notes (body) VALUES ('first row');
SQL
ls -l ~/app/Kini terdapat tiga fail: app.db, app.db-wal dan app.db-shm. Fail -wal menyimpan halaman yang telah dilakukan commit tetapi belum dibuat checkpoint. Fail -shm ialah indeks memori dikongsi yang dipetakan oleh setiap sambungan supaya semuanya bersetuju tentang kandungan WAL. Kedua-duanya ialah sebahagian daripada pangkalan data dan bukan fail sementara. Jika anda menyalin app.db sahaja semasa aplikasi sedang berjalan, anda akan mendapat fail yang tidak mengandungi setiap commit terkini. Jika anda memadam app.db dan membiarkan dua fail yang lain, SQLite akan menggunakan halaman WAL lama itu pada sebarang fail baharu yang muncul dengan nama tersebut. Inilah cara orang merosakkan pangkalan data baharu ketika cuba menetapkan semula pangkalan data.
Tetapan sambungan yang diperlukan oleh setiap aplikasi production
Hanya journal_mode disimpan dalam pangkalan data. Setiap tetapan lain di bawah adalah mengikut sambungan. Ini bermakna aplikasi anda perlu menjalankannya pada setiap sambungan yang dibukanya, termasuk setiap sambungan yang dibuat oleh connection pool di latar belakang.
PRAGMA journal_mode = WAL;
PRAGMA busy_timeout = 5000;
PRAGMA synchronous = NORMAL;
PRAGMA foreign_keys = ON;busy_timeout = 5000 memberitahu SQLite supaya terus mencuba pangkalan data yang dikunci sehingga 5000 milisaat sebelum mengembalikan database is locked. Nilai lalainya ialah 0. Oleh itu, secara lalai, SQLite gagal serta-merta apabila dua operasi penulisan bertindih buat kali pertama. Menetapkan satu nilai ini menghapuskan kebanyakan ralat kunci yang sering disalahkan kepada SQLite.
synchronous = NORMAL ialah tetapan yang sesuai dalam mod WAL, dan pertukarannya perlu difahami. Pada FULL, SQLite memanggil fsync pada WAL bagi setiap commit. Pada NORMAL, SQLite melakukan sync semasa checkpoint. Dokumentasi SQLite menjelaskan dengan tegas perkara yang dikorbankan: transaksi tidak lagi tahan terhadap kegagalan kuasa atau reset keras. Pangkalan data tidak akan rosak akibat kehilangan kuasa itu. Anda hanya kehilangan commit terakhir yang belum ditulis ke cakera. Pada VPS, pertukaran ini biasanya sesuai kerana satu fsync dikeluarkan daripada laluan setiap operasi penulisan.
foreign_keys = ON dimatikan secara lalai untuk keserasian ke belakang, dan tetapan ini adalah mengikut sambungan. Skema yang penuh dengan klausa REFERENCES tidak menguatkuasakan apa-apa sehingga setiap sambungan menghidupkan tetapan ini.
Satu lagi tetapan hanya penting kemudian. SQLite melakukan checkpoint secara automatik apabila WAL berkembang melebihi 1000 halaman. Kerja ini dilakukan oleh sambungan yang kebetulan menyelesaikan transaksi pada masa itu. Keadaan ini tidak bermasalah dengan sendirinya. Namun, ia menjadi persoalan apabila Litestream sedang berjalan kerana Litestream memerlukan kawalan terhadap masa checkpoint dilakukan.
Mengapa database is locked masih berlaku selepas anda menetapkan busy_timeout
Inilah kegagalan yang menyebabkan pengguna kembali kepada Postgres, dan puncanya khusus.
Had masa sibuk memasang pengendali sibuk, tetapi SQLite tidak menjamin bahawa pengendali itu akan dipanggil.
Jika SQLite menentukan bahawa memanggil pengendali sibuk boleh menyebabkan kebuntuan, SQLite akan terus mengembalikan SQLITE_BUSY kepada aplikasi tanpa memanggil pengendali sibuk.
Kebuntuan yang cuba dielakkan berlaku apabila transaksi dinaik taraf. BEGIN kosong dalam SQLite bermaksud BEGIN DEFERRED. Jika pernyataan pertama selepasnya ialah SELECT, anda berada dalam transaksi bacaan. Apabila UPDATE kemudian dalam transaksi yang sama perlu menjadi transaksi tulis, dan sambungan lain telah menulis sejak bacaan anda bermula, SQLite tidak boleh menyebabkan anda menunggu. Syot kilat anda sudah lapuk, dan menunggu hanya akan menyebabkan kedua-dua sambungan menemui kebuntuan antara satu sama lain. Dokumentasi menyatakan hasilnya secara langsung:
Pernyataan tulis seterusnya akan menaik taraf transaksi kepada transaksi tulis jika boleh, atau mengembalikan SQLITE_BUSY.
Had masa 5000 milisaat anda tidak pernah digunakan. Ralat berlaku dengan serta-merta. Sebab itu keadaan ini kelihatan seolah-olah tetapan tersebut tidak berfungsi.
Pembetulannya hanya satu perkataan.
BEGIN IMMEDIATE;
UPDATE notes SET body = 'edited' WHERE id = 1;
COMMIT;BEGIN IMMEDIATE memperoleh kunci tulis pada permulaan, sebelum membaca apa-apa. Tiada proses naik taraf, jadi tiada kebuntuan yang perlu dielakkan. Oleh itu, pengendali sibuk digunakan dan sambungan menunggu gilirannya, bukannya gagal. Kekalkan transaksi baca sahaja dalam keadaan tertangguh. Mana-mana transaksi yang mengandungi operasi tulis hendaklah bersifat serta-merta.
Punca kedua ralat kunci lebih sukar dikesan: mengekalkan transaksi tulis terbuka semasa kerja yang perlahan. SQLite membuat serialisasi terhadap penulis. Oleh itu, transaksi yang dibuka, memanggil API luaran melalui rangkaian, kemudian melakukan commit akan menyekat setiap penulis lain sepanjang tempoh panggilan tersebut. Baca data yang diperlukan, tutup transaksi, lakukan kerja yang perlahan, kemudian buka transaksi tulis yang singkat untuk menyimpan hasilnya.
Sandaran berterusan dengan Litestream
Salinan setiap malam boleh menyebabkan kehilangan penulisan sehingga sehari, dan menjalankan cp terhadap pangkalan data SQLite yang sedang digunakan boleh menghasilkan salinan yang tidak dapat dibuka. Dua perkara adalah selamat. sqlite3 app.db ".backup /path/to/backup.db" menggunakan antara muka sandaran dalam talian SQLite dan boleh berfungsi terhadap pangkalan data yang sedang digunakan. Litestream pergi lebih jauh: ia memantau WAL dan menghantar perubahan ke storan objek secara berterusan. Ini mengurangkan kehilangan data maksimum daripada sehari kepada kira-kira satu saat.
Litestream ialah satu binari Go yang berjalan bersama aplikasi anda. Ia tidak berada di antara aplikasi dengan pangkalan data. Aplikasi anda menulis ke SQLite seperti biasa, manakala Litestream membaca WAL dan memuat naik perubahan.
cd /tmp
curl -fsSL -O https://github.com/benbjohnson/litestream/releases/download/v0.5.14/litestream-0.5.14-linux-x86_64.deb
sudo dpkg -i litestream-0.5.14-linux-x86_64.deb
litestream versionv0.5.14 ialah keluaran yang didokumenkan pada halaman pemasangan Linux rasmi setakat July 2026, dan v0.5.15 dikeluarkan pada 21 July 2026. Tukar versi dalam kedua-dua baris supaya sepadan dengan tag semasa pada halaman keluaran. Gunakan pakej arm64 yang sepadan jika VPS anda menggunakan arm64.
Fail konfigurasi terletak di /etc/litestream.yml. Mulakan dengan replika fail setempat kerana kaedah ini membuktikan keseluruhan proses tanpa memerlukan bukti kelayakan awan.
dbs:
- path: /home/appuser/app/app.db
replica:
type: file
path: /var/backups/litestream/appPerhatikan bahawa medan tersebut ialah replica, dalam bentuk tunggal. Litestream 0.5 menggantikan tatasusunan replicas daripada siri 0.3 dengan satu blok replika. Konfigurasi yang mengandungi dua entri kini gagal semasa permulaan. Banyak panduan pihak ketiga masih menunjukkan tatasusunan lama. Oleh itu, salin struktur di atas dan jangan gunakan contoh pertama yang dipaparkan oleh carian. Siri 0.5 juga menamakan semula subperintah litestream wal kepada litestream ltx kerana format sandaran pada cakera telah berubah.
Semak bahawa konfigurasi boleh dihuraikan sebelum anda mendayakan apa-apa.
sudo litestream databases -config /etc/litestream.ymlKemudian uji proses pergi balik secara manual. Bentuk ini memintas fail konfigurasi dan mereplikasi satu pangkalan data ke satu laluan.
mkdir -p /tmp/replica
litestream replicate ~/app/app.db file:///tmp/replica/appPerintah itu berjalan di latar hadapan dan terus berjalan. Dalam shell kedua, tulis satu baris dan pulihkan replika ke dalam fail baharu.
sqlite3 ~/app/app.db "INSERT INTO notes (body) VALUES ('written after replication started');"
litestream restore -o /tmp/restored.db file:///tmp/replica/app
sqlite3 /tmp/restored.db "SELECT count(*) FROM notes;"Kiraan tersebut merangkumi baris baharu. Jika tidak, perubahan itu belum disegerakkan: Litestream menghantar perubahan mengikut sync-interval yang lalai kepada 1 saat. Tunggu dan lakukan pemulihan sekali lagi. Satu saat itu juga ialah titik pemulihan anda. Kerosakan boleh menyebabkan penulisan daripada selang penyegerakan terakhir hilang, dan tiada konfigurasi dapat mengurangkan nilai itu kepada sifar.
Untuk storan sebenar, gantikan blok replika dengan URL S3. Kaedah ini berfungsi dengan Amazon S3 dan storan objek serasi S3 daripada penyedia lain.
dbs:
- path: /home/appuser/app/app.db
replica:
url: s3://your-bucket-name/app
region: us-east-1
snapshot:
interval: 24h
retention: 24hJangan simpan bukti kelayakan dalam fail tersebut. Litestream membaca LITESTREAM_ACCESS_KEY_ID dan LITESTREAM_SECRET_ACCESS_KEY daripada persekitaran. Oleh itu, letakkannya dalam drop-in systemd yang dimiliki oleh root dengan mod 600.
Nilai snapshot di atas ialah nilai lalai, dan nilai lalai pengekalan sering mengelirukan. Pengekalan menentukan tempoh Litestream menyimpan snapshot serta fail yang berkaitan dengannya. Oleh itu, nilai ini juga menentukan sejauh mana anda boleh memulihkan data ke masa lalu. Dua puluh empat jam bermaksud migrasi yang bermasalah dan disedari pada pagi Wednesday sudah tidak boleh dipulihkan daripada keadaan Monday. Tetapkan retention: 168h kepada seminggu dan tanggung kos storan tambahan.
Buktikan pemulihan sebelum anda memerlukannya
litestream restore -o /tmp/check.db /home/appuser/app/app.db
sqlite3 /tmp/check.db "PRAGMA integrity_check;"
sqlite3 /tmp/check.db "SELECT count(*) FROM notes;"Dengan laluan pangkalan data, litestream restore mencari replika yang sepadan dalam /etc/litestream.yml dan memuat turunnya. PRAGMA integrity_check mencetak ok untuk fail yang sihat. Sebarang output lain bermakna salinan yang dipulihkan tidak boleh digunakan. Jalankan ini mengikut jadual menggunakan perkhidmatan dan pemasa systemd dan baca output tersebut. Selagi anda belum memulihkan sandaran sekurang-kurangnya sekali, anda tidak tahu sama ada sandaran itu berfungsi.
Jalankan Litestream di bawah systemd
Pakej Debian memasang unit litestream yang membaca /etc/litestream.yml.
sudo systemctl enable litestream
sudo systemctl start litestream
sudo journalctl -u litestream -fOutput yang sihat menamakan setiap pangkalan data daripada konfigurasi, kemudian tidak memaparkan apa-apa selain baris penyegerakan berkala. Ralat no such file or directory terhadap laluan pangkalan data anda bermaksud laluan dalam konfigurasi salah, atau proses tersebut tidak dapat membacanya. Secara lalai, unit ini berjalan sebagai root, iaitu keistimewaan yang lebih tinggi daripada keperluan tugas ini. Litestream mesti dapat membaca dan menulis pangkalan data serta direktori yang mengandunginya, kerana Litestream menggunakan fail -wal dan -shm yang terletak bersebelahan dengan pangkalan data anda. Oleh itu, berikan unit ini akaun yang telah digunakan oleh aplikasi anda.
# /etc/systemd/system/litestream.service.d/override.conf
[Service]
User=appuser
Group=appuserGunakan perubahan ini dengan sudo systemctl daemon-reload dan sudo systemctl restart litestream. Penyediaan akaun perkhidmatan khusus dengan keistimewaan minimum mengambil masa beberapa minit. Langkah ini membezakan ejen sandaran daripada proses root kedua pada pelayan.
Satu perkara berkaitan urutan penting jika anda membina semula mesin dari awal. Pangkalan data perlu dipulihkan sebelum aplikasi dimulakan. litestream restore menerima -if-db-not-exists, yang keluar dengan kod 0 apabila fail tersebut sudah wujud. Oleh itu, arahan ini selamat dijalankan pada setiap but. Letakkannya dalam baris ExecStartPre pada unit aplikasi anda. VPS baharu akan memuat turun pangkalan data, manakala VPS sedia ada tidak melakukan apa-apa. litestream replicate mempunyai bendera -restore-if-db-not-exists yang sepadan jika anda lebih suka menyimpan konfigurasi ini di satu tempat.
Perkara yang menyebabkan SQLite gagal pada VPS
Sistem fail rangkaian. Ini ialah had yang tidak boleh diatasi melalui konfigurasi. Mod WAL memerlukan setiap proses yang menggunakan pangkalan data berkongsi kawasan kecil dalam memori. Fail -shm menyediakan kawasan tersebut. Dokumentasi SQLite menyatakan peraturan ini tanpa pengecualian:
Semua proses yang menggunakan pangkalan data mesti berada pada komputer hos yang sama; WAL tidak berfungsi melalui sistem fail rangkaian.
Oleh itu, pangkalan data pada perkongsian NFS (sistem fail rangkaian) atau SMB yang dipasang boleh rosak, dan tiada pragma yang dapat menghalangnya. Terdapat perbezaan yang sering terlepas pandang. Peranti blok rangkaian, iaitu jenis peranti yang biasanya dilampirkan oleh kebanyakan penyedia VPS sebagai storan tambahan, kelihatan kepada Linux sebagai cakera biasa dengan sistem fail biasa. Ini tidak menjadi masalah. Perkongsian fail yang dipasang adalah berbeza.
Pelayan aplikasi kedua. Tiada tetapan yang dapat menjadikan konfigurasi ini berfungsi. Sebaik sahaja anda memerlukan dua mesin untuk menyediakan data yang sama, anda memerlukan pangkalan data yang berkomunikasi melalui rangkaian. Buat keputusan untuk beralih semasa anda masih mempunyai masa untuk merancangnya.
Beban kerja yang banyak menulis. Hanya seorang penulis pada satu-satu masa ialah sifat format fail, bukan tetapan yang boleh dilaraskan. Operasi tulis yang singkat tidak mahal kerana setiap commit ditambah pada WAL. Oleh itu, daya pemprosesan lebih bergantung pada kependaman penulisan kecil cakera berbanding CPU anda. Lihat NVMe berbanding storan SSD SATA pada VPS untuk melihat perbezaannya. Transaksi yang panjang ialah masalah sebenar kerana transaksi tersebut menyebabkan semua penulis lain beratur di belakangnya.
Pertanyaan analitik. SQLite ialah penyimpan berasaskan baris yang dibina untuk transaksi. Papan pemuka yang mengimbas seratus juta baris ialah tugas yang berbeza untuk alat yang berbeza. DuckDB berbanding SQLite untuk kerja pelayan menerangkan had penggunaan setiap alat.
VACUUM semasa replikasi. VACUUM penuh menulis semula seluruh fail pangkalan data. Oleh itu, Litestream perlu memuat naik semula keseluruhan fail tersebut. Dokumentasi Litestream menasihatkan supaya operasi ini tidak dijalankan di tempat semasa replikasi aktif. Hentikan replikator, jalankan vacuum, mulakannya semula dan jangkakan snapshot penuh yang baharu.
Dua replikator pada satu pangkalan data. Jangan sekali-kali menjalankan dua proses Litestream terhadap pangkalan data yang sama atau destinasi replika yang sama. Dokumentasi menyatakan dengan jelas bahawa anda bertanggungjawab untuk mencegah keadaan ini. Jika tidak, replika yang terhasil tidak boleh dipulihkan.
Perkara yang tidak dilindungi oleh Litestream
Litestream melindungi fail pangkalan data sahaja. Fail yang dimuat naik, konfigurasi aplikasi, sijil TLS (keselamatan lapisan pengangkutan) dan fail unit masih perlu anda uruskan. Gabungkan Litestream dengan sandaran luar hos yang disulitkan menggunakan restic mengikut jadual supaya kedua-dua aspek dilindungi. Jika mesin itu baharu, sepuluh minit pertama pada VPS baharu merangkumi kerja akaun pengguna dan tembok api yang diandaikan oleh panduan ini telah selesai.
FAQ
Adakah SQLite mencukupi untuk aplikasi pengeluaran?
Untuk satu aplikasi pada satu pelayan, ya, dengan syarat anda mengaktifkan mod WAL, menetapkan tamat masa sibuk, dan membuat sandaran secara berterusan. Had yang penting adalah dari segi struktur: hanya satu penulis pada satu masa dan hanya satu mesin hos. Aplikasi yang berada dalam had ini mendapat pangkalan data tanpa lompatan rangkaian dan tanpa proses berasingan untuk dipantau. Aplikasi yang melebihi had ini memerlukan pangkalan data klien-pelayan, dan sebarang pelarasan tidak akan mengubah keadaan itu.
Mengapakah saya masih menerima database is locked selepas menetapkan busy_timeout?
SQLite melangkau pengendali sibuk apabila penantian boleh menyebabkan kebuntuan. Transaksi yang bermula dengan BEGIN tanpa pilihan ialah transaksi tertangguh: SELECT pembukaan meletakkannya dalam transaksi bacaan, dan penulisan kemudian perlu menaik taraf transaksi tersebut. Jika sambungan lain membuat penulisan sementara itu, SQLite mengembalikan SQLITE_BUSY dengan serta-merta dan bukannya memanggil pengendali sibuk anda, kerana petikan bacaan anda sudah lapuk. Mulakan sebarang transaksi yang akan membuat penulisan dengan BEGIN IMMEDIATE supaya kunci penulisan diperoleh terlebih dahulu dan tamat masa digunakan.
Bolehkah saya menyimpan pangkalan data SQLite pada storan rangkaian?
Tidak pada sistem fail rangkaian seperti NFS atau SMB. Mod WAL memerlukan semua proses berkongsi memori melalui fail -shm, dan dokumentasi SQLite menyatakan bahawa setiap proses yang menggunakan pangkalan data mesti berada pada komputer hos yang sama. Peranti blok rangkaian yang dilampirkan oleh pembekal anda adalah perkara yang berbeza: Linux melihatnya sebagai cakera biasa dengan sistem fail biasa, dan SQLite berfungsi di situ.
Adakah saya memerlukan Litestream jika saya sudah menjalankan sandaran setiap malam?
Ini bergantung pada jumlah data yang anda sanggup kehilangan. Tugas setiap malam bermakna kehilangan penulisan sehingga dua puluh empat jam. Litestream menyegerakkan data kira-kira sekali sesaat, jadi kerosakan menyebabkan anda kehilangan kira-kira satu saat terakhir. Ia juga lebih selamat daripada menyalin fail pangkalan data menggunakan cp, yang boleh menangkap pangkalan data ketika penulisan sedang berlangsung. Litestream hanya melindungi pangkalan data, jadi teruskan sandaran fail umum secara berasingan.