用于 JavaScript 應(yīng)用程序的五大嵌入式數(shù)據(jù)庫(kù)
我們習(xí)慣于將數(shù)據(jù)庫(kù)視為巨大的存儲(chǔ)平臺(tái),我們可以在其中存儲(chǔ)我們需要的所有數(shù)據(jù),然后通過(guò)某種形式的查詢語(yǔ)言檢索它。擴(kuò)展這些數(shù)據(jù)庫(kù),保持信息的一致性和容錯(cuò)性本身就是一個(gè)挑戰(zhàn)。但是,當(dāng)我們的數(shù)據(jù)需求非常小時(shí)會(huì)發(fā)生什么?
當(dāng)RedShift、BigQuery、甚至MySQL對(duì)我們微小的數(shù)據(jù)需求來(lái)說(shuō)是一個(gè)太大的解決方案時(shí),會(huì)發(fā)生什么?好吧,事實(shí)證明,有一個(gè)應(yīng)用程序可以解決這個(gè)問(wèn)題。事實(shí)上,有很多選擇,所以在這里,我將介紹5大嵌入式數(shù)據(jù)庫(kù),以滿足你的微小數(shù)據(jù)需求。
什么是嵌入式數(shù)據(jù)庫(kù)?
當(dāng)我們讀到“嵌入式”這個(gè)詞時(shí),90% 的人會(huì)得出結(jié)論,我說(shuō)的是物聯(lián)網(wǎng)或移動(dòng)設(shè)備。但這種情況并非如此。
反正不是唯一的情況。誠(chéng)然,這些系統(tǒng)的資源非常有限,這使得大多數(shù)傳統(tǒng)的數(shù)據(jù)庫(kù)系統(tǒng)很難配置和安裝在那里。
但是對(duì)于小型數(shù)據(jù)庫(kù)還有其他的用例,也就是將它們嵌入到軟件產(chǎn)品中。例如,想象一下通過(guò)您的IDE在一個(gè)大型代碼存儲(chǔ)庫(kù)上進(jìn)行搜索。IDE可以嵌入一個(gè)反向索引數(shù)據(jù)庫(kù),允許您搜索關(guān)鍵字并快速獲取相關(guān)文件的參考?;蛘咴谀钕矚g的電子郵件桌面客戶端上執(zhí)行搜索時(shí),該客戶端很可能也有一個(gè)嵌入式數(shù)據(jù)庫(kù)。所有的電子郵件都存儲(chǔ)在那里并被編入索引,所以你可以快速輕松地訪問(wèn)這些信息。
到目前為止,您可能已經(jīng)了解了嵌入式數(shù)據(jù)庫(kù)的另一個(gè)巨大好處,即它們不需要與網(wǎng)絡(luò)調(diào)用進(jìn)行交互。與標(biāo)準(zhǔn)數(shù)據(jù)庫(kù)相比,這是一個(gè)巨大的性能提升。從本質(zhì)上講,在正常的開(kāi)發(fā)中,你希望把數(shù)據(jù)庫(kù)放在自己的服務(wù)器(或服務(wù)器集群)上,這樣它的資源消耗就不會(huì)影響到你架構(gòu)中的其他組件,而對(duì)于嵌入式數(shù)據(jù)庫(kù),你希望它們盡可能地靠近客戶端代碼。這就減少了它們之間的延遲,避免了對(duì)通信渠道(即網(wǎng)絡(luò))的依賴(lài)。
現(xiàn)在,這個(gè)想法可以有多種形式,從使用 JSON 文件作為主存儲(chǔ)的快速內(nèi)存數(shù)據(jù)庫(kù),到可以使用類(lèi)似 SQL 的語(yǔ)言進(jìn)行查詢的高效微型關(guān)系數(shù)據(jù)庫(kù)。
讓我們來(lái)看看5種選擇。
LowDB
讓我們從簡(jiǎn)單的開(kāi)始,LowDB 是一個(gè)小型的內(nèi)存數(shù)據(jù)庫(kù)。這是一個(gè)非常基本的解決方案,但它解決了一個(gè)非常簡(jiǎn)單的用例:需要從基于 JavaScript 的項(xiàng)目中存儲(chǔ)和訪問(wèn)類(lèi)似 JSON 的結(jié)構(gòu)(即文檔)。
LowDB的一個(gè)主要好處是它可以從JavaScript中使用,也就是說(shuō):它可以用于后端、桌面和瀏覽器代碼。
在后端,你可以將它與 Node.js 一起使用,對(duì)于桌面開(kāi)發(fā),它可以集成到一個(gè) Electron 項(xiàng)目中,最后,它也可以通過(guò)其集成的 JS 運(yùn)行時(shí)直接在瀏覽器上運(yùn)行。
這個(gè)數(shù)據(jù)庫(kù)提供的API也相當(dāng)簡(jiǎn)單和簡(jiǎn)約,它不提供任何開(kāi)箱即用的搜索功能。它只限于將一個(gè)JSON文件的數(shù)據(jù)加載到一個(gè)數(shù)組變量中,讓你(用戶)以你認(rèn)為合適的方式找到你要找的東西。
例如,看看下面的代碼:
- import { LowSync, JSONFileSync } from 'lowdb'
- const title = "This is a test"
- const adapter = new JSONFileSync('file.json')
- const db = new LowSync(adapter)
- db.read() //將文件內(nèi)容加載到內(nèi)存中
- db.data ||= { posts: [] } //默認(rèn)值
- db.data.posts.push({ title }) //將數(shù)據(jù)添加到“集合”中
- db.write() //通過(guò)將數(shù)據(jù)保存到JSON文件來(lái)持久化數(shù)據(jù)
- //任何類(lèi)似于查找的操作都由用戶自己來(lái)完成
- let record = db.data.posts.find( p => p.title == "Hello world")
- if(!record) {
- console.log("No data found!")
- } else {
- console.log("== Record found ==")
- console.log(record)
- }
正如你所看到的,這里有趣的部分不是默認(rèn)的行為,而是我正在使用一個(gè)叫做 JSONFileSync 的適配器。我可以很容易地使用一個(gè)由我創(chuàng)建的自定義的適配器,這才是這個(gè)數(shù)據(jù)庫(kù)的真正強(qiáng)項(xiàng)。
它具有高度的可擴(kuò)展性并與 TypeScript 兼容,后者為數(shù)據(jù)存儲(chǔ)提供了類(lèi)似于模式的行為(即不允許添加不遵循預(yù)設(shè)模式的數(shù)據(jù))。
如果混合使用這兩種選項(xiàng),那么LowDB將成為處理本地類(lèi)似json的數(shù)據(jù)的有趣選項(xiàng)。
LevelDB
LevelDB 是由 Google 構(gòu)建的開(kāi)源鍵值數(shù)據(jù)庫(kù)。它是一種超快但非常有限的鍵值存儲(chǔ),其中數(shù)據(jù)按開(kāi)箱即用的鍵排序存儲(chǔ)。
它只有三個(gè)基本操作:Put、Get 和 Delete,沒(méi)有別的——如果你仔細(xì)想想,有點(diǎn)像 LowDB。
和LowDB一樣,它沒(méi)有一個(gè)客戶端-服務(wù)器封裝器,這意味著沒(méi)有辦法從任何語(yǔ)言與它通信,如果你想使用它,你必須使用C/C++庫(kù),如果你想要一個(gè)類(lèi)似服務(wù)器的行為,你必須自己封裝它。
就像我們?cè)谶@里要介紹的大多數(shù)案例一樣,功能非?;荆?yàn)樗鼈兒w了一個(gè)非常簡(jiǎn)單但需要的用例:在靠近代碼的地方存儲(chǔ)數(shù)據(jù)并快速訪問(wèn)。
該數(shù)據(jù)庫(kù)的存儲(chǔ)架構(gòu)是圍繞著日志結(jié)構(gòu)的合并樹(shù)(LSM),這意味著它被優(yōu)化為大型的連續(xù)寫(xiě)操作,而不是小型的隨機(jī)操作。
LevelDB 的一個(gè)主要限制是,一旦打開(kāi),它就會(huì)在存儲(chǔ)上獲得系統(tǒng)級(jí)鎖,這意味著當(dāng)時(shí)只有一個(gè)進(jìn)程可以與數(shù)據(jù)庫(kù)交互。當(dāng)然,您可以使用多個(gè)線程來(lái)并行化該進(jìn)程中的某些操作。但這就是它的范圍。
有趣的是,這個(gè)數(shù)據(jù)庫(kù)被用作Chrome的IndexedDB的后臺(tái)數(shù)據(jù)庫(kù),顯然Minecraft Bedrock版也使用它來(lái)存儲(chǔ)一些分塊和實(shí)體數(shù)據(jù)(盡管從外觀上看,他們使用的是谷歌實(shí)現(xiàn)的略微修改的版本)。
Raima 數(shù)據(jù)庫(kù)管理器
我之前提到過(guò)物聯(lián)網(wǎng)不是嗎? Raima 是速度最快的數(shù)據(jù)庫(kù)管理器之一,專(zhuān)門(mén)針對(duì)在資源受限的物聯(lián)網(wǎng)設(shè)備中運(yùn)行進(jìn)行了優(yōu)化。
資源受限的環(huán)境是什么意思? Raima 只需要 350kb 的 RAM 即可運(yùn)行。這就是我可以極簡(jiǎn)的資源利用。
該解決方案的主要特點(diǎn)之一是它完全支持 SQL,這一點(diǎn)在之前的任何解決方案中都沒(méi)有出現(xiàn)。它提供了一個(gè)關(guān)系數(shù)據(jù)模型,并允許您使用 SQL 語(yǔ)言進(jìn)行查詢。
與 LevelDB 不同的是,它還允許通過(guò)客戶端-服務(wù)器架構(gòu)對(duì)數(shù)據(jù)庫(kù)進(jìn)行多進(jìn)程訪問(wèn)(即這種架構(gòu)允許您比其他架構(gòu)更遠(yuǎn)離源代碼)。如果您決定采用接近源代碼的嵌入式應(yīng)用程序,您還可以使用多線程來(lái)支持對(duì)多個(gè)數(shù)據(jù)庫(kù)的并發(fā)訪問(wèn)。
Raima的靈活性允許你從傳統(tǒng)的客戶-服務(wù)器方法到最有效的(當(dāng)然也是有限的)使用案例,即由單個(gè)客戶消費(fèi)的單一內(nèi)存數(shù)據(jù)庫(kù)。但是,嘿,這是一個(gè)非常有效的嵌入式數(shù)據(jù)庫(kù)的使用案例。
這種靈活性使它成為一種非常通用的解決方案。當(dāng)然,每種部署模式都有自己的優(yōu)點(diǎn)和限制,但是也會(huì)針對(duì)特定的用例進(jìn)行優(yōu)化。因此,請(qǐng)確保您選擇了正確的一個(gè),并從這個(gè)數(shù)據(jù)庫(kù)中獲得最大的好處。
Apache Derby
如果你正在尋找另一個(gè)非常小的、類(lèi)似SQL的數(shù)據(jù)庫(kù),Apache Derby很可能是你正在尋找的東西。
Derby完全是用JAVA編寫(xiě)的,當(dāng)它聲稱(chēng)只有3.5Mb的內(nèi)存占用時(shí),也損失了一點(diǎn)信譽(yù)。畢竟,如果沒(méi)有在主機(jī)系統(tǒng)上安裝JVM,您就不能運(yùn)行或使用它。
也就是說(shuō),如果您的用例允許使用JVM,那么很好,您可以繼續(xù)考慮Derby,否則您可能希望使用更本地的解決方案,如LevelDb或Raima。
但正如我所說(shuō),如果您已經(jīng)在從事 JAVA 項(xiàng)目并且需要集成一個(gè)小型、可靠、基于 SQL 的數(shù)據(jù)庫(kù),那么 Derby 絕對(duì)是一個(gè)潛在的候選者。
它帶有一個(gè)集成的 JDBC 驅(qū)動(dòng)程序,因此不需要額外的依賴(lài)項(xiàng)。它既可以在 JAVA 應(yīng)用程序內(nèi)的嵌入式模式下工作,也可以作為獨(dú)立服務(wù)器運(yùn)行,允許多個(gè)應(yīng)用程序同時(shí)與其交互(類(lèi)似于 Raima 的工作方式,但沒(méi)有許多變體)。
說(shuō)實(shí)話,這個(gè)項(xiàng)目最大的缺點(diǎn)是它的文檔。它可能是JAVA社區(qū)的一個(gè)標(biāo)準(zhǔn),但它對(duì)用戶并不友好,大部分的官方鏈接都把讀者送到一個(gè)私人的匯合頁(yè)面。這里的許多其他解決方案在涉及到文檔時(shí)提供了更順暢的體驗(yàn),這也有助于他們產(chǎn)品的采用。
solidDB
最后,solidDB提供了一個(gè)非常有趣的內(nèi)存關(guān)系數(shù)據(jù)庫(kù),它同時(shí)還可以增強(qiáng)一個(gè)持久性模型。聲稱(chēng)它可以保持兩個(gè)數(shù)據(jù)存儲(chǔ)選項(xiàng)實(shí)時(shí)同步。這可不是個(gè)小要求。
本質(zhì)上就像這里列出的其他解決方案一樣,solidDB 可以通過(guò) ODBC 或 JDBC 訪問(wèn),這允許 JAVA 和 C 應(yīng)用程序通過(guò) SQL 與其交互。
也像這里列出的一些解決方案一樣,它可以以多種模式部署:
- 高可用性模式。這涉及具有重復(fù)數(shù)據(jù)的多個(gè)服務(wù)器。當(dāng)然,這種模式在我們考慮的用例中并不多。
- 共享內(nèi)存訪問(wèn)。這個(gè)方案非常有趣,因?yàn)樗粌H將數(shù)據(jù)保存在內(nèi)存中(就像已經(jīng)列出的其他解決方案一樣),而且還允許多個(gè)應(yīng)用程序訪問(wèn)該內(nèi)存(因此有共享內(nèi)存部分)。當(dāng)然,對(duì)共享內(nèi)存的直接訪問(wèn)需要由同一節(jié)點(diǎn)內(nèi)的應(yīng)用程序完成,但是,它還允許基于 JDBC/ODBC 從外部節(jié)點(diǎn)訪問(wèn)相同的數(shù)據(jù)。將共享內(nèi)存轉(zhuǎn)變?yōu)榫哂型獠吭L問(wèn)權(quán)限的內(nèi)存數(shù)據(jù)庫(kù)。
由于訪問(wèn)數(shù)據(jù)的速度快如閃電,思科、阿爾卡特、諾基亞和西門(mén)子等多家知名企業(yè)聲稱(chēng)將使用該數(shù)據(jù)庫(kù)進(jìn)行關(guān)鍵任務(wù)操作。
鑒于其所有的部署模式、廣泛的文檔和高需求的客戶名單,我可以看到這是這個(gè)名單上最可靠、最穩(wěn)定、最快速的嵌入式數(shù)據(jù)庫(kù)之一。
嵌入式數(shù)據(jù)庫(kù)是為了處理一個(gè)非常具體的用例,或者通過(guò)提供快速可靠的數(shù)據(jù)存儲(chǔ)和最小的延遲,或者通過(guò)允許快速安全地訪問(wèn)數(shù)據(jù)。這里列出的解決方案通過(guò)不同的手段實(shí)現(xiàn)這些目標(biāo),這取決于你和你的特定環(huán)境,以決定哪一個(gè)是適合你的。