圖解:什么是高并發(fā)利器NoSQL?
1.迷茫的小黑
小黑最近有點(diǎn)郁悶。
手頭的工作不是特別喜歡,技術(shù)退步有點(diǎn)嚴(yán)重,于是想出去看看機(jī)會(huì)。
小黑通過(guò)朋友內(nèi)推,前幾天去北京CBD附近的一家名叫宇節(jié)蹦跶的公司面試,被一些問(wèn)題三連擊直接跪掉了。
大白安撫小黑說(shuō):"黑哥,你要知道沒(méi)有好工作,只有好工人,其實(shí)哪兒都差不多,都是打工嘛!"
小黑說(shuō):"那咋能一樣,工具人么得意思,俺的目標(biāo)是架構(gòu)師!"
小黑把大白數(shù)落了一頓,畢竟不想當(dāng)架構(gòu)師的后端不算好的程序員,然后開(kāi)始說(shuō)他碰到的問(wèn)題,原來(lái)事情是這樣的:
小黑開(kāi)場(chǎng)白介紹完自己之后,面試官問(wèn)他喜歡哪個(gè)領(lǐng)域,小黑說(shuō)分布式存儲(chǔ)。
面試官附和道:"確實(shí)是個(gè)不錯(cuò)的領(lǐng)域,那問(wèn)你幾個(gè)存儲(chǔ)相關(guān)的問(wèn)題吧!"
小黑竊喜以為問(wèn)題在自己知識(shí)射程范圍內(nèi),于是面試官拋出了幾個(gè)問(wèn)題:
1.在實(shí)際工作中用到過(guò)哪些NoSQL?
2.NoSQL相比MySQL有什么優(yōu)缺點(diǎn)?
3.WAL和LSM這些底層機(jī)制了解嗎?
4.如何設(shè)計(jì)一個(gè)NoSQL。
聽(tīng)完這幾個(gè)問(wèn)題,小黑慌得一批,東扯西扯了幾句后,面試官也看出小黑關(guān)于存儲(chǔ)的知識(shí)邊界了,很有禮貌地不再追問(wèn)了。
出于友好禮節(jié),問(wèn)了幾個(gè)小黑簡(jiǎn)歷上的東西,最后結(jié)束了這場(chǎng)面試。
大白聽(tīng)完也有點(diǎn)慌,故作鎮(zhèn)定說(shuō):"黑哥,你這幾個(gè)問(wèn)題都比較典型,周末寫(xiě)一篇文章,給你講講這塊東西。"
小黑笑道:"哈哈哈,就等你這個(gè)呢,老規(guī)矩周五放松一下!上周恰燒烤了,這周恰個(gè)火鍋唄"
害,大白和小黑真是吃喝二人組啊,言歸正傳,開(kāi)始NoSQL之旅吧!
2. 大器晚成NoSQL
NoSQL一詞最早出現(xiàn)于1998年,受限于當(dāng)時(shí)的技術(shù)場(chǎng)景和應(yīng)用情況,并沒(méi)有折騰出什么大浪,但是在2009年NoSQL再次被提出,這一次出場(chǎng)有點(diǎn)炸裂,頗有明日之星的趕腳。
一般來(lái)說(shuō),這事行不行往往和口號(hào)有很大關(guān)系,像我大白的口號(hào)就是:人生實(shí)苦,早點(diǎn)退休。
2009年在亞特蘭大的一次重要會(huì)議上對(duì)NoSQL提出了個(gè)文雅&響亮的口號(hào):
select?fun,?profit?from?real_world where relational=false;
本質(zhì)上NoSQL是一類(lèi)數(shù)據(jù)庫(kù)的泛稱,具體的可以分為以下幾種:
本文只介紹鍵值對(duì)key-value型數(shù)據(jù)庫(kù),先看下NoSQL名字的來(lái)源和含義的幾種解讀吧:
-
解讀一
NoSQL 意為"No SQL" 翻譯為SQL已死。潛臺(tái)詞是這類(lèi)數(shù)據(jù)庫(kù)沒(méi)有SQL語(yǔ)句,摒棄了老大哥MySQL的路子,讓它退休。
嚯,好家伙,口氣不小,事實(shí)證明,這種"SQL已死"的自信確實(shí)有點(diǎn)扯犢子了。
-
解讀二
NoSQL 意為"Not Only SQL",顯然沒(méi)有那么囂張了,倒添了幾分謙虛,不僅僅是SQL,除了繼承了老大哥MySQL的一些功能,還增加了新東西,聽(tīng)起來(lái)還不錯(cuò)的樣子。
-
解讀三
NoSQL本質(zhì)上是非關(guān)系型數(shù)據(jù)庫(kù),我們都知道關(guān)系型數(shù)據(jù)庫(kù)一般縮寫(xiě)為RDS或者RDB,所以有人覺(jué)得NoSQL應(yīng)該稱為"No Relational Database",簡(jiǎn)稱"沒(méi)關(guān)系數(shù)據(jù)庫(kù)"。
綜上,我們更傾向于NoSQL為"Not Only SQL",作為關(guān)系型數(shù)據(jù)庫(kù)的補(bǔ)充而存在的一種新形式的數(shù)據(jù)庫(kù)。
3. 給NoSQL一首歌的時(shí)間
工欲善其事 必先利其器,大家都這么忙,必須要給個(gè)學(xué)習(xí)NoSQL的理由。
我們?cè)囅霂追N熟悉的場(chǎng)景(點(diǎn)擊查看大圖):
-
場(chǎng)景一
Leader大熊給小黑一個(gè)需求,這個(gè)需求在幾千萬(wàn)行的MySQL中加個(gè)字段,由于是生產(chǎn)環(huán)境需要找DBA手動(dòng)執(zhí)行,好家伙排隊(duì)大半天才給執(zhí)行,給小黑氣的,太耽誤事了太不方便了。
-
場(chǎng)景二
Leader大熊又給了小黑一個(gè)需求,讓他存儲(chǔ)一個(gè)數(shù)據(jù)包,數(shù)據(jù)包其實(shí)是Json的串,里面有很多字段,但是現(xiàn)在也不明確PM要怎么用,字段是否會(huì)調(diào)整,所以用MySQL存儲(chǔ)的話,字段還不能確定,于是小黑加了個(gè)extra字段來(lái)存儲(chǔ)后續(xù)的擴(kuò)展,暫時(shí)解決了。
-
場(chǎng)景三
Leader大熊讓小黑設(shè)計(jì)一個(gè)并發(fā)訪問(wèn)大一些的服務(wù),來(lái)完成用戶賬號(hào)體系查詢,目前差不多有4億賬號(hào)ID,大熊搞了C++服務(wù)&存儲(chǔ)選擇了MySQL,性能怎么也提不上去,真是一籌莫展。
MySQL橫行江湖數(shù)十載,無(wú)人匹敵,尤其在事務(wù)、數(shù)據(jù)一致性、關(guān)聯(lián)查詢等場(chǎng)景具有絕對(duì)的統(tǒng)治力,確實(shí)是數(shù)據(jù)庫(kù)藍(lán)波萬(wàn)。
科技進(jìn)步和新常用新形式的出現(xiàn)也讓MySQL有些捉襟見(jiàn)肘,畢竟MySQL不是萬(wàn)金油,要保住地位必須與時(shí)俱進(jìn)才行。
在很多場(chǎng)景中我們并不需要事務(wù)、強(qiáng)數(shù)據(jù)一致性、多表關(guān)聯(lián)等特性,所以我們需要一類(lèi)更輕快的數(shù)據(jù)庫(kù),它就是NoSQL。
4. MySQL vs NoSQL
我們有必要將MySQL和NoSQL進(jìn)行一番對(duì)比,來(lái)加深印象:
-
MySQL是高度組織化結(jié)構(gòu)化的數(shù)據(jù)存儲(chǔ),NoSQL無(wú)結(jié)構(gòu)化存儲(chǔ)
-
MySQL使用結(jié)構(gòu)化查詢語(yǔ)句,NoSQL無(wú)查詢語(yǔ)言
-
MySQL需要定義字段和模式,NoSQL自由擴(kuò)展
-
MySQL海量數(shù)據(jù)時(shí)讀寫(xiě)性能劣于NoSQL
-
MySQL擴(kuò)展性較差
上面這些好像全是diss老大哥MySQL的,但是并不是說(shuō)MySQL很弱,相反是MySQL非常強(qiáng)悍。
高并發(fā)&高可用&高可擴(kuò)展的新要求成就了NoSQL,NoSQL之所以可以應(yīng)對(duì)這些新場(chǎng)景,和它的設(shè)計(jì)思想有很大的關(guān)系。
或許可以用葡萄來(lái)說(shuō)明為啥NoSQL更適用于高并發(fā)場(chǎng)景。
-
NoSQL是一粒一粒的葡萄,存取都非常方便,讀寫(xiě)速度快
-
MySQL是一串葡萄,每一粒都是相互關(guān)聯(lián)的,存取較為麻煩,讀寫(xiě)速度慢
兩類(lèi)數(shù)據(jù)庫(kù)的對(duì)比就說(shuō)這么多,我們來(lái)看看幾款大白在實(shí)際工作中用過(guò)的NoSQL吧!
5. NoSQL明星項(xiàng)目
開(kāi)源的NoSQL非常多,大白按照層次挑幾個(gè)典型的代表來(lái)和大家分享一下。
NoSQL可以是單機(jī)的,也可以是分布式的,可以根據(jù)自己的目的來(lái)使用。
今天要介紹的幾款數(shù)據(jù)庫(kù):Redis、Pika、SSDB、RocksDB、LevelDB。
其中LevelDB是谷歌開(kāi)發(fā)的,RocksDB是Facebook在LevelDB的基礎(chǔ)上增加新特性開(kāi)發(fā)的,Redis則不用多說(shuō),SSDB和Pika則是國(guó)內(nèi)開(kāi)源的類(lèi)Redis的數(shù)據(jù)庫(kù),也非常棒。
接下來(lái)看看這幾款數(shù)據(jù)庫(kù)的特點(diǎn)、聯(lián)系、底層原理等有趣的東西。
5.1 谷歌出品LevelDB
LevelDB是谷歌的Sanjay Ghemawat和Jeff Dean使用C++開(kāi)發(fā)的單進(jìn)程/單機(jī)版持久化的key-value數(shù)據(jù)庫(kù),于2011年7月開(kāi)源,可以說(shuō)是重磅產(chǎn)品。
LevelDB支持了最基礎(chǔ)的key-value操作:Get/Put/Delete,但是并沒(méi)有封裝其他的東西,嚴(yán)格意義上來(lái)說(shuō)只是NoSQL存儲(chǔ)引擎。
一般來(lái)說(shuō),機(jī)械磁盤(pán)最害怕的就是隨機(jī)讀寫(xiě),磁盤(pán)呼嚕嚕轉(zhuǎn)起來(lái)就意味著讀寫(xiě)效率在下降。
LevelDB具有很高的隨機(jī)寫(xiě),順序讀/寫(xiě)性能,因此LevelDB很適合應(yīng)用在寫(xiě)多讀少的場(chǎng)景,真讓人好奇高性能的隨機(jī)寫(xiě)怎么做到的。
5.1.1 LSM樹(shù)
很多數(shù)據(jù)在邏輯上相近,但是在物理存儲(chǔ)上卻可能相隔很遠(yuǎn),這樣就會(huì)造成大量的隨機(jī)讀寫(xiě)問(wèn)題,從而降低性能。
LevelDB實(shí)現(xiàn)高性能隨機(jī)寫(xiě)的秘密武器在于使用LSM樹(shù)存儲(chǔ)結(jié)構(gòu),LSM樹(shù)又稱為日志結(jié)構(gòu)合并樹(shù)(Log-Structured Merge-Tree),它并不是具體的數(shù)據(jù)結(jié)構(gòu),而是一種設(shè)計(jì)思想。
LSM樹(shù)對(duì)于每次寫(xiě)入操作,并不是直接將最新的數(shù)據(jù)駐留在磁盤(pán)中,而是將數(shù)據(jù)先放在內(nèi)存。
當(dāng)內(nèi)存數(shù)據(jù)達(dá)到一定的閾值,再將這部分?jǐn)?shù)據(jù)真正刷新到磁盤(pán)文件中,從而將磁盤(pán)隨機(jī)寫(xiě)轉(zhuǎn)換為內(nèi)存順序?qū)?,因而獲得了極高的寫(xiě)性能,但是這種機(jī)制會(huì)降低讀的性能,總體來(lái)說(shuō)降低部分讀性能來(lái)大幅提升寫(xiě)性能是值得的。
5.1.2 LevelDB整體架構(gòu)
LevelDB 存儲(chǔ)結(jié)構(gòu)主要由六個(gè)部分組成:
-
MemTable:內(nèi)存數(shù)據(jù)結(jié)構(gòu),使用SkipList實(shí)現(xiàn),新的數(shù)據(jù)修改會(huì)首先在這里寫(xiě)入,并且有容量限制。
-
Immutable MemTable:待落盤(pán)的數(shù)據(jù)庫(kù)內(nèi)存結(jié)構(gòu),當(dāng) MemTable的大小達(dá)到設(shè)定的閾值時(shí),會(huì)變成 Immutable MemTable,只接受讀操作,不再接受寫(xiě)操作,后續(xù)會(huì)Flush到磁盤(pán)上。
-
SST Files:Sorted String Table Files,磁盤(pán)數(shù)據(jù)存儲(chǔ)文件,分為 Level0 到 LevelN 多層,每一層包含多個(gè) SST 文件,文件內(nèi)數(shù)據(jù)有序。
-
Manifest Files:leveldb元信息清單文件。Manifest記錄 SST 文件在不同 Level 的分布,相當(dāng)于SST文件的索引。
-
Current File:當(dāng)前正在使用的文件清單文件。
LevelDB的讀寫(xiě)過(guò)程和上述的整體架構(gòu)關(guān)系密切,也是先內(nèi)存后磁盤(pán),一層層讀取搜索數(shù)據(jù)的。
5.2 臉書(shū)出品RocksDB
青出于藍(lán)而勝于藍(lán)。
RocksDB在LevelDB的基礎(chǔ)上進(jìn)行了改進(jìn)和優(yōu)化,也成為后續(xù)很多NoSQL所選擇的存儲(chǔ)引擎。
RocksDB仍然是采用C++開(kāi)發(fā)的,并且完全向后兼容了LevelDB的接口,可以說(shuō)是個(gè)平滑升級(jí)。
5.2.1 RocksDB提升點(diǎn)
來(lái)看看RocksDB做了哪些優(yōu)化和提升:
-
RocksDB支持一次 獲取多個(gè)Key,還支持Key范圍查找,LevelDB只能獲取單個(gè)Key。
-
RocksDB支持 多線程合并,而LevelDB是單線程合并的,多核時(shí)代前者效率更高。
-
RocksDB增加了 合并時(shí)過(guò)濾器,對(duì)不符合條件的Key進(jìn)行丟棄。
-
RocksDB可采用 多種壓縮算法,除了LevelDB用的snappy,還有zlib、bzip2。
-
RocksDB支持 增量備份和全量備份。
-
RocksDB支持管道式的Memtable,使用 多個(gè)Memtable,LevelDB只有一個(gè)Memtable。
5.2.2 RocksDB整體架構(gòu)
Rocksdb中引入了Column Family(列族的概念,所謂列族也就是一系列kv組成的數(shù)據(jù)集,所有的讀寫(xiě)操作都需要先指定列族。
每個(gè)ColumnFamily有自己的Memtable, SST文件,所有ColumnFamily共享WAL、Current、Manifest文件。
如果說(shuō)LevelDB是個(gè)平民版的NoSQL存儲(chǔ)引擎,那么RocksDB絕對(duì)是尊享版,所以很多優(yōu)秀的NoSQL成品都是基于RocksDB來(lái)封裝上層協(xié)議和代理支持完成的。
5.3 ideawu的SSDB
SSDB是基于SSD作為底層存儲(chǔ)介質(zhì)的類(lèi)Redis數(shù)據(jù)庫(kù)。
Redis過(guò)于迷人和好用,但是又太昂貴了,所以我們幻想著有一款支持Redis數(shù)據(jù)結(jié)構(gòu)且容量沒(méi)限制的數(shù)據(jù)庫(kù)。
這種數(shù)據(jù)庫(kù)將Redis的數(shù)據(jù)結(jié)構(gòu)優(yōu)勢(shì)和廉價(jià)磁盤(pán)介質(zhì)聯(lián)合起來(lái),著實(shí)讓人著迷。
沒(méi)錯(cuò),SSDB就是這樣一款NoSQL數(shù)據(jù)庫(kù)。
目前SSDB的維護(hù)者并不是特別多,并且在集群化等方面還存在一些問(wèn)題,不過(guò)也算是非常優(yōu)秀的開(kāi)源NoSQL了。
來(lái)簡(jiǎn)單看下SSDB的基本架構(gòu):
簡(jiǎn)單來(lái)說(shuō),SSDB在LevelDB和Redis協(xié)議之間做了一層轉(zhuǎn)換,從而實(shí)現(xiàn)命令和數(shù)據(jù)的切換,這就是使用存儲(chǔ)引擎之前封裝附加部分,從而形成完整的NoSQL。5.4 360出品Pika
其實(shí)SSDB和Pika很有淵源,SSDB的作者曾經(jīng)在360工作,并且SSDB當(dāng)時(shí)在360的生產(chǎn)環(huán)境中使用廣泛,Pika數(shù)據(jù)庫(kù)是360基于RocksDB開(kāi)發(fā)的集群化高性能NoSQL。
Pika是360DBA團(tuán)隊(duì)和基礎(chǔ)架構(gòu)團(tuán)隊(duì)使用C++語(yǔ)言聯(lián)合開(kāi)發(fā)的類(lèi)Redis存儲(chǔ)系統(tǒng),所以完全支持Redis協(xié)議。
Pika是一個(gè)可持久化的大容量Redis存儲(chǔ)服務(wù),解決Redis由于存儲(chǔ)數(shù)據(jù)量巨大而導(dǎo)致內(nèi)存不夠用的容量瓶頸,并且支持全同步和部分同步。
Pika還提供了遷移工具,實(shí)現(xiàn)Redis數(shù)據(jù)到Pika的平滑遷移,Pika的定位目標(biāo)并不是取代redis, 而是作為redis的補(bǔ)充,在性能上肯定會(huì)低于Redis。
從整體架構(gòu)可知,Pika是多線程實(shí)現(xiàn)的,因此對(duì)多核使用效率更高,雖然單線程性能不如Redis,但是多個(gè)線程一起上性能也還不錯(cuò)。
Pika目前在360內(nèi)部使用非常廣泛,在一些其他的互聯(lián)網(wǎng)公司也有使用。
說(shuō)到底NoSQL是一個(gè)實(shí)踐類(lèi)的項(xiàng)目,本文也不能講述太多,否則很空洞,意義不大。
5.5 其他NoSQL
基本上很多互聯(lián)網(wǎng)公司都會(huì)基于LevelDB或者RocksDB開(kāi)發(fā)一款自己的Key-Vaule數(shù)據(jù)庫(kù),有的只支持簡(jiǎn)單的string結(jié)構(gòu),有的完全兼容Redis協(xié)議和客戶端。
大都是解析Redis協(xié)議、使用Redis的客戶端、增加一層命令解析和數(shù)據(jù)格式解析層、再有可能有多線程支持&主從化&集群化等。
自己開(kāi)發(fā)一款簡(jiǎn)單的NoSQL,可以極大提升自己對(duì)于NoSQL的理解,在github上有很多這樣的項(xiàng)目,可以參考學(xué)習(xí)下。
6. 本文小結(jié)
本文粗淺闡述了NoSQL的一些相關(guān)知識(shí)點(diǎn),以及一些筆者實(shí)踐過(guò)的NoSQL。
大致原理本質(zhì)上差不多,但是要打造一款高性能&高可用的工業(yè)級(jí)NoSQL是非常困難的。
最后依然是感謝各位的傾情安排,大家周末愉快!
另外還有兩位中獎(jiǎng)的朋友沒(méi)有聯(lián)系我,一周內(nèi)有效抓緊哈!點(diǎn)擊查看:昨天恰飯了,今天送5本書(shū),感謝大家的理解和支持
往期精彩:
圖解|為什么HTTP3.0使用UDP協(xié)議
圖解|通用搜索引擎背后的技術(shù)點(diǎn)
圖解|什么是一致性哈希算法
圖解|什么是緩存系統(tǒng)三座大山
圖解|什么是缺頁(yè)錯(cuò)誤Page Fault
圖解|什么是RSA算法
免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺(tái)僅提供信息存儲(chǔ)服務(wù)。文章僅代表作者個(gè)人觀點(diǎn),不代表本平臺(tái)立場(chǎng),如有問(wèn)題,請(qǐng)聯(lián)系我們,謝謝!