爲什麼要用 NoSQL

轉自:悟空聊架構

1 MongoDB 和 MySQL

面試官:看你的簡歷上寫了 MongoDB,說下 MongoDB 和 MySQL 的區別吧。

其實對於這個問題,我事先有準備,簡歷上寫了 MongoDB,面試官肯定會問 MongoDB 和 MySQL 的區別。

MongoDB 是非關係型的數據庫(NoSQL),屬於文檔型數據庫,文檔數據庫就是爲了解決關係數據庫帶來的問題。最大的特點是 no-schema,可以存儲和讀取任意的數據。

存儲的數據格式就是 JSON(或者 BSON)。JSON 格式我們都比較熟悉,比如 Rest API 請求返回的 Response 就是 JSON 格式的。JSON 格式的數據和 XML 格式的區別是 JSON 更簡單,沒有那麼多的標籤來定義字段名。也就是說 JSON 是自描述的。另外 JSON 格式存進 MongoDB 中後,即使讀取一個 JSON 中不存在的字段也不會導致 SQL 那樣的語法錯誤。

1.1 MongoDB 優點

由於文檔數據庫具有 no-schema 特性,用起來有以下幾個明顯的好處。

(1)新增的字段不會出錯。

比如用戶表增加一個暱稱的字段,不需要像關係型數據那樣執行更新表結構的語句。我們直接查詢這條文檔出來就可以看到新增的字段了。

(2)查詢歷史數據不會出錯。

上面提到新增了一個暱稱字段,但是歷史數據中是沒有這個字段,如果查詢歷史數據,則返回的數據中不會有這個字段,雖然查詢不會報錯,但是取值時,會返回 null。如果業務代碼中用到了暱稱字段,則需要做兼容性處理。

(3)輕鬆存儲複雜數據。

因爲是用 JSON 存儲,而 JSON 又可以表示複雜的數據結構,比如字段可以存數組,字段可以嵌套字段,而且可以存很多字段。換做 MySQL,則需要設計幾張表來存。MongoDB 存數據的結構,特別適合電商這種業務場景,比如兩種不同的商品,屬性差別就很大,但是用 JSON 存就可以輕鬆應對。

但是文檔數據庫有什麼缺點呢 ?

1.2 MongoDB 缺點

(1)目前 4.0 以前不支持多文檔事務

結合 MongoDB 文檔模型內嵌數組、文檔的支持,目前的單文檔事務能滿足絕大部分開發者的需求。爲了讓 MongoDB 能適應更多的應用場景,讓開發變得更簡單,MongoDB 4.0 將支持複製集內部跨一或多個集合的多文檔事務,保證針對多個文檔的更新的原子性。而在未來的 MongoDB 4.2 版本,還會支持分片集羣的分佈式事務。

我們來看下 MongoDB 不同版本支持的功能:

MongoDB 的事務接口非常簡單,開發者只需要將需要保證原子性的更新序列放到一個 session 的 開始事務 與提交事務之間即可。下面是 Java 使用 MongoDB 事務的示例代碼:

try (ClientSession clientSession = client.startSession()) {
    clientSession.startTransaction();
    try {
        collection.insertOne(clientSession, docOne);
        collection.insertOne(clientSession, docTwo);
        clientSession.commitTransaction();
    } catch (Exception e) {
    clientSession.abortTransaction();
    }
}

(2) 不支持關聯查詢

我們都知道 MySQL 是支持關聯查詢的,也就是可以執行 Join 操作。比如有兩張表:用戶表和訂單表,訂單表中有用戶的 id,且性別只存在用戶表中。如果想購買了手機的男性用戶,用關聯查詢,一步就能搞定。但是如果用 MongoDB,則需要查兩次,先查詢訂單表中購買手機的用戶,再查詢這些用戶中哪些是男性。

2 關係型數據的缺點

面試官:這個項目爲什麼不用關係型數據庫?關係型數據庫有哪些缺點?

順着面試官的思路,可以知道面試官想問的是關係型數據庫有哪些不足之處。

關係型數據庫的不足之處:

(1)存儲的是行記錄

不能存儲數組、嵌套字段等格式的數據。

(2)擴展表結構不方便

操作不存在的列會報錯,而增加列又需要執行 SQL 語句纔行。而且修改時需要特別注意,因爲更新表時會長時間鎖表,這對線上環境可能造成嚴重影響。

(3)佔用內存高

關係型數據庫在對大量數據的表進行統計之類的運算時,佔用內存會很高,因爲它即使只針對某一列進行運算,也會將整行數據從存儲設備讀入內存。

(4)全文搜索性能差

類似於 MySQL 的關係型數據庫,只能用 like 進行整表掃描的匹配,效率很低。現如今,有很多場景需要支持模糊匹配,而且必須支持高效查找。比如查詢包含關鍵字的日誌信息,又或者是根據某個商品關鍵字查詢商品列表。

針對以上的不足之處,我們這個項目用了兩種非關係型的數據存儲方案:MongoDB 和 ElasticSearch。

3 NoSQL 的分類和特點

面試官:你知道的有哪些 NoSQL 數據庫?分別有什麼特點?

NoSQL(NoSQL = Not Only SQL),意即 "不僅僅是 SQL"。

我知道的有 Redis、MongoDB、HBase、全文搜索引擎 Elasticsearch。他們是不同的非關係型存儲方案。

3.1 K-V 存儲型

比如 Redis,它可以用 K-V 鍵值對的方式來存儲數據,而存儲的值可以有好幾種格式,如 string、hash、list、set、bitmap 等。

3.2 文檔存儲型

比如 MongoDB,存儲的 JSON 格式的文檔,解決了關係型數據庫的表約束的問題,比如查詢不存在的字段會報錯。另外也解決了部分存儲格式的問題,因 JSON 可以表示數組,還可以嵌套字段存儲。

3.3 列式存儲型

比如 HBase,按照列來存儲數據,解決了大數據場景下的 I/O 問題。

關係型數據庫按照行來存儲數據,所以稱作行式數據庫。按照行來存儲有以下優勢:

3.4 全文搜索引擎

這個用到的最多的地方就是日誌系統,還有搜索商品信息等類似場景。如下圖所示的電商網站。

我們項目中用到日誌搜索就是利用 ELK。

Elasticsearch 就是 ELK 中的 E。Elasticsearch 就是全文搜索引擎,注意:他是一種 NoSQL 方案,並不是 NoSQL 數據庫。

Logstash 就是 ELK 中的 L。它是 Elastic Stack 的核心產品之一,可用來對數據進行聚合和處理,並將數據發送到 Elasticsearch。Logstash 是一個開源的服務器端數據處理管道,允許您在將數據索引到 Elasticsearch 之前同時從多個來源採集數據,並對數據進行充實和轉換。

Kibana 就是 ELK 中的  K。是一款適用於 Elasticsearch 的數據可視化和管理工具,可以提供實時的直方圖、線性圖等。

如下圖所示:

假如數據庫有如下電影記錄:

1 - 大話西遊

3 - 解析大話西遊

4 - 西遊降魔外傳

5 - 夢幻西遊獨家解析

分詞,將整句分拆爲單詞: gCnODu

**檢索:**獨家大話西遊

將 獨家大話西遊 拆分成 獨家大話西遊。

ES 中 A、B、G 記錄 都有這三個詞的其中一種, 所以 1,2, 3,4, 5 號記錄都有相關的詞被命中。

1 號記錄命中 2 次, A、B 中都有 (命中 2 次) ,而且 1 號記錄有 2 個詞,相關性得分:2 次 / 2 個詞 = 1

2 號記錄命中 2 個詞 A、B 中的都有 (命中 2 次) ,而且 2 號記錄有 2 個詞,相關性得分:2 次 / 3 個詞 = 0.67

3 號記錄命中 2 個詞 A、B 中的都有 (命中 2 次) ,而且 3 號記錄有 2 個詞,相關性得分:2 次 / 3 個詞 = 0.67

4 號記錄命中 2 個詞 A 中有 (命中 1 次) ,而且 4 號記錄有 3 個詞,相關性得分:1 次 / 3 個詞 = 0.33

5 號記錄命中 2 個詞 A 中有 (命中 2 次) ,而且 4 號記錄有 4 個詞,相關性得分:2 次 / 4 個詞 = 0.5

所以檢索出來的記錄順序如下:

1 - 大話西遊 (相關性得分:1)

2 - 大話西遊外傳 (相關性得分:0.67)

3 - 解析大話西遊 (相關性得分:0.67)

5 - 夢幻西遊獨家解析 (相關性得分:0.5)

4 - 西遊降魔 (相關性得分:0.33)

Elasticsearch 與 MySQL 的對比: LS7hvx

另外的 NoSQL 還有圖形數據庫,這裏不做展開。

4. 關係型和 NoSQL 怎麼選?

面試官:關係型和 NoSQL 怎麼選呢?

關係型和 NoSQL 數據庫的選型,考慮幾個指標,數據量、併發量、實時性、一致性要求、讀寫分離、安全性、運維性等。根據這些指標,軟件系統可分成幾類。

面試結果:技術負責人覺得還行,但 HR 今天不在,等 HR 下次通知吧。後續就沒通知了。完。

參考資料: 

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/9khC2Zhy1ozqCsWN_J3unw