日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

映射的存储模型

發(fā)布時間:2024/9/30 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 映射的存储模型 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

http://blog.sina.com.cn/s/blog_693f08470101ovfp.html

http://blog.sina.com.cn/s/blog_693f08470101omuq.html

映射的存儲模型??面向列的存儲和行存儲

?


1個月沒跟大家見面了,這個月真的是很累,做了很多事,天天加班,不過結(jié)還都不錯,以后調(diào)休吧?~

11不知道各位感覺如何?是不是覺得很平穩(wěn)呢??在這次雙11?里面,中間件團(tuán)隊配合業(yè)務(wù)團(tuán)隊使用了一種全新的全鏈路壓測方式進(jìn)行了線上性能驗證,提前就預(yù)演了所有可能的壓力,因此這次雙?11是我五年雙11?支持過程中最淡定的一次?~

?


然后,又使用了阿里中間件的全部技術(shù)支持了某大型公司的企業(yè)的業(yè)務(wù)邏輯重構(gòu)。讓他們的系統(tǒng)業(yè)務(wù)架構(gòu)有了一次全新的變化,讓他們的系統(tǒng)具備了自由擴(kuò)展的能力,從此不再擔(dān)心系統(tǒng)無法支持用戶增長了。順便也就驗證了我們解決問題的整體思路是一個可復(fù)制的思路,將會在未來有更廣闊的發(fā)展空間??玩法變了啊,各位感受到了么?

?


好,話題回到模型上,今天我們開啟一個新的主題,就是映射的存儲模型。換句話說,在了解了?k-v的基本機(jī)制之后,下一步我們研究一下我們的數(shù)據(jù)應(yīng)該如何使用映射。


回顧一下映射,映射的本質(zhì)就是一個?map,給出map?key?map就返回key?所對應(yīng)的?value。我們也介紹過,在計算機(jī)里的大部分事情其實都可以被表示為一個?map,比如,給定扇區(qū)號,返回給定扇區(qū)的數(shù)據(jù)等等。

?


我們已經(jīng)知道了?Map,而在這里我們最需要解決的問題就是,給定一組數(shù)據(jù),應(yīng)該如何存放到我們的映射里呢?其實存放的方法非常多樣,而核心的問題是用戶的實際需求。

?


這里我們需要舉個例子,假定目前我們需要存儲的數(shù)據(jù)是一組數(shù)據(jù)。

bizOrderID

sellerID

buyerId

content

0

0

4

‘a(chǎn)’

1

0

3

‘c’

2

0

2

‘I’

3

0

1

‘d’

4

3

4

‘b’

5

2

4

‘f’

?

?

針對這樣一組數(shù)據(jù),我們其實是有很多種不同的存儲方式的。

?

第一種,以pk作為key,以其他數(shù)據(jù)作為value?

Map

Key

Value

{bizOrderId:0}

{sellerID:0,buyerId:4,content:’a’}

{bizOrderId:1}

{sellerID:0,buyerId:3,content:’c’}

{bizOrderId:2}

{sellerID:0,buyerId:2,content:’i’}

{bizOrderId:3}

{sellerID:0,buyerId:1,content:’d’}

{bizOrderId:4}

{sellerID:3,buyerId:4,content:’b’}

{bizOrderId:5}

{sellerID:2,buyerId:4,content:’f’}

?

可以看出,在這種存儲的實現(xiàn)中,每一行的數(shù)據(jù)都冗余了列的名字和該列所對應(yīng)的類型信息。

這種方式有個專用的名詞,就叫面向列的存儲,當(dāng)然,雖然出現(xiàn)了“列”字,但各位可千萬不要望文生義,這面向列的存儲,跟我們后面要看到的列存基本不沾邊。。

這種存儲方式,最大的好處就是每個value里面的數(shù)據(jù)可以完全自己定義,目前主流的實現(xiàn)是使用json來存儲value數(shù)據(jù),這樣,如果業(yè)務(wù)要求增加一個列,那就在json拼裝的時候額外增加一個列就行了。而如果業(yè)務(wù)需要減少一個列,也可以直接在代碼里拼裝,減少了運維的成本。

不過這樣做也不是完全沒有代價,額外的冗余數(shù)據(jù)就意味著額外的空間消耗,所以目前通用的優(yōu)化方案,利用了列的個數(shù)本身是比較有限的,這個特性,于是利用一個新的map_bit. Key為列的名字,value為一個bit .?從而減少冗余數(shù)據(jù)帶來的過多空間消耗。如下:

Map_bit

Key

Value(bit)

sellerID

‘a(chǎn)’

bizOrderId

‘b’

buyerId

‘c’

content

‘d’

?

Map

Key

Value

{b:0}

{a:0,c:4,d:’a’}

{b:1}

{a:0,c:3,d:’c’}

{b:2}

{a:0,c:2,d:’i’}

{b:3}

{a:0,c:1,d:’d’}

{b:4}

{a:3,c:4,d:’b’}

{b:5}

{a:2,c:4,d:’f’}

?

有了這么個結(jié)構(gòu),面向列的存儲里面數(shù)據(jù)冗余的大問題得到了部分的解決,然而這種模式還有優(yōu)化的空間。在大部分情況下,我們的業(yè)務(wù)模型基本上是穩(wěn)定的,不會過于頻繁的發(fā)生變化。如果我們能夠有這樣的假定,那么我們就可以將列所對應(yīng)的位置固定下來,用一個叫map_schema的表格來存儲,不就不需要冗余上面的那些’a’,’b’,’c’,’d’bit信息了。可以更多地節(jié)省存儲空間啊。

map_schema

Key

Value

sellerID

表格內(nèi)的位置:1

bizOrderId

表格內(nèi)的位置:0

buyerId

表格內(nèi)的位置:2

content

表格內(nèi)的位置:3

?

Map

0

0

4

‘a(chǎn)’

1

0

3

‘c’

2

0

2

‘I’

3

0

1

‘d’

4

3

4

‘b’

5

2

4

‘f’

?

這種方式就是我們最常見的行存了,這種方式的比較于面向列的存儲,最主要的優(yōu)勢就是空間消耗更少,而且申請空間的效率更高,因為用戶在開始的時候就已經(jīng)指定了所有數(shù)據(jù)所需要的數(shù)據(jù)類型(空間消耗),因此消耗的空間是相對比較固定的。

而對于面向列的存儲而言,由于不能提前假定每一行數(shù)據(jù)的大小,所以只能使用變長數(shù)據(jù)存儲格式來存儲數(shù)據(jù)。?因此也會有更多的空間浪費,并且提高申請存儲空間的代價。

無論是面向列的存儲,還是行存,他們的寫入都可以只通過一次map.put(key,value)就可以完成。所以寫入的效率比較高,如果按照pk這一列做查詢,速度也會非常快,因為也只需要一個map.get(key)就可以取出需要的數(shù)據(jù),速度自然也就是很快的。


上上周我們討論了行存儲,那么現(xiàn)在呢我們來看看列存的存儲方式

?

在一個文件塊內(nèi)是能夠放多個數(shù)據(jù)的,行存的存儲方式是一個文件塊內(nèi)放置多行的數(shù)據(jù)。而列存,顧名思義,就是一個文件塊內(nèi)放置多列的數(shù)據(jù)了唄~~

?

舉個例子:

對上面的那張表,如果我們按照列的方式存儲到映射里,應(yīng)該如何存儲呢?

首先,我們需要一個映射map_columns來存儲每個列的具體映射表是哪個。

?

?

Map_columns

Key

Value(bit)

sellerID

Map_sellerID

bizOrderID

Map_bizOrderID

buyerID

Map_buyerID

content

Map_content

?

第一組數(shù)據(jù),用于存儲sellerID的映射關(guān)系。當(dāng)然真實存儲的時候,不需要去存儲keybizOrderID這個信息的,因為這是所有列存所必須遵守的,而對于value而言,Map的名字其實就標(biāo)記了這組映射的value值的所有信息,所以也不需要記錄的,這里用()標(biāo)記出來,主要是為了方便理解

Map_sellerID

Key(bizOrderID)

Value(sellerID)

0

0

1

0

2

0

3

0

4

3

?

第二組數(shù)據(jù)(buyerID),同樣的,數(shù)據(jù)的類型信息在Map_columns里面就記錄好了。這里直接記錄真正的數(shù)據(jù)就行了。

Map_buyerID

Key(bizOrderID)

Value(buyerID)

0

4

1

3

2

2

3

1

4

4

5

4

?

第三組數(shù)據(jù)(content)

Map_content

Key(bizOrderID)

Value(buyerID)

0

‘a(chǎn)’

1

‘c’

2

‘I’

3

‘d’

4

‘b’

5

‘f’

?

?

在介紹了列存這種數(shù)據(jù)結(jié)構(gòu)之后,我們來與行存做一個比較分析,來去看看為什么列存和行存會有完全不同的一些技術(shù)特性。

?

數(shù)據(jù)結(jié)構(gòu)這種東西,沒有一種能夠解決所有的問題,更多地時候是在各種權(quán)衡和妥協(xié)中找到一個平衡點的過程,對于行存和列存,這東西也是一樣的。。

?

古人云~任何不帶使用場景討論的數(shù)據(jù)結(jié)構(gòu)優(yōu)缺點分析都是耍流氓。

我們需要先看看用戶怎么用我們的存儲的。

應(yīng)用總是希望快速的完成數(shù)據(jù)的寫入得,而用戶一般來說一定是按照整行的方式進(jìn)行數(shù)據(jù)的寫入,因為這是用戶正常組織數(shù)據(jù)的方式嘛。。。

?

空間分析:

?????????對行存儲來說,壓縮一般是按照塊來進(jìn)行的,常見的壓縮方式的核心思想其實也并不復(fù)雜。

?????????第一個思路是字典壓縮,也就是將固定的bytes序列換成更小的一個bit來表示,這樣就可以用更小的空間來存儲更多地內(nèi)容了,比如人類在這世界上只有三種性別,所以字典只需要2bit(存儲四個type),所以就算人類人口成長到了100億,每一個人還是只需要兩個bit就可以存儲嘛。

?????????第二個思路就是bitMap(目前很熱的bloomFilter其實也是bitmap思想的一個特例),所謂bitMap,是利用bit數(shù)組的下標(biāo)的true(1)/false(0)來標(biāo)記某個數(shù)字是否已經(jīng)存入到這個數(shù)組內(nèi)。

比如,要存儲0,3,5,8四個數(shù)字,所有數(shù)字的最大值是8.那么我們可以建立一個bitMap來存儲這組數(shù)字:

true(1)/false(0)

1

0

0

1

0

1

0

0

1

位置

0

1

2

3

4

5

6

7

8

?

這樣,我們只需要一個bit數(shù)組就可以存儲原來需要多個bytes才能存儲的多組數(shù)字了。

?

?

基本上來說,壓縮的核心思路就是有機(jī)的結(jié)合上面這兩個元素,結(jié)合各種映射關(guān)系來完成數(shù)據(jù)壓縮的。

在這個壓縮核心思想的基礎(chǔ)上,還有很多擴(kuò)展的方法,最主要的方式就是把bitMapBtree結(jié)合進(jìn)行壓縮,bitMap用來表示某個數(shù)據(jù)在整個數(shù)組內(nèi)的重復(fù)出現(xiàn)的具體位置是哪些,又因為有多個數(shù)據(jù),所以在bitMap上面再套一個btree,用來幫助尋找某個key是否存在,以及如果存在的話,具體位置有哪些。

?

可以發(fā)現(xiàn),壓縮比率很高的場景,一般來說都是數(shù)值類型的東西。所以如果你把一大組數(shù)值類的數(shù)據(jù)放在一起,并且這個數(shù)值類的數(shù)據(jù)重復(fù)度很高,或者比較有規(guī)律,那么做壓縮的效果一般來說就會很好。

?

然而,對于行存儲來說就以我們的一行數(shù)據(jù)為例:

bizOrderID

sellerID

buyerId

content

0

0

4

‘a(chǎn)’

這行數(shù)據(jù)里又出現(xiàn)了數(shù)字,又有字符,那么這種場景下就很難選擇完全使用數(shù)值類壓縮方式來做,而只能選擇字典壓縮了,很容易想象,字典壓縮因為是通用壓縮法,所以壓縮比率也就比較一般了。。

而對于行存儲而言,這方面就能獲得很大的好處,因為數(shù)值類的數(shù)據(jù)被物理的放在一起了,而且性別啊,門牌號啊,電話號碼啊這類明顯有一定規(guī)律的數(shù)據(jù)被物理上的放在了一起,所以壓縮效果好那就是自然而然的事情咯~

?

一般來說,行存儲的壓縮比率大概是1:1.5~2左右頂頭了。?也就是能減少一倍的數(shù)據(jù)量。而對于列存儲而言,大部分情況下列存儲的壓縮都能在1:20 ~ 1:30?以上,極大的減少了空間消耗。

空間消耗的減少意味著什么?原來必須存在磁盤的“大數(shù)據(jù)”現(xiàn)在可以用更少的機(jī)器,甚至是單機(jī)就可以搞定,節(jié)省機(jī)器成本,同時還能提升一個重要的指標(biāo),我們下面就立刻分析一下。

?

寫入效率分析:

?????????對于行存儲來說,一行數(shù)據(jù)的寫入就對應(yīng)了一個map.put操作,所以效率自然是很高。

?????????而對于列存儲來說,一行數(shù)據(jù)的寫入,假設(shè)這個數(shù)據(jù)列有4列,那么就會對應(yīng)4map.put操作,如果有6列,那么就對應(yīng)6map.put操作。效率低于列存。

?

?????????然而,這并不是絕對的,讓我們把條件稍微做個變換,效果就會立刻不同,如果用戶不需要單次寫入后立刻返回,而是可以一次寫入100條以上的數(shù)據(jù),那么形勢就會立刻發(fā)生逆轉(zhuǎn)!

?????????因為列存是將壓縮后的數(shù)據(jù)寫入磁盤的,聯(lián)想壓縮比率,原來需要寫20mb的數(shù)據(jù),現(xiàn)在可能只寫1mbcpu和內(nèi)存相比,磁盤目前仍然是整個系統(tǒng)的核心瓶頸,而且差距很大,因此減少硬盤寫入就直接的減少了寫入一組數(shù)據(jù)所需要的時間。

?????????因此,列存在數(shù)據(jù)導(dǎo)入的場景下?lián)碛羞h(yuǎn)遠(yuǎn)快于行存儲的數(shù)據(jù)寫入速度也就不足為奇了。

?

那么,想不想知道行存,列存是如何解決各類用戶奇葩的多維度查詢需求的??下一篇我們將進(jìn)入這一領(lǐng)域進(jìn)行探索。


總結(jié)

以上是生活随笔為你收集整理的映射的存储模型的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。