Cara Gunakan SQLite Untuk Aplikasi Pengeluaran di VPS
Ketahui cara mengoptimumkan SQLite bagi aplikasi kecil di VPS. Panduan ini merangkumi mod WAL, busy_timeout, replikasi Litestream serta had sebenar penggunaan pangkalan data ini.
Apabila SQLite menjadi pangkalan data pengeluaran yang tepat pada VPS
Menjalankan SQLite dalam persekitaran pengeluaran pada VPS adalah pilihan yang tepat untuk kebanyakan aplikasi kecil, dan sebabnya mudah: satu proses pada satu mesin yang menulis ke satu fail tidak memerlukan pelayan pangkalan data. Tiada daemon untuk diselia, tiada port untuk difirewall, tiada kata laluan untuk ditukar, dan tiada mesin kedua untuk dikekalkan. Pertanyaan (query) adalah panggilan fungsi dan bukannya perjalanan rangkaian pergi balik, jadi halaman yang menjalankan empat puluh pertanyaan hanya menelan kos empat puluh panggilan fungsi.
Kosnya adalah terhad dan nyata. SQLite membenarkan seorang penulis pada satu masa untuk keseluruhan fail pangkalan data, dan fail tersebut tidak boleh dikongsi antara dua mesin. Kedua-dua had ini boleh diterima untuk satu VPS yang menjalankan satu aplikasi. Kedua-duanya akan menjadi masalah besar sebaik sahaja anda melangkaui bentuk tersebut. Panduan ini merangkumi tetapan yang menjadikan SQLite selamat pada pelayan, sandaran berterusan dengan Litestream, dan tahap di mana anda perlu berhenti menggunakannya.
Pasang alat baris perintah terlebih dahulu. Semua arahan di bawah dijalankan pada Ubuntu 24.04.
sudo apt update
sudo apt install -y sqlite3
sqlite3 --versionArahan itu akan mencetak versi yang bermula dengan 3. diikuti dengan tarikh binaan dan hash sumber. Ubuntu 24.04 membekalkan SQLite 3.45.1 setakat Julai 2026. Aplikasi anda mungkin tidak menggunakan binari ini: kebanyakan runtime bahasa membundel salinan pustaka SQLite mereka sendiri, selalunya versi yang lebih baharu, jadi semak versi yang dilaporkan oleh pemacu pangkalan data anda sebelum anda bergantung pada ciri terkini.
Mengapa mod WAL ialah perkara pertama yang perlu anda ubah
Secara lalai, SQLite menggunakan rollback journal. Sebelum menukar sesuatu halaman, ia menyalin halaman asal ke dalam fail -journal, kemudian menyunting pangkalan data di tempatnya. Untuk melakukan perkara itu dengan selamat, ia mengambil kunci eksklusif pada keseluruhan fail, jadi setiap pembaca perlu menunggu semasa sebarang penulisan sedang berjalan. Pada komputer riba, tiada siapa yang menyedarinya. Pada pelayan web, satu penulisan yang perlahan akan menyekat setiap permintaan yang mengakses pangkalan data tersebut.
Mod WAL (write-ahead log) menyongsangkan urutan ini. Penulis menambah halaman baharu ke dalam fail -wal yang berasingan dan membiarkan pangkalan data utama tidak disentuh. Pembaca terus membaca fail utama pada snapshot yang mereka mulakan, jadi pembaca tidak menyekat penulis dan penulis tidak menyekat pembaca. Kemudian, satu checkpoint akan menyalin halaman WAL yang terkumpul kembali ke dalam pangkalan data utama. Perubahan tunggal ini merupakan faktor utama yang menjadikan SQLite boleh digunakan di sebalik aplikasi web.
Hidupkan mod WAL dan sahkan ia kekal
mkdir -p ~/app
sqlite3 ~/app/app.db "PRAGMA journal_mode=WAL;"Perintah tersebut mencetak wal. Output itu bukan sekadar hiasan. PRAGMA journal_mode mengembalikan mod sebenar pangkalan data, jadi balasan delete bermakna perubahan gagal dan anda masih menggunakan rollback journal.
Mod WAL adalah kekal. Ia merupakan flag dalam pengepala pangkalan data dan bukannya tetapan sambungan, jadi anda hanya perlu menjalankannya sekali bagi setiap fail pangkalan data dan setiap 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 apa 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/Terdapat tiga fail sekarang: app.db, app.db-wal dan app.db-shm. Fail -wal menyimpan halaman yang telah di-commit tetapi belum di-checkpoint. Fail -shm ialah indeks memori kongsi yang dipetakan oleh setiap sambungan supaya semuanya bersetuju tentang kandungan WAL. Kedua-duanya adalah milik pangkalan data dan bukan fail sementara. Jika anda menyalin app.db secara berasingan semasa aplikasi sedang berjalan, anda akan mendapat fail yang kehilangan setiap commit terbaharu. Jika anda memadam app.db dan membiarkan dua fail lain di tempatnya, SQLite akan menggunakan halaman WAL lama tersebut pada mana-mana fail baharu yang muncul dengan nama itu; inilah cara pengguna merosakkan pangkalan data baharu semasa cuba menetapkan semula pangkalan data sedia ada.
Tetapan sambungan yang diperlukan oleh setiap aplikasi pengeluaran
Hanya journal_mode yang disimpan di dalam pangkalan data. Setiap tetapan lain di bawah adalah mengikut sambungan, yang bermaksud aplikasi anda perlu menjalankannya pada setiap sambungan yang dibuka, termasuk setiap sambungan yang dicipta oleh 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 semula pangkalan data yang terkunci sehingga 5000 milisaat sebelum ia mengembalikan database is locked. Nilai lalai ialah 0, jadi secara lalai SQLite gagal serta-merta apabila dua penulis bertindih buat kali pertama. Menetapkan nilai tunggal ini menghapuskan kebanyakan ralat kunci yang sering disalahkan kepada SQLite sendiri.
synchronous = NORMAL ialah tetapan yang betul dalam mod WAL, dan pertukaran ini wajar difahami. Pada FULL, SQLite memanggil fsync pada WAL pada setiap commit. Pada NORMAL, ia melakukan penyelarasan (sync) semasa checkpoint sahaja. Dokumentasi SQLite menyatakan dengan jelas apa yang anda korbankan: transaksi tidak lagi bersifat durable selepas kegagalan kuasa atau hard reset. Pangkalan data tidak akan rosak akibat kehilangan kuasa tersebut, anda hanya kehilangan commit terakhir yang belum sampai ke cakera. Pada VPS, ini biasanya merupakan pertukaran yang wajar, kerana ia mengeluarkan fsync daripada laluan setiap penulisan.
foreign_keys = ON dimatikan secara lalai untuk keserasian ke belakang, dan ia adalah mengikut sambungan. Skema yang penuh dengan klausa REFERENCES tidak menguatkuasakan apa-apa sehingga setiap sambungan mengaktifkan tetapan ini.
Satu lagi tetapan hanya penting kemudian. SQLite melakukan checkpoint secara automatik sebaik sahaja WAL melebihi 1000 halaman, dan kerja tersebut dilakukan oleh mana-mana sambungan yang kebetulan menamatkan transaksi pada saat itu. Itu sudah memadai. Ia menjadi persoalan apabila Litestream sedang berjalan, kerana Litestream mahukan kawalan ke atas bila checkpoint berlaku.
Mengapa database is locked masih berlaku selepas anda menetapkan busy_timeout
Ini ialah kegagalan yang menyebabkan pengguna kembali kepada Postgres, dan ia mempunyai satu punca khusus.
Busy timeout memasang pengendali sibuk (busy handler), dan SQLite tidak menjamin untuk memanggilnya.
Jika SQLite menentukan bahawa memanggil pengendali sibuk boleh menyebabkan kebuntuan (deadlock), ia akan terus mengembalikan SQLITE_BUSY kepada aplikasi dan bukannya memanggil pengendali sibuk tersebut.
Kebuntuan yang dielakkan itu berlaku apabila transaksi dinaik taraf. BEGIN kosong dalam SQLite bermaksud BEGIN DEFERRED. Jika pernyataan pertama selepasnya ialah SELECT, anda berada dalam transaksi baca. Apabila UPDATE kemudian dalam transaksi yang sama perlu menjadi transaksi tulis, dan sambungan lain telah menulis sejak bacaan anda bermula, SQLite tidak boleh membuat anda menunggu. Ini kerana syot kilat (snapshot) anda sudah lapuk dan menunggu hanya akan menyebabkan kedua-dua sambungan mengalami kebuntuan antara satu sama lain. Dokumentasi menyatakan hasilnya secara terus:
Pernyataan tulis seterusnya akan menaik taraf transaksi kepada transaksi tulis jika boleh, atau mengembalikan SQLITE_BUSY.
Had masa 5000 milisaat anda tidak pernah dirujuk. Ralat tiba serta-merta, itulah sebabnya ia kelihatan seolah-olah tetapan tersebut tidak berfungsi.
Penyelesaiannya ialah satu perkataan.
BEGIN IMMEDIATE;
UPDATE notes SET body = 'edited' WHERE id = 1;
COMMIT;BEGIN IMMEDIATE mengambil kunci tulis pada permulaan, sebelum membaca apa-apa. Tiada naik taraf, jadi tiada kebuntuan untuk dielakkan, maka pengendali sibuk akan digunakan dan sambungan akan menunggu gilirannya dan bukannya gagal. Pastikan transaksi baca sahaja sebagai deferred. Sebarang transaksi yang mengandungi operasi tulis haruslah immediate.
Punca kedua ralat kunci lebih sukar dikesan: membiarkan transaksi tulis terbuka semasa melakukan kerja yang perlahan. SQLite menyirikan (serialize) penulis, jadi transaksi yang dibuka, memanggil API luaran melalui rangkaian, dan kemudian melakukan commit akan menyekat setiap penulis lain sepanjang tempoh panggilan tersebut. Baca apa yang anda perlukan, tutup transaksi, lakukan kerja yang perlahan, kemudian buka transaksi tulis yang singkat untuk menyimpan hasilnya.
Sandaran berterusan dengan Litestream
Salinan harian boleh menyebabkan kehilangan data sehingga sehari, dan menjalankan cp terhadap pangkalan data SQLite yang sedang aktif boleh menghasilkan salinan yang tidak boleh dibuka. Terdapat dua kaedah yang selamat. sqlite3 app.db ".backup /path/to/backup.db" menggunakan antara muka sandaran dalam talian SQLite dan berfungsi terhadap pangkalan data yang sedang digunakan. Litestream melangkah lebih jauh: ia memantau WAL dan menghantar perubahan ke storan objek secara berterusan, yang mengurangkan risiko kehilangan data daripada sehari kepada kira-kira satu saat.
Litestream ialah satu binari Go yang berjalan di samping aplikasi anda. Ia tidak berada di antara aplikasi dan pangkalan data. Aplikasi anda menulis ke SQLite seperti biasa, dan Litestream membaca WAL serta memuat naik apa yang berubah.
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 dalam halaman pemasangan Linux rasmi setakat Julai 2026, dan v0.5.15 menyusul pada 21 Julai 2026. Tukar versi dalam kedua-dua baris untuk memadankan tag semasa pada halaman keluaran, dan ambil pakej arm64 yang sepadan jika VPS anda menggunakan arm64.
Fail konfigurasi terletak di /etc/litestream.yml. Mulakan dengan replika fail setempat, kerana ia membuktikan keseluruhan gelung tanpa memerlukan 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 blok replika tunggal, dan konfigurasi yang membawa dua entri akan gagal semasa permulaan. Banyak panduan pihak ketiga masih menunjukkan tatasusunan lama, jadi salin bentuk di atas dan bukannya contoh pertama yang ditemui melalui carian. Siri 0.5 juga menamakan semula subperintah litestream wal kepada litestream ltx, kerana format sandaran pada cakera telah berubah.
Pastikan konfigurasi diurai dengan betul sebelum anda mendayakan apa-apa.
sudo litestream databases -config /etc/litestream.ymlKemudian, buktikan kitaran lengkap secara manual. Bentuk ini melangkau 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 depan dan terus beroperasi. 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 termasuk baris baharu itu. Jika tidak, perubahan tersebut belum diselaraskan lagi: Litestream menolak data pada sync-interval yang ditetapkan secara lalai kepada 1 saat, jadi tunggu dan pulihkan sekali lagi. Satu saat itu juga merupakan titik pemulihan anda. Kegagalan sistem menyebabkan kehilangan data maksimum daripada selang penyelarasan terakhir, dan tiada konfigurasi yang boleh menjadikannya sifar.
Untuk storan sebenar, tukar blok replika kepada URL S3. Ini berfungsi terhadap Amazon S3 dan storan objek yang serasi dengan 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: 24hPastikan kelayakan tidak diletakkan dalam fail tersebut. Litestream membaca LITESTREAM_ACCESS_KEY_ID dan LITESTREAM_SECRET_ACCESS_KEY daripada persekitaran, jadi letakkannya dalam fail drop-in systemd yang dimiliki oleh root dengan mod 600.
Nilai snapshot di atas adalah nilai lalai, dan nilai lalai pengekalan sering mengejutkan pengguna. Pengekalan ialah tempoh Litestream menyimpan snapshot dan fail yang berkaitan dengannya, jadi ia juga menentukan sejauh mana anda boleh memulihkan data ke masa lalu. Dua puluh empat jam bermakna migrasi buruk yang anda sedari pada pagi Rabu sudah tidak boleh dipulihkan daripada keadaan hari Isnin. Tetapkan retention: 168h untuk seminggu dan bayar kos storan tambahan tersebut.
Pastikan pemulihan berfungsi 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;"Diberikan satu laluan pangkalan data, litestream restore akan mencari replika yang sepadan dalam /etc/litestream.yml dan memuat turunnya. PRAGMA integrity_check akan mencetak ok jika fail tersebut dalam keadaan baik, dan sebarang output lain bermakna salinan yang dipulihkan tidak boleh digunakan. Jalankan proses ini mengikut jadual menggunakan perkhidmatan dan pemasa systemd serta semak outputnya. Selagi anda belum pernah memulihkan sandaran, anda tidak tahu sama ada ia benar-benar berfungsi.
Menjalankan 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 akan menyenaraikan setiap pangkalan data daripada konfigurasi dan kemudian kekal senyap selain daripada baris penyelarasan berkala. Ralat no such file or directory terhadap laluan pangkalan data anda bermakna laluan dalam konfigurasi adalah salah, atau proses tersebut tidak dapat membacanya. Unit ini berjalan sebagai root secara lalai, yang merupakan keistimewaan lebih daripada yang diperlukan oleh tugasan ini. Litestream mesti boleh membaca dan menulis kedua-dua pangkalan data serta direktori yang menyimpannya, kerana ia berfungsi dengan fail -wal dan -shm di sebelah pangkalan data anda, jadi berikan akses kepada akaun yang sudah digunakan oleh aplikasi anda.
# /etc/systemd/system/litestream.service.d/override.conf
[Service]
User=appuser
Group=appuserGunakan tetapan tersebut dengan sudo systemctl daemon-reload dan sudo systemctl restart litestream. Menyediakan akaun servis khusus dengan keistimewaan paling rendah mengambil masa beberapa minit, dan ia merupakan perbezaan antara ejen sandaran dengan proses root kedua pada mesin tersebut.
Satu perincian susunan adalah penting jika anda membina semula mesin dari awal. Anda mahu pangkalan data dipulihkan sebelum aplikasi bermula. litestream restore menerima -if-db-not-exists, yang keluar dengan kod 0 apabila fail sudah sedia ada, jadi ia selamat untuk dijalankan pada setiap but. Letakkannya dalam baris ExecStartPre pada unit aplikasi anda dan VPS baharu akan memuat turun pangkalan data tersebut manakala VPS sedia ada tidak melakukan apa-apa. litestream replicate mempunyai flag -restore-if-db-not-exists yang sepadan jika anda lebih suka menyimpannya di satu tempat.
Di mana SQLite gagal pada VPS
Sistem fail rangkaian. Ini adalah had yang tidak boleh diatasi melalui konfigurasi. Mod WAL memerlukan setiap proses yang menggunakan pangkalan data untuk berkongsi kawasan memori kecil, iaitu fungsi yang disediakan oleh fail -shm. Dokumentasi SQLite menyatakan peraturan ini tanpa pengecualian:
Semua proses yang menggunakan pangkalan data mestilah berada pada komputer hos yang sama; WAL tidak berfungsi melalui sistem fail rangkaian.
Oleh itu, pangkalan data pada NFS (network file system) atau share SMB yang dipasang (mounted) boleh mengalami kerosakan, dan tiada pragma yang dapat menghalangnya. Terdapat perbezaan di sini yang sering terlepas pandang. Peranti block rangkaian, yang merupakan storan tambahan yang dibekalkan oleh kebanyakan penyedia VPS, muncul kepada Linux sebagai cakera biasa dengan sistem fail biasa, dan ini adalah selamat. File share yang dipasang adalah berbeza.
Pelayan aplikasi kedua. Tiada tetapan yang boleh menjadikannya berfungsi. Sebaik sahaja anda memerlukan dua mesin untuk melayani data yang sama, anda memerlukan pangkalan data yang berkomunikasi melalui rangkaian. Buat keputusan untuk beralih sementara anda masih mempunyai masa untuk merancangnya.
Beban kerja dengan banyak penulisan (write-heavy). Satu penulis pada satu masa adalah sifat format fail tersebut, bukan sesuatu yang boleh dilaraskan. Penulisan pendek adalah murah kerana setiap commit adalah penambahan (append) kepada WAL, jadi throughput lebih bergantung kepada latensi penulisan kecil cakera anda berbanding CPU. Lihat NVMe berbanding storan SATA SSD pada VPS untuk melihat perbezaan tersebut. Transaksi yang panjang adalah masalah sebenar, kerana ia akan menyekat setiap penulis lain di belakangnya.
Pertanyaan analitikal. SQLite ialah storan baris yang dibina untuk transaksi. Papan pemuka yang mengimbas seratus juta baris adalah tugas berbeza untuk alat yang berbeza, dan DuckDB berbanding SQLite untuk kerja pelayan merangkumi di mana had tersebut terletak.
VACUUM di bawah replikasi. VACUUM penuh akan menulis semula keseluruhan fail pangkalan data, yang bermaksud Litestream perlu memuat naik kesemuanya sekali lagi, dan dokumentasi Litestream menasihatkan agar tidak menjalankannya secara terus semasa replikasi aktif. Hentikan replikator, lakukan vacuum, mulakan 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 tanggungjawab untuk mencegah perkara ini terletak pada anda, dan hasilnya adalah replika yang tidak boleh dipulihkan.
Perkara yang tidak dilindungi oleh Litestream
Litestream hanya melindungi fail pangkalan data dan tiada yang lain. Fail yang dimuat naik, konfigurasi aplikasi, sijil TLS (transport layer security) dan fail unit masih di bawah tanggungjawab anda. Gandingkan ia dengan sandaran luar kotak yang disulitkan menggunakan restic mengikut jadual supaya kedua-dua bahagian dilindungi. Jika mesin tersebut baharu, sepuluh minit pertama pada VPS baharu merangkumi kerja akaun pengguna dan firewall yang diandaikan sudah selesai dalam panduan ini.
FAQ
Adakah SQLite cukup baik untuk aplikasi pengeluaran?
Untuk satu aplikasi pada satu pelayan, ya, dengan syarat anda menghidupkan mod WAL, menetapkan busy timeout, dan membuat sandaran secara berterusan. Had yang penting adalah dari segi struktur: satu penulis pada satu masa, dan satu mesin hos. Aplikasi yang memenuhi had tersebut mendapat pangkalan data tanpa lompatan rangkaian dan tanpa proses berasingan untuk dipantau. Aplikasi yang tidak memenuhi had tersebut memerlukan pangkalan data klien-pelayan, dan tiada jumlah penalaan yang boleh mengubah perkara itu.
Mengapa saya masih mendapat database is locked selepas menetapkan busy_timeout?
Kerana SQLite melangkau pengendali sibuk (busy handler) apabila menunggu boleh menyebabkan kebuntuan (deadlock). Transaksi yang bermula dengan BEGIN biasa adalah tertangguh (deferred): SELECT pembukaan meletakkannya dalam transaksi baca, dan penulisan kemudian perlu dinaik taraf. Jika sambungan lain menulis di antara masa tersebut, SQLite mengembalikan SQLITE_BUSY serta-merta dan bukannya memanggil pengendali sibuk anda, kerana syot kilat baca anda sudah lapuk. Mulakan sebarang transaksi yang akan menulis dengan BEGIN IMMEDIATE supaya kunci tulis diambil di awal dan timeout akan terpakai.
Bolehkah saya menyimpan pangkalan data SQLite saya 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 melihat cakera biasa dengan sistem fail biasa di atasnya, dan SQLite berfungsi di sana.
Adakah saya memerlukan Litestream jika saya sudah menjalankan sandaran harian?
Ia bergantung kepada berapa banyak data yang anda sanggup hilang. Tugasan harian bermakna kehilangan sehingga dua puluh empat jam penulisan. Litestream menyegerakkan kira-kira sekali sesaat, jadi kegagalan sistem menyebabkan anda kehilangan kira-kira satu saat terakhir. Ia juga lebih selamat daripada menyalin fail pangkalan data dengan cp, yang boleh menangkap pangkalan data semasa sedang menulis. Litestream hanya melindungi pangkalan data, jadi pastikan sandaran fail umum tetap dijalankan di sampingnya.