掃二維碼與項目經(jīng)理溝通
我們在微信上24小時期待你的聲音
解答本文疑問/技術(shù)咨詢/運營咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流
工作中總是遇到數(shù)據(jù)存儲相關(guān)的 Bug 工單,新需求開發(fā)設(shè)計中也多多少少會有數(shù)據(jù)模型設(shè)計和存儲相關(guān)的問題。經(jīng)過幾次存儲方案設(shè)計選型和討論后發(fā)現(xiàn)需要有更全面的思考框架。

創(chuàng)新互聯(lián)建站是一家集網(wǎng)站建設(shè),路北企業(yè)網(wǎng)站建設(shè),路北品牌網(wǎng)站建設(shè),網(wǎng)站定制,路北網(wǎng)站建設(shè)報價,網(wǎng)絡(luò)營銷,網(wǎng)絡(luò)優(yōu)化,路北網(wǎng)站推廣為一體的創(chuàng)新建站企業(yè),幫助傳統(tǒng)企業(yè)提升企業(yè)形象加強企業(yè)競爭力??沙浞譂M足這一群體相比中小企業(yè)更為豐富、高端、多元的互聯(lián)網(wǎng)需求。同時我們時刻保持專業(yè)、時尚、前沿,時刻以成就客戶成長自我,堅持不斷學(xué)習(xí)、思考、沉淀、凈化自己,讓我們?yōu)楦嗟钠髽I(yè)打造出實用型網(wǎng)站。
故寫了這篇文章,拋出我的觀察和思考,希望日后可以將一些更先進 (合適) 的技術(shù)引入公司業(yè)務(wù),助力業(yè)務(wù)發(fā)展。
存儲選型的目的還是為了我們的使用場景和用戶服務(wù),因此在選型前需要回答一些業(yè)務(wù)指標(biāo) & 技術(shù)指標(biāo)方面的問題,以便于我們清楚存儲選型的應(yīng)用環(huán)境。
數(shù)據(jù)庫的分類方式非常多樣,因參考維度不同而存在較大差異,下面是常見的一些分類。
先拿我們最熟悉的關(guān)系數(shù)據(jù)庫來說,它的優(yōu)點非常多,我們選用關(guān)系數(shù)據(jù)庫的理由可簡單概括為以下幾點:
可由二維表結(jié)構(gòu)來邏輯表達,相對網(wǎng)狀、層次等其他模型更加容易被理解。嚴(yán)格遵循數(shù)據(jù)格式與長度規(guī)范,數(shù)據(jù)以行為單位,一行數(shù)據(jù)表示一個實體信息,每一行數(shù)據(jù)的屬性都是相同的。
支持 ACID 特性,可以維護數(shù)據(jù)之間的一致性,這是使用關(guān)系數(shù)據(jù)庫非常重要的一個理由。
通用的 SQL 語言使得操作關(guān)系型數(shù)據(jù)庫非常方便,支持 join 等復(fù)雜查詢,Sql + 二維關(guān)系是關(guān)系型數(shù)據(jù)庫最無可比擬的優(yōu)點,這種易用性非常貼近開發(fā)者。
數(shù)據(jù)持久化到磁盤,沒有丟失數(shù)據(jù)風(fēng)險。
最常用的關(guān)系型數(shù)據(jù)庫產(chǎn)品 MySql、Oracle 服務(wù)器性能卓越,服務(wù)穩(wěn)定,通常很少出現(xiàn)宕機異常。
然而,在享受關(guān)系數(shù)據(jù)庫帶來的便利的同時,我們也不得不面臨很多麻煩的問題:
數(shù)據(jù)按行存儲,即使只針對某一列進行運算,也會將整行數(shù)據(jù)從存儲設(shè)備中讀入內(nèi)存,導(dǎo)致 IO 較高。寫入更新頻繁的情況下,數(shù)據(jù)庫往往會出現(xiàn) CPU 飆高、Sql 執(zhí)行慢、客戶端報數(shù)據(jù)庫連接池不夠等異常情況,且性能瓶頸通過加 CPU、換固態(tài)硬盤、繼續(xù)買服務(wù)器加數(shù)據(jù)庫做分庫等方式處理 ROI 不高,受限于其本身的特點,可能花了很多錢都未必能達到想要的效果。因此例如萬人秒殺這種場景,我們絕對不可能通過數(shù)據(jù)庫直接去扣減庫存,需要做好流量漏斗。
為維護數(shù)據(jù)一致性付出的代價大
數(shù)據(jù)一致性是關(guān)系型數(shù)據(jù)庫的核心,但是同樣為了維護數(shù)據(jù)一致性的代價也非常大。SQL 標(biāo)準(zhǔn)為事務(wù)定義了不同的隔離級別,從低到高依次是讀未提交、讀已提交、可重復(fù)度、串行化,事務(wù)隔離級別越低,可能導(dǎo)致的并發(fā)異常越多,但是能提供的并發(fā)能力越強。那么為了保證事務(wù)一致性,數(shù)據(jù)庫就需要提供并發(fā)控制與故障恢復(fù)兩種技術(shù),前者用于減少并發(fā)異常,后者可以在系統(tǒng)異常的時候保證事務(wù)與數(shù)據(jù)庫狀態(tài)不會被破壞。對于并發(fā)控制,其核心思想就是加鎖,無論是樂觀鎖還是悲觀鎖,只要提供的隔離級別越高,那么讀寫性能必然會受影響。
為了提供豐富的查詢能力,通常熱點表都會有多個二級索引,一旦有了二級索引,數(shù)據(jù)的新增必然伴隨著所有二級索引的新增,數(shù)據(jù)的更新也必然伴隨著所有二級索引的更新,這不可避免地降低了關(guān)系型數(shù)據(jù)庫的讀寫能力,且索引越多讀寫能力越差。除了數(shù)據(jù)文件不可避免地占空間外,索引占的空間其實也并不少。
隨著業(yè)務(wù)規(guī)模擴大,一種方式是對數(shù)據(jù)庫做分庫,做了分庫之后,數(shù)據(jù)遷移(1 個庫的數(shù)據(jù)按照一定規(guī)則打到 2 個庫中)、跨庫 join、分布式事務(wù)處理都是需要考慮的問題,尤其是分布式事務(wù)處理,業(yè)界當(dāng)前都沒有特別好的解決方案。
例如 like “% 新年快樂 %”,只能搜索到 “新年快樂,愛大家”,無法搜索到 “新年真是太快樂了,愛大家” 這樣的文本,即不具備分詞能力,且 like 查詢在 “% 新年快樂” 這樣的搜索條件下,無法命中索引,將會導(dǎo)致查詢效率大大降低。
由于數(shù)據(jù)庫存儲的是結(jié)構(gòu)化數(shù)據(jù),因此表結(jié)構(gòu) schema 是固定的,擴展不方便,如果需要修改表結(jié)構(gòu),需要執(zhí)行 DDL(data definition language)語句修改,修改期間會導(dǎo)致鎖表,部分服務(wù)不可用。
如上文所分析的,關(guān)系型數(shù)據(jù)庫優(yōu)點明顯,缺點同樣不能忽視,因此通常在企業(yè)規(guī)模不斷擴大的情況下,不會一味指望通過增強數(shù)據(jù)庫的能力來解決數(shù)據(jù)存儲問題,而是會引入其他存儲,也就是我們說的 NoSql。
NoSql 的全稱為 Not Only SQL,泛指非關(guān)系型數(shù)據(jù)庫,是對關(guān)系型數(shù)據(jù)庫的一種補充,特別注意補充這兩個字,這意味著 NoSql 與關(guān)系型數(shù)據(jù)庫并不是對立關(guān)系,二者各有優(yōu)劣,取長補短,在合適的場景下選擇合適的存儲引擎才是正確的做法。
下面看一下常用的 NoSql 及他們的代表產(chǎn)品,并對每種 NoSql 的優(yōu)缺點和適用場景做一下分析,便于熟悉每種 NoSql 的特點,方便技術(shù)選型。
KV 型 NoSql 顧名思義就是以鍵值對形式存儲的非關(guān)系型數(shù)據(jù)庫,是最常見的一種 NoSql。Redis、MemCache 是其中的代表,Redis 又是 KV 型 NoSql 中應(yīng)用最廣泛的 NoSql,KV 型數(shù)據(jù)庫以 Redis 為例,最大的優(yōu)點總結(jié)下來主要有兩點:
所以說,KV 型 NoSql 最大的優(yōu)點就是高性能,利用 Redis 自帶的 BenchMark 做基準(zhǔn)測試,TPS 可達到 10 萬的級別,性能非常強勁。同樣的 Redis 也有所有 KV 型 NoSql 都有的比較明顯的缺點:
綜上所述,KV 型 NoSql 最合適的場景就是緩存的場景:
針對那些讀遠多于寫的數(shù)據(jù),引入一層緩存,每次讀從緩存中讀取,緩存中讀取不到,再去數(shù)據(jù)庫中取,取完之后再寫入到緩存,對數(shù)據(jù)做好失效機制通常就沒有大問題了。通常來說,緩存是性能優(yōu)化的第一選擇也是見效最明顯的方案。
傳統(tǒng)關(guān)系型數(shù)據(jù)庫主要通過索引來達到快速查詢的目的,但是在全文搜索的場景下,索引是無能為力的,like 查詢無法滿足所有模糊匹配需求,使用限制太大且使用不當(dāng)容易引起慢查詢問題,搜索型 NoSql 的誕生正是為了解決關(guān)系型數(shù)據(jù)庫全文搜索能力較弱的問題,ElasticSearch 是搜索型 NoSql 的代表產(chǎn)品。
全文搜索的原理是倒排索引,我們看一下什么是倒排索引,它是關(guān)鍵字 –> 文檔的映射,舉例來說,現(xiàn)在這里有四個短句:
搜索引擎會根據(jù)一定的分詞規(guī)則將一句話切成多個關(guān)鍵字,并以關(guān)鍵字的維度維護關(guān)鍵字在每個文本中的出現(xiàn)次數(shù)。這樣下次搜索“Tom”關(guān)鍵字的時候,由于 Tom 這個詞語在“Tom is Tom”、“Tom is my friend”、“Tom is Betty’s husband” 三句話中都出現(xiàn)過,因此這三條記錄都會被檢索出來,而且由于”Tom is Tom” 這句話中”Tom” 出現(xiàn)了 2 次,因此這條記錄對”Tom” 這個單詞的匹配度最高,最先展示。這就是搜索引擎倒排索引的基本原理,假設(shè)某個關(guān)鍵字在某個文檔中出現(xiàn),那么倒排索引中有兩部分內(nèi)容:
相對應(yīng)的,我們搜索”Betty Tom” 這兩個詞語也是一樣,搜索引擎將”Betty Tom” 切分為”Tom”、”Betty” 兩個單詞,根據(jù)開發(fā)者指定的滿足率,比如滿足率 = 50%,那么只要記錄中出現(xiàn)了兩個單詞之一的記錄都會被檢索出來,再按照匹配度進行展示。
搜索型 NoSql 以 ElasticSearch 為例,它的優(yōu)點為:
1)支持分詞場景、全文搜索,這是區(qū)別于關(guān)系型數(shù)據(jù)庫最大特點。
2)數(shù)據(jù)寫文件無丟失風(fēng)險,在集群環(huán)境下可以方便橫向擴展,可承載 PB 級別的數(shù)據(jù)。
3)支持條件查詢,支持聚合操作,類似關(guān)系型數(shù)據(jù)庫的 Group By,但是功能更加強大,適合做數(shù)據(jù)分析。
4)高可用,自動發(fā)現(xiàn)新的或者失敗的節(jié)點,重組和重新平衡數(shù)據(jù),確保數(shù)據(jù)是安全和可訪問的。
同樣,ElasticSearch 也有比較明顯的缺點:
1)性能全靠內(nèi)存來頂,也是使用的時候最需要注意的點,非常吃內(nèi)存,大數(shù)據(jù)量下 64G + SSD 基本就是標(biāo)配,相同的配置多一倍內(nèi)存,一個月差不多就要多花好多錢。至于 ElasticSearch 內(nèi)存主要用在以下幾個地方:
2)數(shù)據(jù)結(jié)構(gòu)靈活性不高,字段一旦建立就沒法修改類型了,假如建立的數(shù)據(jù)表某個字段沒有加全文索引,想加上,那么只能把整個表刪了再重建。
3)讀寫之間有延遲,寫入的數(shù)據(jù)差不多 1s 樣子會被讀取到(數(shù)據(jù)寫入時需要維護很多索引)。
因此,搜索型 NoSql 最適用的場景就是有條件搜索尤其是全文搜索的場景,作為關(guān)系型數(shù)據(jù)庫的一種替代方案,通常搜索型 NoSql 也會作為一層前置緩存,來對關(guān)系型數(shù)據(jù)庫進行保護。
此外,搜索型數(shù)據(jù)庫還有一種非常重要的應(yīng)用場景。我們可以想,一旦對數(shù)據(jù)庫做了分庫分表后,原來可以在單表中做的聚合操作、統(tǒng)計操作是否統(tǒng)統(tǒng)失效?例如我把訂單表分 16 個庫,1024 張表,那么訂單數(shù)據(jù)就散落在 1024 張表中,我想要統(tǒng)計昨天浙江省單筆成交金額最高的訂單是哪筆如何做?這就是搜索型 NoSql 的另一大作用了,我們可以把分表之后的數(shù)據(jù)統(tǒng)一打在搜索型 NoSql 中,利用搜索型 NoSql 的搜索與聚合能力完成對全量數(shù)據(jù)的查詢。
列式 NoSql 和關(guān)系型數(shù)據(jù)庫一樣都有主鍵的概念,區(qū)別在于關(guān)系型數(shù)據(jù)庫是按照行組織的數(shù)據(jù),數(shù)據(jù)字段即使沒有值同樣占空間,列式存儲完全是另一種方式,它是按列進行數(shù)據(jù)組織的,好處在于:
大數(shù)據(jù)時代最具代表性的技術(shù)之一 HBase 就是列式 NoSQL 的產(chǎn)品實現(xiàn),其優(yōu)點主要是:
缺點主要表現(xiàn)在:
因此 HBase 比較適用于 KV 型存儲且未來無法預(yù)估數(shù)據(jù)增長量的場景,另外 HBase 使用還是需要一定的經(jīng)驗,主要體現(xiàn)在 RowKey 的設(shè)計上。
文檔型 NoSql 指的是將半結(jié)構(gòu)化數(shù)據(jù)存儲為文檔的一種 NoSql,文檔型 NoSql 通常以 JSON 或者 XML 格式存儲數(shù)據(jù),因此文檔型 NoSql 是沒有 Schema 的,由于沒有 Schema 的特性,我們可以隨意地存儲與讀取數(shù)據(jù),因此文檔型 NoSql 的出現(xiàn)是解決關(guān)系型數(shù)據(jù)庫表結(jié)構(gòu)擴展不方便的問題的。
MongoDB 是文檔型 NoSql 的代表產(chǎn)品,同時也是所有 NoSql 產(chǎn)品中的明星產(chǎn)品之一,它的很多概念與關(guān)系數(shù)據(jù)庫類似,因此,對于 MongDB,我們只需要理解成一個 Free-Schema 的關(guān)系型數(shù)據(jù)庫就好了,其優(yōu)點主要是:
缺點在于:
總而言之,MongDB 的使用場景很大程度上可以對標(biāo)關(guān)系型數(shù)據(jù)庫,但是比較適合處理那些沒有 join、沒有強一致性要求且表 Schema 會常變化的數(shù)據(jù)。
通過以上討論分析我們心中已經(jīng)有了一個基本的選型框架指導(dǎo),實際上在數(shù)據(jù)庫選型時回答自己兩個核心問題就好了:
NoSQL 數(shù)據(jù)庫都是通過犧牲了 ACID 特性來獲取更高性能的,假設(shè)表數(shù)據(jù)有很強的事務(wù)特性需求,那么這類數(shù)據(jù)是不適合放在非關(guān)系型數(shù)據(jù)庫。此外,選用 NoSQL 數(shù)據(jù)庫時也要根據(jù)公司技術(shù)??蚣?、業(yè)務(wù)特性、運維成本等多方面考慮是否采納。
關(guān)系型數(shù)據(jù)庫和 NoSQL 數(shù)據(jù)庫的選型,往往需要考慮幾個指標(biāo):
常見軟件系統(tǒng)數(shù)據(jù)庫選型參考如下:
設(shè)計實踐中,要基于需求、業(yè)務(wù)驅(qū)動架構(gòu),無論選用 RDB/NoSQL, 一定是以需求為導(dǎo)向,最終數(shù)據(jù)存儲方案必然是各種權(quán)衡的綜合性設(shè)計。

我們在微信上24小時期待你的聲音
解答本文疑問/技術(shù)咨詢/運營咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流