天天看點

高性能NoSQL一、關系型資料庫的特點二、常見的NoSQL方案

目錄

一、關系型資料庫的特點

二、常見的NoSQL方案

1.K-V存儲

2.文檔資料庫

3.列式資料庫

4.全文搜尋引擎

一、關系型資料庫的特點

關系型資料庫由于其強大的 SQL 功能和 ACID 的屬性,使得其在各式各樣的系統中得到了廣泛的應用。但世界上沒有什麼是"銀彈",關系型資料庫同樣也存在着一些問題,比如:

  • 關系資料庫存儲的是行記錄,無法存儲資料結構

以微網誌的關注關系為例,“我關注的人”是一個使用者 ID 清單,使用關系資料庫存儲隻能将清單拆成多行,然後再查詢出來組裝,無法直接存儲一個清單。

  • 關系資料庫的 schema 擴充很不友善

表結構 schema 是強限制,操作不存在的列會報錯,業務變化時擴充列也比較麻煩,需要執行 DDL語句修改,而且修改時可能會長時間鎖表。

  • 關系資料庫在大資料場景下 I/O 較高

如果對一些大量資料的表進行統計之類的運算,關系資料庫的 I/O 會很高,因為即使隻針對其中某一列進行運算,關系資料庫也會将整行資料從儲存設備讀入記憶體。

  • 關系資料庫的全文搜尋功能比較弱

關系資料庫的全文搜尋隻能使用 like 進行整表掃描比對,性能非常低,在網際網路這種搜尋複雜的場景下無法滿足業務要求。

網際網路需求場景複雜多變,疊代迅猛,針對上面的問題,誕生了很多NoSQL解決方案,遵循架構設計的“合适”原則,選擇合适自己業務需求的存儲方案才是最明智的。

NoSQL在解決上述部分問題的同時,本質上是犧牲ACID中的某些特性,這裡可以這樣了解:NoSQL 是 SQL 的一個有力補充,NoSQL != No SQL,而是 NoSQL = Not Only SQL。

二、常見的NoSQL方案

主要分為4類:

  • K-V存儲:解決關系型資料庫無法存儲資料結構的問題,比如:Redis。
  • 文檔資料庫:解決關系型資料庫強schema限制的問題,比如:MongoDB。
  • 列資料庫:解決關系型資料庫大資料場景下的I/O問題,比如:HBase。
  • 全文搜尋引擎:解決關系型資料庫的全文搜尋性能問題,比如:Elasticseach。

1.K-V存儲

全稱是Key-Value存儲,其中Key是資料的辨別,類似關系型資料庫中的主鍵,Value是具體的資料。

Redis 是 K-V 存儲的典型代表,它是一款開源(基于 BSD 許可)的高性能 K-V 緩存和存儲系統。Redis 的 Value 是具體的資料結構,包括 string、hash、list、set、sorted set、bitmap 和 hyperloglog,是以常常被稱為資料結構伺服器。

有些操作在關系型資料庫中會很麻煩,性能很低,比如redis中LPOP key 從隊列的左邊出隊一個元素,但在關系型資料庫中,需要多個操作:查詢出第一條資料、删除第一條資料、更新從第二條開始的所有資料的位置編号等(位置編号和ID不一樣)。

Redis 的缺點主要展現在并不支援完整的 ACID 事務,Redis 雖然提供事務功能,但 Redis 的事務和關系資料庫的事務不可同日而語,Redis 的事務隻能保證隔離性和一緻性(I 和 C),無法保證原子性和持久性(A 和 D)。

雖然 Redis 并沒有嚴格遵循 ACID 原則,但實際上大部分業務也不需要嚴格遵循 ACID 原則。以上面的微網誌關注操作為例,即使系統沒有将 A 加入 B 的粉絲清單,其實業務影響也非常小,是以我們在設計方案時,需要根據業務特性和要求來确定是否可以用 Redis,而不能因為 Redis 不遵循 ACID 原則就直接放棄。

基本指令參考:http://redis.cn/commands.html

2.文檔資料庫

文檔資料庫的出現主要是想解決關系型資料庫schema帶來的問題,文檔資料庫最大的特點就是no-schema,可以存儲和讀取任意的資料。常見的資料格式是JSON(BSON),因為JSON是自描述的,無須在使用前定義字段。

文檔資料庫的no-schema特點,給業務開發快速疊代開發帶來了很大的優勢。

1. 新增字段簡單

業務上增加新的字段,無須再像關系資料庫一樣要先執行 DDL 語句修改表結構,程式代碼直接讀寫即可。

2. 曆史資料不會出錯

對于曆史資料,即使沒有新增的字段,也不會導緻錯誤,隻會傳回空值,此時代碼進行相容處理即可。

3. 可以很容易存儲複雜資料

JSON 是一種強大的描述語言,能夠描述複雜的資料結構。比如我們在設計1個使用者管理系統時,僅使用者基本資訊,可能都需要設計多張表結構,但使用文檔資料庫,一個JSON就可以全部描述。因為使用 JSON 來描述資料,比使用關系型資料庫表來描述資料友善和容易得多,而且更加容易了解。

文檔資料庫的這個特點,特别适合電商和遊戲這類的業務場景。以電商為例,不同商品的屬性差異很大。例如,冰箱的屬性和筆記本電腦的屬性差異非常大。

即使是同類商品也有不同的屬性。例如,LCD 和 LED 顯示器,兩者有不同的參數名額。這種業務場景如果使用關系資料庫來存儲資料,就會很麻煩,而使用文檔資料庫,會簡單、友善許多,擴充新的屬性也更加容易。

文檔資料庫 no-schema 的特性帶來的這些優勢也是有代價的,最主要的代價就是不支援事務。例如,使用 MongoDB 來存儲商品庫存,系統建立訂單的時候首先需要減扣庫存,然後再建立訂單。這是一個事務操作,用關系資料庫來實作就很簡單,但如果用 MongoDB 來實作,就無法做到事務性。異常情況下可能出現庫存被扣減了,但訂單沒有建立的情況。是以某些對事務要求嚴格的業務場景是不能使用文檔資料庫的。

文檔資料庫另外一個缺點就是無法實作關系資料庫的 join 操作。例如,我們有一個使用者資訊表和一個訂單表,訂單表中有買家使用者 id。如果要查詢“購買了蘋果筆記本使用者中的女性使用者”,用關系資料庫來實作,一個簡單的 join 操作就搞定了;而用文檔資料庫是無法進行 join 查詢的,需要查兩次:一次查詢訂單表中購買了蘋果筆記本的使用者,然後再查詢這些使用者哪些是女性使用者。

3.列式資料庫

列式資料庫就是按照列來存儲資料的資料庫,與之對應的傳統關系資料庫被稱為“行式資料庫”,因為關系資料庫是按照行來存儲資料的。

關系資料庫行式存儲資料的優點:

  • 業務同時讀取多個列時效率高,因為這些列都是按行存儲在一起的,一次磁盤操作就能夠把一行資料中的各個列都讀取到記憶體中。
  • 能夠一次性完成對一行中的多個列的寫操作,保證了針對行資料寫操作的原子性和一緻性;否則如果采用列存儲,可能會出現某次寫操作,有的列成功了,有的列失敗了,導緻資料不一緻。

可以看出,行式存儲的優勢是在特定的業務場景下才能展現,如果不存在這樣的業務場景,那麼行式存儲的優勢也将不複存在,甚至成為劣勢,典型的場景就是海量資料進行統計。例如,計算某個城市體重超重的人員資料,實際上隻需要讀取每個人的體重這一列并進行統計即可,而行式存儲即使最終隻使用一列,也會将所有行資料都讀取出來。如果單行使用者資訊有 1KB,其中體重隻有 4 個位元組,行式存儲還是會将整行 1KB 資料全部讀取到記憶體中,這是明顯的浪費。而如果采用列式存儲,每個使用者隻需要讀取 4 位元組的體重資料即可,I/O 将大大減少。

除了節省 I/O,列式存儲還具備更高的存儲壓縮比,能夠節省更多的存儲空間。普通的行式資料庫一般壓縮率在 3:1 到 5:1 左右,而列式資料庫的壓縮率一般在 8:1 到 30:1 左右,因為單個列的資料相似度相比行來說更高,能夠達到更高的壓縮率。

同樣,如果場景發生變化,列式存儲的優勢又會變成劣勢。典型的場景是需要頻繁地更新多個列。因為列式存儲将不同列存儲在磁盤上不連續的空間,導緻更新多個列時磁盤是随機寫操作;而行式存儲時同一行多個列都存儲在連續的空間,一次磁盤寫操作就可以完成,列式存儲的随機寫效率要遠遠低于行式存儲的寫效率。此外,列式存儲高壓縮率在更新場景下也會成為劣勢,因為更新時需要将存儲資料解壓後更新,然後再壓縮,最後寫入磁盤。

基于上述列式存儲的優缺點,一般将列式存儲應用在離線的大資料分析和統計場景中,因為這種場景主要是針對部分列單列進行操作,且資料寫入後就無須再更新删除。(監控趨勢圖場景)

4.全文搜尋引擎

傳統關系型資料庫主要是根據索引來達到快速查詢的目的,但在全文搜尋的業務場景下,索引也不行,展現在:

  • 全文搜尋的條件可以随意排列組合,如果通過索引來滿足,則索引的數量會非常多。
  • 全文搜尋的模糊比對方式,索引無法滿足,隻能用 like 查詢,而 like 查詢是整表掃描,效率非常低。

1. 全文搜尋基本原理

全文搜尋引擎的技術原理被稱為“反向索引”(Inverted index),也常被稱為反向索引、置入檔案或反向檔案,是一種索引方法,其基本原理是建立單詞到文檔的索引。之是以被稱為“倒排”索引,是和“正排“索引相對的,“正排索引”的基本原理是建立文檔到單詞的索引。我們通過一個簡單的樣例來說明這兩種索引的差異。

假設我們有一個技術文章的網站,裡面收集了各種技術文章,使用者可以在網站浏覽或者搜尋文章。

正排索引示例:

高性能NoSQL一、關系型資料庫的特點二、常見的NoSQL方案

正排索引适用于根據文檔名稱來查詢文檔内容。例如,使用者在網站上單擊了“面向對象葵花寶典是什麼”,網站根據文章标題查詢文章的内容展示給使用者。 

 反向索引示例:

高性能NoSQL一、關系型資料庫的特點二、常見的NoSQL方案

 反向索引适用于根據關鍵詞來查詢文檔内容。例如,使用者隻是想看“設計”相關的文章,網站需要将文章内容中包含“設計”一詞的文章都搜尋出來展示給使用者。

2. 全文搜尋的使用方式

全文搜尋引擎的索引對象是單詞和文檔,而關系資料庫的索引對象是鍵和行,兩者的術語差異很大,不能簡單地等同起來。是以,為了讓全文搜尋引擎支援關系型資料的全文搜尋,需要做一些轉換操作,即将關系型資料轉換為文檔資料。

目前常用的轉換方式是将關系型資料按照對象的形式轉換為 JSON 文檔,然後将 JSON 文檔輸入全文搜尋引擎進行索引。

全文搜尋引擎能夠基于 JSON 文檔建立全文索引,然後快速進行全文搜尋。以 Elasticsearch 為例,其索引基本原理如下:

Elastcisearch 是分布式的文檔存儲方式。它能存儲和檢索複雜的資料結構——序列化成為 JSON 文檔——以實時的方式。在 Elasticsearch 中,每個字段的所有資料都是預設被索引的。即每個字段都有為了快速檢索設定的專用反向索引。而且,不像其他多數的資料庫,它能在相同的查詢中使用所有反向索引,并以驚人的速度傳回結果。

ES官方文檔:https://www.elastic.co/guide/cn/elasticsearch/guide/current/data-in-data-out.html

參考:李運華老師《從0開始學架構》(極客時間)