自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

到底選擇SQL還是NoSQL?看這里!

運(yùn)維 數(shù)據(jù)庫(kù)運(yùn)維
你是否在為系統(tǒng)的數(shù)據(jù)庫(kù)來(lái)一波大流量就幾乎打滿 CPU,日常 CPU 居高不下煩惱?你是否在各種 NoSQL 間糾結(jié)不定,到底該選用哪種最好?今天的你就是昨天的我,這也是我寫這篇文章的初衷。

你是否在為系統(tǒng)的數(shù)據(jù)庫(kù)來(lái)一波大流量就幾乎打滿 CPU,日常 CPU 居高不下煩惱?你是否在各種 NoSQL 間糾結(jié)不定,到底該選用哪種最好?今天的你就是昨天的我,這也是我寫這篇文章的初衷。

[[273819]]

圖片來(lái)自 Pexels

作為互聯(lián)網(wǎng)從業(yè)人員,我們要知道關(guān)系型數(shù)據(jù)庫(kù)(MySQL、Oracle)無(wú)法滿足我們對(duì)存儲(chǔ)的所有要求,因此對(duì)底層存儲(chǔ)的選型,對(duì)每種存儲(chǔ)引擎的理解非常重要。

同時(shí)也由于過(guò)去一段時(shí)間的工作經(jīng)歷,對(duì)這塊有了一些更多的思考,想通過(guò)自己的總結(jié)把這塊寫出來(lái)分享給大家。

結(jié)構(gòu)化數(shù)據(jù)、非結(jié)構(gòu)化數(shù)據(jù)與半結(jié)構(gòu)化數(shù)據(jù)

文章的開始,聊一下結(jié)構(gòu)化數(shù)據(jù)、非結(jié)構(gòu)化數(shù)據(jù)與半結(jié)構(gòu)化數(shù)據(jù),因?yàn)閿?shù)據(jù)特點(diǎn)的不同,將在技術(shù)上直接影響存儲(chǔ)引擎的選型。

首先是結(jié)構(gòu)化數(shù)據(jù),根據(jù)定義結(jié)構(gòu)化數(shù)據(jù)指的是由二維表結(jié)構(gòu)來(lái)邏輯表達(dá)和實(shí)現(xiàn)的數(shù)據(jù),嚴(yán)格遵循數(shù)據(jù)格式與長(zhǎng)度規(guī)范,也稱作為行數(shù)據(jù),特點(diǎn)為:數(shù)據(jù)以行為單位,一行數(shù)據(jù)表示一個(gè)實(shí)體的信息,每一行數(shù)據(jù)的屬性是相同的。

例如:

因此關(guān)系型數(shù)據(jù)庫(kù)很好契合結(jié)構(gòu)化數(shù)據(jù)的特點(diǎn),關(guān)系型數(shù)據(jù)庫(kù)也是關(guān)系型數(shù)據(jù)最主要的存儲(chǔ)與管理引擎。

非結(jié)構(gòu)化數(shù)據(jù),指的是數(shù)據(jù)結(jié)構(gòu)不規(guī)則或不完整,沒有任何預(yù)定義的數(shù)據(jù)模型,不方便用二維邏輯表來(lái)表現(xiàn)的數(shù)據(jù),例如辦公文檔(Word)、文本、圖片、HTML、各類報(bào)表、視頻音頻等。

介于結(jié)構(gòu)化與非結(jié)構(gòu)化數(shù)據(jù)之間的數(shù)據(jù)就是半結(jié)構(gòu)化數(shù)據(jù)了,它是結(jié)構(gòu)化數(shù)據(jù)的一種形式,雖然不符合二維邏輯這種數(shù)據(jù)模型結(jié)構(gòu),但是包含相關(guān)標(biāo)記,用來(lái)分割語(yǔ)義元素以及對(duì)記錄和字段進(jìn)行分層。

常見的半結(jié)構(gòu)化數(shù)據(jù)有 XML 和 JSON,例如:

  1. <person> 
  2.     <name>張三</name
  3.     <age>18</age> 
  4.     <phone>12345</phone> 
  5. </person> 

這種結(jié)構(gòu)也被成為自描述的結(jié)構(gòu)。

以關(guān)系型數(shù)據(jù)庫(kù)的方式做存儲(chǔ)的架構(gòu)演進(jìn)

首先,我們看一下使用關(guān)系型數(shù)據(jù)庫(kù)的方式,企業(yè)一個(gè)系統(tǒng)發(fā)展的幾個(gè)階段的架構(gòu)演進(jìn)(由于本文寫的是 SQL 與 NoSQL,因此只以存儲(chǔ)方式作為切入點(diǎn),不會(huì)涉及類似 MQ、ZK 這些中間件內(nèi)容):

階段一

企業(yè)剛發(fā)展的階段,最簡(jiǎn)單,一個(gè)應(yīng)用服務(wù)器配一個(gè)關(guān)系型數(shù)據(jù)庫(kù),每次讀寫數(shù)據(jù)庫(kù)。

階段二

無(wú)論是使用 MySQL 還是 Oracle 還是別的關(guān)系型數(shù)據(jù)庫(kù),數(shù)據(jù)庫(kù)通常不會(huì)先成為性能瓶頸,通常隨著企業(yè)規(guī)模的擴(kuò)大,一臺(tái)應(yīng)用服務(wù)器扛不住上游過(guò)來(lái)的流量且一臺(tái)應(yīng)用服務(wù)器會(huì)產(chǎn)生單點(diǎn)故障的問題。

因此加應(yīng)用服務(wù)器并且在流量入口使用 Nginx 做一層負(fù)載均衡,保證把流量均勻打到應(yīng)用服務(wù)器上。

階段三

隨著企業(yè)規(guī)模的繼續(xù)擴(kuò)大,此時(shí)由于讀寫都在同一個(gè)數(shù)據(jù)庫(kù)上,數(shù)據(jù)庫(kù)性能出現(xiàn)一定的瓶頸。

此時(shí)簡(jiǎn)單地做一層讀寫分離,每次寫主庫(kù),讀備庫(kù),主備庫(kù)之間通過(guò) Binlog 同步數(shù)據(jù),就能很大程度上解決這個(gè)階段的數(shù)據(jù)庫(kù)性能問題。

階段四

企業(yè)發(fā)展越來(lái)越好了,業(yè)務(wù)越來(lái)越大了,做了讀寫分離數(shù)據(jù)庫(kù)壓力還是越來(lái)越大,這時(shí)候怎么辦呢?

一臺(tái)數(shù)據(jù)庫(kù)扛不住,那我們就分幾臺(tái)吧,做分庫(kù)分表,對(duì)表做垂直拆分,對(duì)庫(kù)做水平拆分。

以擴(kuò)數(shù)據(jù)庫(kù)為例,擴(kuò)出兩臺(tái)數(shù)據(jù)庫(kù),以一定的單號(hào)(例如交易單號(hào)),以一定的規(guī)則(例如取模)。

交易單號(hào)對(duì) 2 取模為 0 的丟到數(shù)據(jù)庫(kù) 1 去,交易單號(hào)對(duì) 2 取模為 1 的丟到數(shù)據(jù)庫(kù) 2 去,通過(guò)這樣的方式將寫數(shù)據(jù)庫(kù)的流量均分到兩臺(tái)數(shù)據(jù)庫(kù)上。

一般分庫(kù)分表會(huì)使用 Shard 的方式,通過(guò)一個(gè)中間件,便于連接管理、數(shù)據(jù)監(jiān)控且客戶端無(wú)需感知數(shù)據(jù)庫(kù) IP。

關(guān)系型數(shù)據(jù)庫(kù)的優(yōu)點(diǎn)

上面的方式,看似可以解決問題(實(shí)際上確實(shí)也能解決很多問題),正常對(duì)關(guān)系型數(shù)據(jù)庫(kù)做一下讀寫分離+分庫(kù)分表,支撐個(gè) 1W+ 的讀寫 QPS 還是問題不大的。

但是受限于關(guān)系型數(shù)據(jù)庫(kù)本身,這套架構(gòu)方案依然有著明顯的不足,下面對(duì)利用關(guān)系型數(shù)據(jù)庫(kù)方式做存儲(chǔ)的方案的優(yōu)點(diǎn)先進(jìn)行一下分析,后一部分再分析一下缺點(diǎn),對(duì)某個(gè)技術(shù)的優(yōu)缺點(diǎn)的充分理解是技術(shù)選型的前提。

①易理解

因?yàn)樾?列的二維表邏輯是非常貼近邏輯世界的一個(gè)概念,關(guān)系模型相對(duì)網(wǎng)狀、層次等其他模型更加容易被理解。

②操作方便

通用的 SQL 語(yǔ)言使得操作關(guān)系型數(shù)據(jù)庫(kù)非常方便,支持 Join 等復(fù)雜查詢。

③數(shù)據(jù)一致性

支持 ACID 特性,可以維護(hù)數(shù)據(jù)之間的一致性,這是使用數(shù)據(jù)庫(kù)非常重要的一個(gè)理由之一。

例如同銀行轉(zhuǎn)賬,張三轉(zhuǎn)給李四 100 元錢,張三扣 100 元,李四加 100 元,而且必須同時(shí)成功或者同時(shí)失敗,否則就會(huì)造成用戶的資損。

④數(shù)據(jù)穩(wěn)定

數(shù)據(jù)持久化到磁盤,沒有丟失數(shù)據(jù)風(fēng)險(xiǎn),支持海量數(shù)據(jù)存儲(chǔ)。

⑤服務(wù)穩(wěn)定

最常用的關(guān)系型數(shù)據(jù)庫(kù)產(chǎn)品 MySQL、Oracle 服務(wù)器性能卓越,服務(wù)穩(wěn)定,通常很少出現(xiàn)宕機(jī)異常。

關(guān)系型數(shù)據(jù)庫(kù)的缺點(diǎn)

緊接著的,我們看一下關(guān)系型數(shù)據(jù)庫(kù)的缺點(diǎn),也是比較明顯的。

①高并發(fā)下 IO 壓力大

數(shù)據(jù)按行存儲(chǔ),即使只針對(duì)其中某一列進(jìn)行運(yùn)算,也會(huì)將整行數(shù)據(jù)從存儲(chǔ)設(shè)備中讀入內(nèi)存,導(dǎo)致 IO 較高。

②為維護(hù)索引付出的代價(jià)大

為了提供豐富的查詢能力,通常熱點(diǎn)表都會(huì)有多個(gè)二級(jí)索引,一旦有了二級(jí)索引,數(shù)據(jù)的新增必然伴隨著所有二級(jí)索引的新增。

數(shù)據(jù)的更新也必然伴隨著所有二級(jí)索引的更新,這不可避免地降低了關(guān)系型數(shù)據(jù)庫(kù)的讀寫能力,且索引越多讀寫能力越差。

有機(jī)會(huì)的話可以看一下自己公司的數(shù)據(jù)庫(kù),除了數(shù)據(jù)文件不可避免地占空間外,索引占的空間其實(shí)也并不少。

③為維護(hù)數(shù)據(jù)一致性付出的代價(jià)大

數(shù)據(jù)一致性是關(guān)系型數(shù)據(jù)庫(kù)的核心,但是同樣為了維護(hù)數(shù)據(jù)一致性的代價(jià)也是非常大的。

我們都知道 SQL 標(biāo)準(zhǔn)為事務(wù)定義了不同的隔離級(jí)別,從低到高依次是讀未提交、讀已提交、可重復(fù)讀、串行化,事務(wù)隔離級(jí)別月底,可能出現(xiàn)的并發(fā)異常越多,但是通常而言能提供的并發(fā)能力越強(qiáng)。

那么為了保證事務(wù)一致性,數(shù)據(jù)庫(kù)就需要提供并發(fā)控制與故障恢復(fù)兩種技術(shù),前者用于減少并發(fā)異常,后者可以在系統(tǒng)異常的時(shí)候保證事務(wù)與數(shù)據(jù)庫(kù)狀態(tài)不會(huì)被破壞。

對(duì)于并發(fā)控制,其核心思想就是加鎖,無(wú)論是樂觀鎖還是悲觀鎖,只要提供的隔離級(jí)別越高,那么讀寫性能必然越差。

④水平擴(kuò)展后帶來(lái)的種種問題難處理

前文提過(guò),隨著企業(yè)規(guī)模擴(kuò)大,一種方式是對(duì)數(shù)據(jù)庫(kù)做分庫(kù),做了分庫(kù)之后,數(shù)據(jù)遷移(1 個(gè)庫(kù)的數(shù)據(jù)按照一定規(guī)則打到 2 個(gè)庫(kù)中)、跨庫(kù) Join(訂單數(shù)據(jù)里有用戶數(shù)據(jù),兩條數(shù)據(jù)不在同一個(gè)庫(kù)中)、分布式事務(wù)處理都是需要考慮的問題,尤其是分布式事務(wù)處理,業(yè)界當(dāng)前都沒有特別好的解決方案。

⑤表結(jié)構(gòu)擴(kuò)展不方便

由于數(shù)據(jù)庫(kù)存儲(chǔ)的是結(jié)構(gòu)化數(shù)據(jù),因此表結(jié)構(gòu) Schema 是固定的,擴(kuò)展不方便,如果需要修改表結(jié)構(gòu),需要執(zhí)行 DDL(data definition language)語(yǔ)句修改,修改期間會(huì)導(dǎo)致鎖表,部分服務(wù)不可用。

⑥全文搜索功能弱

例如 like "%中國(guó)真?zhèn)ゴ?",只能搜索到"2019年中國(guó)真?zhèn)ゴ?,愛祖?guó)",無(wú)法搜索到"中國(guó)真是太偉大了"這樣的文本,即不具備分詞能力。

且 like 查詢?cè)?quot;%中國(guó)真?zhèn)ゴ?quot;這樣的搜索條件下,無(wú)法命中索引,將會(huì)導(dǎo)致查詢效率大大降低。

寫了這么多,我的理解核心還是前三點(diǎn),它反映出的一個(gè)問題是關(guān)系型數(shù)據(jù)庫(kù)在高并發(fā)下的能力是有瓶頸的。

尤其是寫入/更新頻繁的情況下,出現(xiàn)瓶頸的結(jié)果就是數(shù)據(jù)庫(kù) CPU 高、SQL 執(zhí)行慢、客戶端報(bào)數(shù)據(jù)庫(kù)連接池不夠等錯(cuò)誤,因此例如萬(wàn)人秒殺這種場(chǎng)景,我們絕對(duì)不可能通過(guò)數(shù)據(jù)庫(kù)直接去扣減庫(kù)存。

可能有朋友說(shuō),數(shù)據(jù)庫(kù)在高并發(fā)下的能力有瓶頸,我公司有錢,加 CPU、換固態(tài)硬盤、繼續(xù)買服務(wù)器加數(shù)據(jù)庫(kù)做分庫(kù)不就好了。

問題是這是一種性價(jià)比非常低的方式,花 1000 萬(wàn)達(dá)到的效果,換其他方式可能 100 萬(wàn)就達(dá)到了,不考慮人員、服務(wù)器投入產(chǎn)出比的 Leader 就是個(gè)不合格的 Leader。

且關(guān)系型數(shù)據(jù)庫(kù)的方式,受限于它本身的特點(diǎn),可能花了錢都未必能達(dá)到想要的效果。

至于什么是花 100 萬(wàn)就能達(dá)到花 1000 萬(wàn)效果的方式呢?可以繼續(xù)往下看,這就是我們要說(shuō)的 NoSQL。

結(jié)合 NoSQL 的方式做存儲(chǔ)的架構(gòu)演進(jìn)

像上文分析的,數(shù)據(jù)庫(kù)作為一種關(guān)系型數(shù)據(jù)的存儲(chǔ)引擎,存儲(chǔ)的是關(guān)系型數(shù)據(jù),它有優(yōu)點(diǎn),同時(shí)也有明顯的缺點(diǎn)。

因此通常在企業(yè)規(guī)模不斷擴(kuò)大的情況下,不會(huì)一味指望通過(guò)增強(qiáng)數(shù)據(jù)庫(kù)的能力來(lái)解決數(shù)據(jù)存儲(chǔ)問題,而是會(huì)引入其他存儲(chǔ),也就是我們說(shuō)的 NoSQL。

NoSQL 的全稱為 Not Only SQL,泛指非關(guān)系型數(shù)據(jù)庫(kù),是對(duì)關(guān)系型數(shù)據(jù)庫(kù)的一種補(bǔ)充。

特別要注意補(bǔ)充這兩個(gè)字,這意味著 NoSQL 與關(guān)系型數(shù)據(jù)庫(kù)并不是對(duì)立關(guān)系,二者各有優(yōu)劣,取長(zhǎng)補(bǔ)短,在合適的場(chǎng)景下選擇合適的存儲(chǔ)引擎才是正確的做法。

比較簡(jiǎn)單的 NoSQL 就是緩存:

針對(duì)那些讀遠(yuǎn)多于寫的數(shù)據(jù),引入一層緩存,每次讀從緩存中讀取,緩存中讀取不到,再去數(shù)據(jù)庫(kù)中取,取完之后再寫入到緩存,對(duì)數(shù)據(jù)做好失效機(jī)制通常就沒有大問題了。

通常來(lái)說(shuō),緩存是性能優(yōu)化的第一選擇也是見效最明顯的方案。但是,緩存通常都是 KV 型存儲(chǔ)且容量有限(基于內(nèi)存),無(wú)法解決所有問題,于是再進(jìn)一步的優(yōu)化,我們繼續(xù)引入其他 NoSQL:

數(shù)據(jù)庫(kù)、緩存與其他 NoSQL 并行工作,充分發(fā)揮每種 NoSQL 的特點(diǎn)。當(dāng)然 NoSQL 在性能方面大大優(yōu)于關(guān)系型數(shù)據(jù)庫(kù)的同時(shí),往往也伴隨著一些特性的缺失,比較常見的就是事務(wù)功能的缺失。

下面看一下常用的 NoSQL 及他們的代表產(chǎn)品,并對(duì)每種 NoSQL 的優(yōu)缺點(diǎn)和適用場(chǎng)景做一下分析,便于熟悉每種 NoSQL 的特點(diǎn),方便技術(shù)選型。

KV 型 NoSQL(代表:Redis)

KV 型 NoSQL 顧名思義就是以鍵值對(duì)形式存儲(chǔ)的非關(guān)系型數(shù)據(jù)庫(kù),是最簡(jiǎn)單、最容易理解也是大家最熟悉的一種 NoSQL,因此比較快地帶過(guò)。

Redis、MemCache 是其中的代表,Redis 又是 KV 型 NoSQL 中應(yīng)用很廣泛的 NoSQL。

KV 型數(shù)據(jù)庫(kù)以 Redis 為例,最大的優(yōu)點(diǎn)我總結(jié)下來(lái)就兩點(diǎn):

  • 數(shù)據(jù)基于內(nèi)存,讀寫效率高。
  • KV 型數(shù)據(jù),時(shí)間復(fù)雜度為 O(1),查詢速度快。

因此,KV 型 NoSQL 最大的優(yōu)點(diǎn)就是高性能,利用 Redis 自帶的 BenchMark 做基準(zhǔn)測(cè)試,TPS 可達(dá)到 10 萬(wàn)的級(jí)別,性能非常強(qiáng)勁。

同樣的 Redis 也有所有 KV 型 NoSQL 都有的比較明顯的缺點(diǎn):

  • 只能根據(jù) K 查 V,無(wú)法根據(jù) V 查 K。
  • 查詢方式單一,只有 KV 的方式,不支持條件查詢,多條件查詢唯一的做法就是數(shù)據(jù)冗余,但這會(huì)極大的浪費(fèi)存儲(chǔ)空間。
  • 內(nèi)存是有限的,無(wú)法支持海量數(shù)據(jù)存儲(chǔ)。
  • 同樣的,由于 KV 型 NoSQL 的存儲(chǔ)是基于內(nèi)存的,會(huì)有丟失數(shù)據(jù)的風(fēng)險(xiǎn)。

綜上所述,KV 型 NoSQL 最合適的場(chǎng)景就是緩存的場(chǎng)景:

  • 讀遠(yuǎn)多于寫。
  • 讀取能力強(qiáng)。
  • 沒有持久化的需求,可以容忍數(shù)據(jù)丟失,反正丟了再查詢一把寫入就是了。

例如根據(jù)用戶 id 查詢用戶信息,每次根據(jù)用戶 id 去緩存中查詢一把,查到數(shù)據(jù)直接返回,查不到去關(guān)系型數(shù)據(jù)庫(kù)里面根據(jù) id 查詢一把數(shù)據(jù)寫到緩存中去。

搜索型NoSQL(代表:ES)

傳統(tǒng)關(guān)系型數(shù)據(jù)庫(kù)主要通過(guò)索引來(lái)達(dá)到快速查詢的目的,但是在全文搜索的場(chǎng)景下,索引是無(wú)能為力的。

like 查詢一來(lái)無(wú)法滿足所有模糊匹配需求,二來(lái)使用限制太大且使用不當(dāng)容易造成慢查詢。

搜索型 NoSQL 的誕生正是為了解決關(guān)系型數(shù)據(jù)庫(kù)全文搜索能力較弱的問題,ElasticSearch 是搜索型 NoSQL 的代表產(chǎn)品。

全文搜索的原理是倒排索引,我們看一下什么是倒排索引。要說(shuō)倒排索引我們先看下什么是正排索引,傳統(tǒng)的正排索引是文檔-->關(guān)鍵字的映射。

例如"Tom is my friend"這句話,會(huì)將其切分為"Tom"、"is"、"my"、"friend"四個(gè)單詞,在搜索的時(shí)候?qū)ξ臋n進(jìn)行掃描,符合條件的查出來(lái)。

這種方式原理非常簡(jiǎn)單,但是由于其檢索效率太低,基本沒什么實(shí)用價(jià)值。

倒排索引則完全相反,它是關(guān)鍵字-->文檔的映射,我用張表格展示一下就比較清楚了:

意思是我現(xiàn)在這里有"Tom is Tom"、"Tom is my friend"、"Thank you, Betty"、"Tom is Betty's husband"四句話。

搜索引擎會(huì)根據(jù)一定的切分規(guī)則將這句話切成 N 個(gè)關(guān)鍵字,并以關(guān)鍵字的維度維護(hù)關(guān)鍵字在每個(gè)文本中的出現(xiàn)次數(shù)。

這樣下次搜索"Tom"的時(shí)候,由于 Tom 這個(gè)詞語(yǔ)在"Tom is Tom"、"Tom is my friend"、"Tom is Betty's husband"三句話中都有出現(xiàn),因此這三條記錄都會(huì)被檢索出來(lái)。

且由于"Tom is Tom"這句話中"Tom"出現(xiàn)了 2 次,因此這條記錄對(duì)"Tom"這個(gè)單詞的匹配度最高,最先展示。

這就是搜索引擎倒排索引的基本原理,假設(shè)某個(gè)關(guān)鍵字在某個(gè)文檔中出現(xiàn),那么倒排索引中有兩部分內(nèi)容:

  • 文檔 id。
  • 在該文檔中出現(xiàn)的位置情況。

可以舉一反三,我們搜索"Betty Tom"這兩個(gè)詞語(yǔ)也是一樣,搜索引擎將"Betty Tom"切分為"Tom"、"Betty"兩個(gè)單詞,根據(jù)開發(fā)者指定的滿足率,比如滿足率=50%,那么只要記錄中出現(xiàn)了兩個(gè)單詞之一的記錄都會(huì)被檢索出來(lái),再按照匹配度進(jìn)行展示。

搜索型 NoSQL 以 ElasticSearch 為例,它的優(yōu)點(diǎn)為:

  • 支持分詞場(chǎng)景、全文搜索,這是區(qū)別于關(guān)系型數(shù)據(jù)庫(kù)的最大特點(diǎn)。
  • 支持條件查詢,支持聚合操作,類似關(guān)系型數(shù)據(jù)庫(kù)的 Group By,但是功能更加強(qiáng)大,適合做數(shù)據(jù)分析。
  • 數(shù)據(jù)寫文件無(wú)丟失風(fēng)險(xiǎn),在集群環(huán)境下可以方便橫向擴(kuò)展,可承載 PB 級(jí)別的數(shù)據(jù)。
  • 高可用,自動(dòng)發(fā)現(xiàn)新的或者失敗的節(jié)點(diǎn),重組和重新平衡數(shù)據(jù),確保數(shù)據(jù)是安全和可訪問的。

同樣,ElasticSearch 也有比較明顯的缺點(diǎn):

①性能全靠?jī)?nèi)存來(lái)頂,也是使用的時(shí)候最需要注意的點(diǎn),非常吃硬件資源、吃內(nèi)存,大數(shù)據(jù)量下 64G+SSD 基本是標(biāo)配,算得上是數(shù)據(jù)庫(kù)中的愛馬仕了。

為什么要專門提一下內(nèi)存呢,因?yàn)閮?nèi)存這個(gè)東西是很值錢的,相同的配置多一倍內(nèi)存,一個(gè)月差不多就要多花幾百塊錢。

至于 ElasticSearch 內(nèi)存用在什么地方,大概有如下這些:

  • Indexing Buffer:ElasticSearch 基于 Luence,Lucene 的倒排索引是先在內(nèi)存里生成,然后定期以 Segment File 的方式刷磁盤的,每個(gè) Segment File 實(shí)際就是一個(gè)完整的倒排索引。
  • Segment Memory:倒排索引前面說(shuō)過(guò)是基于關(guān)鍵字的,Lucene 在 4.0 后會(huì)將所有關(guān)鍵字以 FST 這種數(shù)據(jù)結(jié)構(gòu)的方式將所有關(guān)鍵字在啟動(dòng)的時(shí)候全量加載到內(nèi)存,加快查詢速度,官方建議至少留系統(tǒng)一半內(nèi)存給 Lucene。
  • 各類緩存:Filter Cache、Field Cache、Indexing Cache 等,用于提升查詢分析性能,例如 Filter Cache 用于緩存使用過(guò)的 Filter 的結(jié)果集。
  • Cluter State Buffer:ElasticSearch 被設(shè)計(jì)為每個(gè) Node 都可以響應(yīng)用戶請(qǐng)求,因此每個(gè) Node 的內(nèi)存中都包含有一份集群狀態(tài)的拷貝,一個(gè)規(guī)模很大的集群這個(gè)狀態(tài)信息可能會(huì)非常大。

②讀寫之間有延遲,寫入的數(shù)據(jù)差不多 1s 樣子會(huì)被讀取到,這也正常,寫入的時(shí)候自動(dòng)加入這么多索引肯定影響性能。

③數(shù)據(jù)結(jié)構(gòu)靈活性不高,ElasticSearch 這個(gè)東西,字段一旦建立就沒法修改類型了,假如建立的數(shù)據(jù)表某個(gè)字段沒有加全文索引,想加上,那么只能把整個(gè)表刪了再重建。

因此,搜索型 NoSQL 最適用的場(chǎng)景就是有條件搜索尤其是全文搜索的場(chǎng)景,作為關(guān)系型數(shù)據(jù)庫(kù)的一種替代方案。

另外,搜索型數(shù)據(jù)庫(kù)還有一種特別重要的應(yīng)用場(chǎng)景。我們可以想,一旦對(duì)數(shù)據(jù)庫(kù)做了分庫(kù)分表后,原來(lái)可以在單表中做的聚合操作、統(tǒng)計(jì)操作是否統(tǒng)統(tǒng)失效?

例如我把訂單表分 16 個(gè)庫(kù),1024 張表,那么訂單數(shù)據(jù)就散落在 1024 張表中,我想要統(tǒng)計(jì)昨天浙江省單筆成交金額最高的訂單是哪筆如何做?我想要把昨天的所有訂單按照時(shí)間排序分頁(yè)展示如何做?

這就是文檔型 NoSQL 的另一大作用了,我們可以把分表之后的數(shù)據(jù)統(tǒng)一打在文檔型 NoSQL 中,利用文檔型 NoSQL 的搜索與聚合能力完成對(duì)全量數(shù)據(jù)的查詢。

至于為什么把它放在 KV 型 NoSQL 后面作為第二個(gè)寫呢,因?yàn)橥ǔK阉餍?NoSQL 也會(huì)作為一層前置緩存,來(lái)對(duì)關(guān)系型數(shù)據(jù)庫(kù)進(jìn)行保護(hù)。

列式 NoSQL(代表:HBase)

列式 NoSQL,大數(shù)據(jù)時(shí)代代表性的技術(shù)之一了,以 HBase 為代表。列式 NoSQL 是基于列式存儲(chǔ)的,那么什么是列式存儲(chǔ)呢,列式 SQL 和關(guān)系型數(shù)據(jù)庫(kù)一樣都有主鍵的概念,區(qū)別在于關(guān)系型數(shù)據(jù)庫(kù)是按照行組織的數(shù)據(jù):

看到每行有 name、phone、address 三個(gè)字段,這是行式存儲(chǔ)的方式,且可以觀察 id=2 的這條數(shù)據(jù),即使 phone 字段沒有,它也是占空間的。

列式存儲(chǔ)完全是另一種方式,它是按每一列進(jìn)行組織的數(shù)據(jù):

這么做有什么好處呢?大致有以下幾點(diǎn):

  • 查詢時(shí)只有指定的列會(huì)被讀取,不會(huì)讀取所有列。
  • 存儲(chǔ)上節(jié)約空間,Null 值不會(huì)被存儲(chǔ),一列中有時(shí)候會(huì)有很多重復(fù)數(shù)據(jù)(尤其是枚舉數(shù)據(jù),性別、狀態(tài)等),這類數(shù)據(jù)可壓縮,行式數(shù)據(jù)庫(kù)壓縮率通常在 3:1~5:1 之間,列式數(shù)據(jù)庫(kù)的壓縮率一般在 8:1~30:1 左右。
  • 列數(shù)據(jù)被組織到一起,一次磁盤 IO 可以將一列數(shù)據(jù)一次性讀取到內(nèi)存中。

第二點(diǎn)說(shuō)到了數(shù)據(jù)壓縮,什么意思呢,以比較常見的字典表壓縮方式舉例:

 

仔細(xì)看圖理解一下,應(yīng)該就懂了。接著繼續(xù)講講優(yōu)缺點(diǎn),列式 NoSQL,以 HBase 為代表的,優(yōu)點(diǎn)為:

  • 海量數(shù)據(jù)無(wú)限存儲(chǔ),PB 級(jí)別數(shù)據(jù)隨便存,底層基于 HDFS(Hadoop 文件系統(tǒng)),數(shù)據(jù)持久化。
  • 讀寫性能好,只要沒有濫用造成數(shù)據(jù)熱點(diǎn),讀寫基本隨便玩。
  • 橫向擴(kuò)展在關(guān)系型數(shù)據(jù)庫(kù)及非關(guān)系型數(shù)據(jù)庫(kù)中都是方便的之一,只需要添加新機(jī)器就可以實(shí)現(xiàn)數(shù)據(jù)容量的線性增長(zhǎng),且可用在廉價(jià)服務(wù)器上,節(jié)省成本。
  • 本身沒有單點(diǎn)故障,可用性高。
  • 可存儲(chǔ)結(jié)構(gòu)化或者半結(jié)構(gòu)化的數(shù)據(jù)。
  • 列數(shù)理論上無(wú)限,HBase 本身只對(duì)列族數(shù)量有要求,建議 1~3 個(gè)。

說(shuō)了這么多 HBase 的優(yōu)點(diǎn),又到了說(shuō) HBase 缺點(diǎn)的時(shí)候了:

  • HBase 是 Hadoop 生態(tài)的一部分,因此它本身是一款比較重的產(chǎn)品,依賴很多 Hadoop 組件,數(shù)據(jù)規(guī)模不大沒必要用,運(yùn)維還是有點(diǎn)復(fù)雜的。
  • KV 式,不支持條件查詢,或者說(shuō)條件查詢非常非常弱吧,HBase 在 Scan 掃描一批數(shù)據(jù)的情況下還是提供了前綴匹配這種 API 的,條件查詢除非定義多個(gè) RowKey 做數(shù)據(jù)冗余。
  • 不支持分頁(yè)查詢,因?yàn)榻y(tǒng)計(jì)不了數(shù)據(jù)總數(shù)。

因此 HBase 比較適用于那種 KV 型的且未來(lái)無(wú)法預(yù)估數(shù)據(jù)增長(zhǎng)量的場(chǎng)景,另外 HBase 使用還是需要一定的經(jīng)驗(yàn),主要體現(xiàn)在 RowKey 的設(shè)計(jì)上。

文檔型 NoSQL(代表:MongoDB)

坦白講,根據(jù)我的工作經(jīng)歷,文檔型 NoSQL 我只有比較淺的使用經(jīng)驗(yàn),因此這部分只能結(jié)合之前的使用與網(wǎng)上的文章大致給大家介紹一下。

什么是文檔型 NoSQL 呢,文檔型 NoSQL 指的是將半結(jié)構(gòu)化數(shù)據(jù)存儲(chǔ)為文檔的一種 NoSQL。

文檔型 NoSQL 通常以 JSON 或者 XML 格式存儲(chǔ)數(shù)據(jù),因此文檔型 NoSQL 是沒有 Schema 的。

由于沒有 Schema 的特性,我們可以隨意地存儲(chǔ)與讀取數(shù)據(jù),因此文檔型 NoSQL 的出現(xiàn)是解決關(guān)系型數(shù)據(jù)庫(kù)表結(jié)構(gòu)擴(kuò)展不方便的問題的。

MongoDB 是文檔型 NoSQL 的代表產(chǎn)品,同時(shí)也是所有 NoSQL 產(chǎn)品中的明星產(chǎn)品之一,因此這里以 MongoDB 為例。

按我的理解,作為文檔型 NoSQL,MongoDB 是一款完全和關(guān)系型數(shù)據(jù)庫(kù)對(duì)標(biāo)的產(chǎn)品,就我們從存儲(chǔ)上來(lái)看:

可看到,關(guān)系型數(shù)據(jù)庫(kù)是按部就班地每個(gè)字段一列存,在 MongDB 里面就是一個(gè) JSON 字符串存儲(chǔ)。

關(guān)系型數(shù)據(jù)可以為 name、phone 建立索引,MongoDB 使用 createIndex 命令一樣可以為列建立索引,建立索引之后可以大大提升查詢效率。

其他方面而言,就大的基本概念,二者之間基本也是類似的:

因此,對(duì)于 MongDB,我們只要理解成一個(gè) Free-Schema 的關(guān)系型數(shù)據(jù)庫(kù)就完事了,它的優(yōu)缺點(diǎn)比較一目了然,優(yōu)點(diǎn):

  • 沒有預(yù)定義的字段,擴(kuò)展字段容易。
  • 相較于關(guān)系型數(shù)據(jù)庫(kù),讀寫性能優(yōu)越,命中二級(jí)索引的查詢不會(huì)比關(guān)系型數(shù)據(jù)庫(kù)慢,對(duì)于非索引字段的查詢則是全面勝出。

缺點(diǎn)在于:

  • 不支持事務(wù)操作,雖然 MongoDB 4.0 之后宣稱支持事務(wù),但是效果待觀測(cè)。
  • 多表之間的關(guān)聯(lián)查詢不支持(雖然有嵌入文檔的方式),Join 查詢還是需要多次操作。
  • 空間占用較大,這個(gè)是 MongDB 的設(shè)計(jì)問題,空間預(yù)分配機(jī)制+刪除數(shù)據(jù)后空間不釋放,只有用 db.repairDatabase() 去修復(fù)才能釋放。
  • 目前沒發(fā)現(xiàn) MongoDB 有關(guān)系型數(shù)據(jù)庫(kù)例如 MySQL 的 Navicat 這種成熟的運(yùn)維工具。

總而言之,MongDB 的使用場(chǎng)景很大程度上可以對(duì)標(biāo)關(guān)系型數(shù)據(jù)庫(kù),但是比較適合處理那些沒有 Join、沒有強(qiáng)一致性要求且表 Schema 會(huì)常變化的數(shù)據(jù)。

總結(jié):數(shù)據(jù)庫(kù)與 NoSQL 及各種 NoSQL 間的對(duì)比

最后一部分,做一個(gè)總結(jié),本文歸根到底是兩個(gè)話題:

  • 何時(shí)選用關(guān)系型數(shù)據(jù)庫(kù),何時(shí)選用非關(guān)系型數(shù)據(jù)庫(kù)。
  • 選用非關(guān)系型數(shù)據(jù)庫(kù),使用哪種非關(guān)系型數(shù)據(jù)庫(kù)。

首先是第一個(gè)話題,關(guān)系型數(shù)據(jù)庫(kù)與非關(guān)系型數(shù)據(jù)庫(kù)的選擇,在我理解里面無(wú)非就是兩點(diǎn)考慮:

第一點(diǎn),不多解釋應(yīng)該都理解,非關(guān)系型數(shù)據(jù)庫(kù)都是通過(guò)犧牲了 ACID 特性來(lái)獲取更高的性能的,假設(shè)兩張表之間有比較強(qiáng)的一致性需求,那么這類數(shù)據(jù)是不適合放在非關(guān)系型數(shù)據(jù)庫(kù)中的。

第二點(diǎn),核心數(shù)據(jù)不走非關(guān)系型數(shù)據(jù)庫(kù),例如用戶表、訂單表,但是這有一個(gè)前提,就是這一類核心數(shù)據(jù)會(huì)有多種查詢模式。

例如用戶表有 ABCD 四個(gè)字段,可能根據(jù) AB 查,可能根據(jù) AC 查,可能根據(jù) D 查,假設(shè)核心數(shù)據(jù),但是就是個(gè) KV 形式,比如用戶的聊天記錄,那么 HBase 一存就完事了。

從這幾年的工作經(jīng)驗(yàn)來(lái)看,非核心數(shù)據(jù)尤其是日志、流水一類中間數(shù)據(jù)千萬(wàn)不要寫在關(guān)系型數(shù)據(jù)庫(kù)中,這一類數(shù)據(jù)通常有兩個(gè)特點(diǎn):

  • 寫遠(yuǎn)高于讀
  • 寫入量巨大

一旦使用關(guān)系型數(shù)據(jù)庫(kù)作為存儲(chǔ)引擎,將大大降低關(guān)系型數(shù)據(jù)庫(kù)的能力,正常讀寫 QPS 不高的核心服務(wù)會(huì)受這一類數(shù)據(jù)讀寫的拖累。

接著是第二個(gè)問題,如果我們使用非關(guān)系型數(shù)據(jù)庫(kù)作為存儲(chǔ)引擎,那么如何選型?

其實(shí)上面的文章基本都寫了,這里只是做一個(gè)總結(jié)(所有的缺點(diǎn)都不會(huì)體現(xiàn)事務(wù)這個(gè)點(diǎn),因?yàn)檫@是所有 NoSQL 相比關(guān)系型數(shù)據(jù)庫(kù)共有的一個(gè)問題):

但是這里特別說(shuō)明,選型一定要結(jié)合實(shí)際情況而不是照本宣科,比如:

  • 企業(yè)發(fā)展之初,明明一個(gè)關(guān)系型數(shù)據(jù)庫(kù)就能搞定且支撐一年的架構(gòu),搞一套大而全的技術(shù)方案出來(lái)。
  • 有一些數(shù)據(jù)條件查詢多,更適合使用 ElasticSearch 做存儲(chǔ)降低關(guān)系型數(shù)據(jù)庫(kù)壓力,但是公司成本有限,這種情況下這類數(shù)據(jù)可以嘗試?yán)^續(xù)使用關(guān)系型數(shù)據(jù)庫(kù)做存儲(chǔ)。
  • 有一類數(shù)據(jù)格式簡(jiǎn)單,就是這個(gè) KV 類型且增長(zhǎng)量大,但是公司沒有 HBase 這方面的人才,運(yùn)維上可能會(huì)有一定難度,出于實(shí)際情況考慮,可先用關(guān)系型數(shù)據(jù)庫(kù)頂一陣子。

所以,如果不考慮實(shí)際情況,雖然確實(shí)有些存儲(chǔ)引擎更加合適,但是強(qiáng)行使用反而適得其反,總而言之,適合自己的才是最好的。

 

責(zé)任編輯:武曉燕 來(lái)源: 五月的倉(cāng)頡
相關(guān)推薦

2019-08-14 14:54:19

MySQLPostgreSQL數(shù)據(jù)庫(kù)

2014-07-30 10:29:13

大數(shù)據(jù)NoSQL

2021-06-15 05:52:59

SQLNoSQL數(shù)據(jù)庫(kù)

2017-10-17 09:55:16

數(shù)據(jù)庫(kù)SQL Server規(guī)范集錦

2014-03-20 14:02:17

大數(shù)據(jù)

2024-07-30 11:40:00

數(shù)據(jù)庫(kù)NoSQLSQL

2020-12-18 09:11:43

數(shù)據(jù)庫(kù)SQLNoSQL

2019-10-25 09:01:09

物聯(lián)網(wǎng)Wi-Fi通信

2011-04-07 11:02:52

游標(biāo)

2011-07-19 10:08:09

SQLNoSQL云計(jì)算

2024-10-12 09:33:24

消息隊(duì)列多線程并行編程

2023-09-27 10:23:19

NoSQL數(shù)據(jù)模型

2018-08-13 09:20:21

NoSQLSQL數(shù)據(jù)

2017-12-17 20:17:23

NoSQLSQL數(shù)據(jù)

2014-11-05 10:08:50

2011-05-13 09:46:20

MySQLNoSQL

2020-03-06 10:33:01

網(wǎng)絡(luò)欺詐在線支付網(wǎng)絡(luò)安全

2021-03-31 06:37:03

WiFi 6路由器WiFi 5

2011-04-06 10:06:13

數(shù)據(jù)不刪

2015-12-08 10:23:23

SDN軟件定義網(wǎng)絡(luò)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)