小巧、快速、可靠
任選三項

網路上的 SQLite
注意事項和考量事項

簡介

SQLite 函式庫的使用者,特別是應用程式開發人員,如果想要存取透過網路連線的不同系統上的 SQLite 資料庫,通常會很輕易地透過指定一個檔案名稱,來開啟一個資料庫連線,而這個檔案名稱會參考網路檔案系統中的某個資料庫檔案。(這裡的「遠端資料庫」)然後透過作業系統 API 存取這個「檔案」,讓使用者產生一種從/到本地端檔案的 I/O 錯覺。這種錯覺雖然很好,但在某些重要的方面並不完美。

這種簡單的「遠端資料庫」方法通常不是從多個系統使用單一 SQLite 資料庫的最佳方式(即使它看起來「有效」),因為它經常會導致各種問題和麻煩。由於這些問題在某些使用情況下是不可避免的,但並非經常發生或可重複,因此應用程式開發人員不應依賴早期的測試成功來判定他們的遠端資料庫使用方式是否能如預期般運作。

使用遠端資料庫檔案時產生的問題

下圖顯示元件及其連結,供後續討論時參考

Client Application SQLite Database Engine Database File(s) SQLite API Calls DB Engine File I/O

這些問題來自於上述三個區塊之間兩個資料/控制通道的屬性和使用方式。

通道流量

「API 呼叫」頻道承載的資訊少於「檔案 I/O」頻道。提交查詢或指定資料修改的 API 呼叫通常需要傳遞的位元少於傳輸到/從資料庫檔案以儲存或尋找資料的位元。「查詢結果擷取」通常需要比 API 流量更多的檔案流量,因為要傳回的資料很少可以在不讀取未請求資料的情況下找到。

頻道頻寬

「API 呼叫」頻道以處理器主記憶體速度(每秒千兆字)運作,資料通常透過參照傳遞(因此不會複製)。相反地,即使是最快的檔案 I/O 頻道也較慢。它們需要複製資料,通常透過需要位元序列化的媒介。對於旋轉磁性媒體,傳輸等待盤片旋轉和磁頭移動,然後受到旋轉速度的限制。

當檔案 I/O 頻道包含網路連線時(除了在其遠端進行一些真正的檔案 I/O 之外),會造成額外的緩慢。即使原始傳輸速率沒有限制頻寬,流量仍必須在兩端封包和緩衝。額外的 I/O 處理器層會增加排程延遲。然而,傳輸速度變慢是網路檔案系統最不重要的問題。

頻道可靠性

「API 呼叫」頻道高度可靠,錯誤率未說明且被忽略為可忽略不計。只有當系統斷電時,頻道才會發生故障(隕石等情況除外)。

「檔案 I/O」頻道在直接連接到本機儲存裝置時,也高度可靠。(旋轉儲存的 MTBF 超過 100 萬小時,NVRAM 的使用壽命更長。)本機裝置還有一個特性,對於設計資料庫管理軟體以確保ACID行為至關重要:當所有處理寫入裝置都已完成時(當 POSIX fsync() 或 Windows FlushFileBuffers() 呼叫傳回時),檔案系統會儲存「已寫入」資料,或在儲存任何後續寫入資料之前儲存「已寫入」資料。

當網路檔案系統裝置和軟體層介於檔案系統用戶端和實際儲存裝置的檔案系統之間時,會引入故障和錯誤行為的重大來源。雖然網路資料傳輸經過良好的錯誤檢查,但傳輸封包並非全部都能在傳送後可靠地到達目的地。有些封包會被其他封包破壞,必須重新傳送。在封包破壞的狀況下,重複重試會造成延遲,超過類似資料傳輸到本機儲存裝置所需的時間。用戶端寫入的某些部分最終會儲存在與其他寫入部分不同的時間順序。

由於網路檔案系統寫入會發生資料失序和完全遺失,因此在開始後續一組檔案寫入之前,必須準確知道一組檔案寫入已完成。此保證是透過使用設計穩健且實作正確的 fsync()(或等效)作業系統函數取得。不幸的是,對於某些應用程式而言,網路檔案系統同步作業可能不如本機檔案系統同步穩健。在網路封包傳輸錯誤的情況下,要達成穩健的同步很困難,有時會為了效能而放寬防護措施。

網路檔案系統中的檔案鎖定也會出現類似的風險。SQLite 仰賴獨佔鎖定進行寫入作業,而這些鎖定已知在某些網路檔案系統中無法正確運作。這已導致資料庫損毀。當此類設計人員變更實作以符合更常見的用例時,可能會再次發生。

重點是網路檔案系統的同步和鎖定可靠性因實作和安裝而異。它所依賴的設計假設在應用程式測試的地方可能比在依賴它的地方更為真實。請自行承擔(以及您的客戶)風險。請參閱 如何損毀您的資料庫檔案

效能和可靠性問題

從上述圖表和討論中,很明顯地,在兩個通道之一中插入網路連結會降低效能(又稱「速度」)。考量 API 呼叫通道和檔案 I/O 通道之間的相對流量,會發現此類插入在 API 呼叫通道的效能影響較小。

考量可靠性影響較為容易,且結果較為明確:在 API 呼叫通道中插入網路連結有時也可能導致呼叫失敗。但如果 Client 應用程式已費心正確使用 SQL/SQLite 交易,此類失敗只會導致交易失敗並回滾,而不會危害資料的完整性。相反地,如果網路連結插入到檔案 I/O 通道,交易可能會失敗(如同 API 呼叫插入),但會額外導致遠端資料庫損毀。

這些網路不可靠性問題可以透過在回滾模式下使用 SQLite 完全或在可接受的程度內減輕。然而,SQLite 函式庫並未在跨網路場景中測試,這也不太可能。因此,使用遠端資料庫是由使用者自行承擔風險

建議

一般來說,如果資料透過網路與應用程式分開,您會想要使用客戶端/伺服器資料庫。這是因為資料庫引擎會作為資料庫流量上的頻寬降低過濾器。

如果資料透過網路與應用程式分開,您會希望低流量連結透過網路,而不是高流量連結。這表示資料庫引擎需要與資料庫本身在同一台機器上。像 PostgreSQL 這樣的客戶端/伺服器資料庫就是如此。SQLite 的不同之處在於資料庫引擎與應用程式在同一台機器上執行,這會迫使較高流量的連結在遠端資料庫場景中穿過網路。這通常會導致效能降低。

網路檔案系統不支援同時讀寫並同時保持資料庫一致的能力。因此,如果您有多個位於不同機器上的多個客戶端需要同時進行資料庫讀寫,您有以下選擇

1. 使用客戶端/伺服器資料庫引擎。PostgreSQL 是個絕佳的選擇。這的變體是

2. 在 WAL 模式 中主機 SQLite 資料庫,但所有讀寫都來自儲存資料庫檔案的同一台機器上的處理程序。實作一個在資料庫機器上執行的代理程式,用於傳遞來自遠端機器的讀寫要求。

3. 在 回滾模式 中使用 SQLite。這表示你可以有多個同時讀取器或一個寫入器,但不能同時有讀取器和寫入器。

應用程式程式設計人員應當意識到其應用程式的使用者可能會選擇使用遠端資料庫(如果他們可以的話)。除非已實施上述選項之一,或一次一個,否則會使用獨佔存取,程式設計人員應考慮封鎖該選項,除非可靠性不重要。

摘要

選擇適合你和你的客戶的技術。如果你的資料與你的應用程式在不同的機器上,那麼你應考慮使用客戶端/伺服器資料庫。SQLite 是為資料和應用程式共存于同一台機器上的情況而設計的。SQLite 仍可以在許多遠端資料庫情況下工作,但客戶端/伺服器解決方案通常在這種情況下會工作得更好。

此頁面最後修改於 2022-06-22 21:14:29 UTC