Redis 數(shù)據(jù)結(jié)構(gòu)與內(nèi)存管理策略(上)

Redis 數(shù)據(jù)類型特點與使用場景

redis?為我們提供了?5?種數(shù)據(jù)類型畦木,基本上我們使用頻率最高的就是?string?蛆封,而對其他四種數(shù)據(jù)類型使用的頻次稍弱于?string?惨篱。

一方面是由于?string?使用起來比較簡單砸讳,可以方便存儲復(fù)雜大對象簿寂,使用場景比較多陶耍。還有一個原因就是由于?redis expire time?只能設(shè)置在?key?上泊碑,像?list馒过、hash腹忽、set嘹锁、zset?屬于集合類型领猾,會管理一組?item摔竿,我們無法在這些集合的?item?上設(shè)置過期時間继低,所以使用?expire time?來處理集合的?cache?失效會變得稍微復(fù)雜些冷溃。但是?string?使用?expire time?來管理過期策略會比較簡單似枕,因為它包含的項少凿歼。這里說的集合是寬泛的類似集合答憔。

導(dǎo)致我們習慣性的使用?string?而忽視其他四種數(shù)據(jù)類型的另一個深層次原因,大多是由于我們對另外四種數(shù)據(jù)類型的使用和原理不是太了解傲武。這個時候往往會忽視在特定場景下使用某種數(shù)據(jù)類型可能會比?string?性能高出很多态兴,比如使用?hash?結(jié)構(gòu)來提高某個實體的某個項的修改等瞻润。

這里我們不打算羅列這?5?種數(shù)據(jù)類型的使用方法绍撞,這些資料網(wǎng)上有很多傻铣。我們主要討論這?5?種數(shù)據(jù)類型的功能特點,這些特點分別適合用于處理哪些現(xiàn)實的業(yè)務(wù)場景就谜,最重要的是我們?nèi)绾谓M合性的使用這?5?種數(shù)據(jù)類型來解決復(fù)雜的?cache?問題缆瓣。

String弓坞、List渡冻、Hash族吻、Set砍艾、Zset

String

string?是?redis?提供的字符串類型脆荷◎涯保可以針對?string?類型獨立設(shè)置?expire time?孤澎。通常用來存儲長字符串數(shù)據(jù),比如岖妄,某個對象的?json?字符串。

string?類型我們在使用上最巧妙的是可以動態(tài)拼接?key丸凭。通常我們可以將一組?id?放在?set?里惜犀,然后動態(tài)查找?string?還是否存在汽烦,如果不存在說明已經(jīng)過期或者由于數(shù)據(jù)修改主動?delete?了撇吞,需要再做一次?cache?數(shù)據(jù)?load?。

雖然?set?無法設(shè)置?item?的過期時間迄薄,但是我們可以將?set item?與?string key?關(guān)聯(lián)來達到相同的效果讥蔽。

上圖中的左邊是一個?key?為?set:order:ids?的?set?集合,它可能是一個全量集合碰缔,也可能是某個查詢條件獲取出來的一個集合金抡。

有時候復(fù)雜點的場景需要多個?set?集合來支撐計算梗肝,在?redis 服務(wù)器?里可能會有很多類似這樣的集合巫击。

這些集合我們可以稱為?功能數(shù)據(jù)坝锰,這些數(shù)據(jù)是用來輔助?cache?計算的顷级,當進行各種集合運算之后會得出當前查詢需要返回的子集弓颈,最后我們才會去獲取某個訂單真正的數(shù)據(jù)。

這些?string:order:{orderId}?字符串?key?并不一定是為了服務(wù)一種場景橘蜜,而是整個系統(tǒng)最底層的數(shù)據(jù),各種場景最后都需要獲取這些數(shù)據(jù)跌捆。那些?set?集合可以認為是查詢條件數(shù)據(jù)佩厚,用來輔助查詢條件的計算。

redis?為我們提供了?TYPE?命令來查看某個?key?的數(shù)據(jù)類型陶冷,如:string?類型:

SETstring:order:100order-100TYPEstring:order:100string

List

list?在提高?throughput?的場景中非常適用煞额,因為它特有的?LPUSH膊毁、RPUSH婚温、LPOP栅螟、RPOP?功能可以無縫的支持生產(chǎn)者嵌巷、消費者架構(gòu)模式。

這非常適合實現(xiàn)類似?Java Concurrency?Fork/Join?框架中的?work-stealing 算法 (工作竊取)?坪圾。

java fork/join?框架使用并行來提高性能兽泄,但是會帶來由于并發(fā)?take task?帶來的?race condition (競態(tài)條件)?問題病梢,所以采用?work-stealing 算法?來解決由于競爭問題帶來的性能損耗觅彰。

上圖中模擬了一個典型的支付?callback?峰值場景。在峰值出現(xiàn)的地方一般我們都會使用加?buffer?的方式來加快請求處理速度飒责,這樣才能提高并發(fā)處理能力宏蛉,提高?throughput?拾并。

支付?gateway?收到?callback?之后不做任何處理直接交給?分發(fā)器?。分發(fā)器?是一個無狀態(tài)的?cluster?芥喇,每個?node?通過向?注冊中心?pull handler queue list继控,也就是獲取下游處理器注冊到注冊中心里的消息通道武通。

每一個分發(fā)器?node?會維護一個本地?queue list?,然后順序推送消息到這些?queue list?即可囚枪。這里會有點小問題劳淆,就是?支付?gateway?調(diào)用分發(fā)器的時候是如何做?load balance?沛鸵,如果不是平均負載可能會有某個?queue list?高出其他?queue list?奈辰。

而分發(fā)器不需要做?soft load balance?冯挎,因為哪怕某個?queue list?比其他?queue list?多也無所謂房官,因為下游?message handler?會根據(jù)?work-stealing?算法來竊取其他消費慢的?queue list?续滋。

redis list 的?LPUSH蜡峰、RPUSHLPOP油航、RPOP?特性確實可以在很多場景下提高這種橫向擴展計算能力怀浆。

Hash

hash?數(shù)據(jù)類型很明顯是基于?hash?算法的谊囚,對于項的查找時間復(fù)雜度是?O(1)?的,在極端情況下可能出現(xiàn)項?hash?沖突問題执赡,redis?內(nèi)部是使用鏈表加?key?判斷來解決的镰踏。具體?redis?內(nèi)部的數(shù)據(jù)結(jié)構(gòu)我們在后面有介紹,這里就不展開了沙合。

hash?數(shù)據(jù)類型的特點通车煳保可以用來解決帶有映射關(guān)系,同時又需要對某些項進行更新或者刪除等操作芳来。如果不是某個項需要維護挎袜,那么一般可以通過使用?string?來解決全景。

如果有需要對某個字段進行修改炕贵,使用?string?很明顯是會多出很多開銷鳖轰,需要讀取出來反序列化成對象然后操作睛蛛,然后再序列化寫回?redis?客冈,這中間可能還有并發(fā)問題渠缕。

那我們可以使用?redis hash?提供的實體屬性?hash?存儲特性,我們可以認為?hash value?是一個?hash table?,實體的每一個屬性都是通過?hash?得到屬性的最終數(shù)據(jù)索引。

上圖使用?hash?數(shù)據(jù)類型來記錄頁面的?a/b metrics?蹋辅,左邊的是首頁?index?的各個區(qū)域的統(tǒng)計褒傅,右邊是營銷?marketing?的各個區(qū)域統(tǒng)計旋廷。

在程序里我們可以很方便的使用?redis?的?atomic?特性對?hash?某個項進行累加操作扎运。

HMSEThash:mall:page:ab:metrics:indextopbanner10leftbanner5rightbanner8bottombanner20productmore10topshopping8OK

HGETALLhash:mall:page:ab:metrics:index1)"topbanner"2)"10"3)"leftbanner"4)"5"5)"rightbanner"6)"8"7)"bottombanner"8)"20"9)"productmore"10)"10"11)"topshopping"12)"8"

HINCRBYhash:mall:page:ab:metrics:indextopbanner1(integer)11

使用?redis hash increment?進行原子增加操作。HINCRBY?命令可以原子增加任何給定的整數(shù),也可以通過?HINCRBYFLOAT?來原子增加浮點類型數(shù)據(jù)寥茫。

Set

set?集合數(shù)據(jù)類型可以支持集合運算玖喘,不能存儲重復(fù)數(shù)據(jù)澎媒。

set?最大的特點就是集合的計算能力,inter 交集union 并集弛车、diff 差集喻括,這些特點可以用來做高性能的交叉計算或者剔除數(shù)據(jù)。

set?集合在使用場景上還是比較多和自由的微姊。舉個簡單的例子界逛,在應(yīng)用系統(tǒng)中比較常見的就是商品赞别、活動類場景腰埂。用一個?set?緩存有效商品集合,再用一個?set?緩存活動商品集合。如果商品出現(xiàn)上下架操作只需要維護有效商品?set?洁奈,每次獲取活動商品的時候需要過濾下是否有下架商品轮蜕,如果有就需要從活動商品中剔除细燎。

當然寸莫,下架的時候可以直接刪除緩存的活動商品棒拂,但是活動是從?marketing?系統(tǒng)中?load?出來的牢屋,就算我將?cache?里的活動商品刪除,當下次再從?marketing系統(tǒng)中?load?活動商品時候還是會有下架商品赌髓。當然這只是舉例妒貌,一個場景有不同的實現(xiàn)方法拧晕。

上圖中左右兩邊是兩個不同的集合膘盖,左邊是營銷域中的可用商品ids集合最冰,右邊是營銷域中活動商品ids集合,中間計算出兩個集合的交集分冈。

SADDset:marketing:product:available:ids100010010001201000130100014010001501000160

SMEMBERSset:marketing:product:available:ids1)"1000100"2)"1000120"3)"1000130"4)"1000140"5)"1000150"6)"1000160"

SADDset:marketing:activity:product:ids100010010001201000130100014010002001000300

SMEMBERSset:marketing:activity:product:ids1)"1000100"2)"1000120"3)"1000130"4)"1000140"5)"1000200"6)"1000300"

SINTERset:marketing:product:available:idsset:marketing:activity:product:ids1)"1000100"2)"1000120"3)"1000130"4)"1000140"

在一些復(fù)雜的場景中丈攒,也可以使用?SINTERSTORE?命令將交集計算后的結(jié)果存儲在一個目標集合中。 這在使用?pipeline?命令管道中特別有用景殷,將?SINTERSTORE?命令包裹在?pipeline?命令串中可以重復(fù)使用計算出來的結(jié)果集。

由于?redis?是?Signle-Thread 單線程模型?,基于這個特性我們就可以使用?redis?提供的?pipeline 管道?來提交一連串帶有邏輯的命令集合繁成,這些命令在處理期間不會被其他客戶端的命令干擾。

Zset

zset?排序集合與?set?集合類似溯祸,但是?zset?提供了排序的功能种冬。在介紹?set?集合的時候我們知道?set?集合中的成員是無序的,zset?填補了集合可以排序的空隙。

zset?最強大的功能就是可以根據(jù)某個?score 比分值?進行排序堪藐,這在很多業(yè)務(wù)場景中非常急需岖食。比如捐腿,在促銷活動里根據(jù)商品的銷售數(shù)量來排序商品,在旅游景區(qū)里根據(jù)流入人數(shù)來排序熱門景點等复罐。

基本上人們在做任何事情都需要根據(jù)某些條件進行排序双肤。

其實?zset?在我們應(yīng)用系統(tǒng)中能用到地方到處都是,這里我們舉一個簡單的例子遮斥,在團購系統(tǒng)中我們通常需要根據(jù)參團人數(shù)來排序成團列表,大家都希望參加那些即將成團的團。

上圖是一個根據(jù)團購code創(chuàng)建的zset,score 分值?就是參團人數(shù)累加和。

ZADDzset:marketing:groupon:group:codes5G_PXYJY9QQFA8G_4EXMT6NZJQ20G_W7BMF5QC2P10G_429DHBTGZX8G_KHZGH9U4PP

ZREVRANGEBYSCOREzset:marketing:groupon:group:codes100001)"G_W7BMF5QC2P"2)"G_ZMZ69HJUCB"3)"G_429DHBTGZX"4)"G_KHZGH9U4PP"5)"G_4EXMT6NZJQ"6)"G_PXYJY9QQFA"

ZREVRANGEBYSCOREzset:marketing:groupon:group:codes10000withscores1)"G_W7BMF5QC2P"2)"20"3)"G_ZMZ69HJUCB"4)"10"5)"G_429DHBTGZX"6)"10"7)"G_KHZGH9U4PP"8)"8"9)"G_4EXMT6NZJQ"10)"8"11)"G_PXYJY9QQFA"12)"5"

zset?本身提供了很多方法用來進行集合的排序忌穿,如果需要?score?分值可以使用?withscore?字句帶出每一項的分值澜公。

在一些比較特殊的場合可能需要組合排序姆另,可能有多個?zset?分別用來對同一個實體在不同維度的排序喇肋,按時間排序坟乾、按人數(shù)排序等。這個時候就可以組合使用?zset帶來的便捷性蝶防,利用?pipeline?再結(jié)合多個?zset?最終得出組合排序集合甚侣。

案例:滬江團購系統(tǒng)大促?hot-top?接口?cache?設(shè)計

我們總結(jié)了?redis?提供的?5?種數(shù)據(jù)類型的各自特點和一般的使用場景。但是我們不僅僅可以分開使用這些數(shù)據(jù)類型间学,我們完全可以綜合使用這些數(shù)據(jù)類型來完成復(fù)雜的?cache?場景殷费。

下面我們分享一個使用多個?zset?、string?來優(yōu)化?團購系統(tǒng)?前臺接口的例子低葫。由于篇幅和時間限制详羡,這里只介紹跟本次案例相關(guān)的信息。

hot-top?接口是指熱點嘿悬、排名接口的意思实柠,表示它的瀏覽量、并發(fā)量比較高善涨,一般大促的時候都會有幾個這種性能要求比較高的接口窒盐。

我們先來分析一個查詢接口所包含的常規(guī)信息。

首先一個查詢接口肯定是有?query condition 查詢條件?钢拧,然后是?sort 排序信息_ 蟹漓、最后是?page 分頁信息_ 。這是一般接口所承擔的基本職責源内,當然葡粒,特殊場景下還需要支持?master/slave replication?時關(guān)于數(shù)據(jù)?session 一致性?的要求,需要提供跟蹤標記來回?master?查詢數(shù)據(jù)姿锭,這里就不展開了塔鳍。

我們可以抽象出這幾個維度的信息:

query condition

查詢條件,companyid=100呻此,sellerid=1010101 諸如此類轮纫。

sort

排序信息,一般是默認一個列排序焚鲜,但是在復(fù)雜的場景下會有可能讓接口使用者定制排序字段掌唾,比如一些租戶信息列。

page

分頁信息忿磅,簡單理解就是數(shù)據(jù)記錄排完序之后的第幾行到第幾行糯彬。

由于這里我們純粹用?redis?來提高?cache?能力,不涉及到有關(guān)于任何搜索的能力葱她,所以這里忽略其他復(fù)雜查詢的情況撩扒。其實我們在復(fù)雜的地方使用了?elastcsearch?來提高搜索能力。

上述我們分析總結(jié)出了一個查詢接口的基本信息吨些,這里還有一個有關(guān)于高并發(fā)接口的設(shè)計原則就是將?hot-top?接口和一般?search?接口分離開搓谆,因為只有分而治之才能分別根據(jù)特點選用不同的技術(shù)炒辉。如果我們不分職責將所有的查詢場景封裝在一個接口里,那么在后面優(yōu)化接口性能的時候基本就很麻煩了泉手,有些場景是無法或者很難用?cache?來解決的黔寇,因為接口里耦合了各種場景邏輯,就算勉強能實現(xiàn)性能也不會高斩萌。

前面做這些鋪墊是為了能在介紹案例的時候達成一個基本的共識》炜悖現(xiàn)在我們來看下這個團購系統(tǒng)的?hot-top?接口的具體邏輯。

在大促的時候需要展現(xiàn)團購列表颊郎,這個接口的訪問量是非常大的憋飞,團購活動需要根據(jù)參團人數(shù)倒序排序,并且分頁返回指定數(shù)量的團列表姆吭。

我們假設(shè)這個接口名為?getTopGroups(getTopGroupsRequest request)

query condition 查詢條件問題

我們來仔細分析下搀崭,首先不同的查詢條件從?DB?里查詢出來的數(shù)據(jù)是不一樣的,也就是說查詢出來的團列表是不一樣的猾编,可能有?company 公司?瘤睹、channel 渠道?等過濾條件。由于一個團購活動下不會有太多團答倡,頂多上百個是極限了轰传,所以一個查詢條件出來的團列表也頂多幾十個,而且根據(jù)場景分析熱點查詢條件不會超過十個瘪撇,所以我們選擇將?查詢條件 hash?出一個?code?來緩存本次查詢條件的全量團列表集合获茬,但是這些結(jié)果集是沒有任何排序的。

sort 排序問題

再看根據(jù)參團人數(shù)排序問題倔既,我們立刻就可以想到使用?zset?來處理團排序問題恕曲,因為只有一個排序維度,所以一個?zset?就夠了渤涌。我們使用一個 __zset__來緩存所有團的參團人數(shù)集合佩谣,它是一個全量的團排序集合。

那么我們?nèi)绾螌⒂脩舻牟樵儣l件出來的團列表根據(jù)參團人數(shù)排序尼实蓬,剛好可以使用?zset?的交集運算直接計算出當前這個集合的?zset?子集茸俭。

page 分頁問題

通過對已經(jīng)排序之后的團列表?zset?使用?zrange?來獲取出分頁集合。

我們來看下完整的流程安皱,如何處理查詢调鬓、排序、分頁的酌伊。

上圖從?query condition?計算?hash code?腾窝,然后通過?DB?查詢出當前條件全量團列表。

zset:marketing:groupon:hottop:available:group key?表示全量團的參團人數(shù),用一個?zset?來緩存虹脯。接著將這兩個?zset?計算交集辜贵,就可以得出當前查詢所需要的帶有參團人數(shù)的?zset?,最后在使用?zrevrange?獲取分頁區(qū)間归形。

ZADDzset:marketing:groupon:hottop:condition:29860800G4ZD5732YZQ0G5VW3YF42UC0GF773FEJ7CC0GFW8DUEND8S0GKPKKW8XEY90GL324DGWMZM(integer)6

ZADDzset:marketing:groupon:hottop:available:group5GN7KQH36ZWK10GS7VB22AWD415GF773FEJ7CC17G5VW3YF42UC18G4ZD5732YZQ32GTYJKCEJBRR40GKPKKW8XEY945GL324DGWMZM50GFW8DUEND8S60GYTKY4ACWLT(integer)10

ZINTERSTOREzset:marketing:groupon:hottop:condition:interstore2zset:marketing:groupon:hottop:condition:2986080zset:marketing:groupon:hottop:available:group(integer)6

ZRANGEzset:marketing:groupon:hottop:condition:interstore0-1withscores1)"GF773FEJ7CC"2)"15"3)"G5VW3YF42UC"4)"17"5)"G4ZD5732YZQ"6)"18"7)"GKPKKW8XEY9"8)"40"9)"GL324DGWMZM"10)"45"11)"GFW8DUEND8S"12)"50"

ZREVRANGEzset:marketing:groupon:hottop:condition:interstore24withscores1)"GKPKKW8XEY9"2)"40"3)"G4ZD5732YZQ"4)"18"5)"G5VW3YF42UC"6)"17"

有了返回的團?code?集合之后就可以通過?mget?來批量獲取?string?類型的團詳情信息,這里就不貼出代碼了鼻由。

由于篇幅和時間關(guān)系暇榴,這里就不展開太多的業(yè)務(wù)場景介紹了。這其中還涉及到計算?cache?過期時間的問題蕉世,這也跟促銷活動的運營規(guī)則有關(guān)系蔼紧,還涉及到有可能?query condition hash?沖突問題等,但是這些已經(jīng)不與我們本節(jié)主題相關(guān)狠轻。

Redis 內(nèi)存數(shù)據(jù)結(jié)構(gòu)與編碼

我們已經(jīng)了解了?redis?提供的?5?種數(shù)據(jù)類型奸例,那么?redis?內(nèi)部到底是如何支持這?5?種數(shù)據(jù)類型的,也就是說?redis?到底是使用什么樣的數(shù)據(jù)結(jié)構(gòu)來存儲向楼、查找我們設(shè)置在內(nèi)存中的數(shù)據(jù)查吊。

雖然我們使用?5?種數(shù)據(jù)類型來緩存數(shù)據(jù),但是?redis?會根據(jù)我們存儲數(shù)據(jù)的不同而選用不同的數(shù)據(jù)結(jié)構(gòu)和編碼湖蜕。

我們?nèi)粘J褂玫氖?redis?提供的?5?種數(shù)據(jù)類型逻卖,但是這?5?種數(shù)據(jù)類型在內(nèi)存中的數(shù)據(jù)結(jié)構(gòu)和編碼有很多種。隨著我們存儲的數(shù)據(jù)類型的不同昭抒、數(shù)據(jù)量的大小不同都會引起內(nèi)存數(shù)據(jù)結(jié)構(gòu)的動態(tài)調(diào)整评也。

本節(jié)只是做數(shù)據(jù)結(jié)構(gòu)和編碼的一般性介紹,不做過多細節(jié)討論灭返,一方面是關(guān)于?redis?源碼分析的資料網(wǎng)上有很多盗迟,還有一個原因就是?redis?每一個版本的實現(xiàn)有很大差異,一旦展開細節(jié)討論每一個點每一個數(shù)據(jù)結(jié)構(gòu)都會很復(fù)雜熙含,所以我們這里就不展開討論這些罚缕,只是起到拋磚引玉作用。

OBJECT?encoding key怎静、DEBUG OBJECT?key

我們知道使用?type?命令可以查看某個?key?是否是?5?種數(shù)據(jù)類型之一怕磨,但是當我們想查看某個?key?底層是使用哪種數(shù)據(jù)結(jié)構(gòu)和編碼來存儲的時候可以使用?OBJECT encoding?命令。

SETstring:orderid:1010101010101010OK

OBJECT encodingstring:orderid:10101010"int"

SETstring:orderid:10101010"orderid:10101010"OK

OBJECT encodingstring:orderid:10101010"embstr"

同樣一個?key?消约,但是由于我們設(shè)置的值不同而?redis?選用了不同的內(nèi)存數(shù)據(jù)結(jié)構(gòu)和編碼肠鲫。雖然?redis?提供的?string?數(shù)據(jù)類型,但是?redis?會自動識別我們?cache?的數(shù)據(jù)類型是?int?還是?string?或粮。

如果我們設(shè)置的是字符串导饲,且這個字符串長度不大于?39?字節(jié)那么將使用?embstr?來編碼,如果大于?39?字節(jié)將使用?raw?來編碼。redis 4.0?將這個閥值擴大了?45?個字節(jié)渣锦。

除了使用?OBJECT encoding?命令外硝岗,我們還可以使用?DEBUG OBJECT?命令來查看更多詳細信息。

DEBUG OBJECTstring:orderid:10101010Valueat:0x7fd190500210refcount:1encoding:intserializedlength:5lru:6468044lru_seconds_idle:8

DEBUGOBJECTstring:orderid:10101010Valueat:0x7fd19043be60refcount:1encoding:embstrserializedlength:17lru:6465804lru_seconds_idle:1942

DEBUG OBJECT?能看到這個對象的?refcount 引用計數(shù)?袋毙、serializedlength 長度?型檀、lru_seconds_idle 時間?,這些信息決定了這個?key?緩存清除策略听盖。

簡單動態(tài)字符串(simple dynamic string)

簡單動態(tài)字符串簡稱?SDS?胀溺,在?redis?中所有涉及到字符串的地方都是使用?SDS?實現(xiàn),當然這里不包括字面量皆看。?SDS?與傳統(tǒng)?C?字符串的區(qū)別就是?SDS?是結(jié)構(gòu)化的仓坞,它可以高效的處理分配、回收腰吟、長度計算等問題无埃。

structsdshdr{unsignedintlen;unsignedintfree;charbuf[];};

這是?redis 3.0?版本的?sds.h?頭文件定義,3.0.0?之后變化比較大毛雇。len?表示字符串長度嫉称,free?表示空間長度,buf?數(shù)組表示字符串灵疮。

SDS?有很多優(yōu)點澎埠,比如,獲取長度的時間復(fù)雜度?O(1)?始藕,不需要遍歷所有?char buf[]?組數(shù)蒲稳,直接返回?len?值。

staticinlinesize_t sdslen(constsds s) {structsdshdr *sh = (void*)(s-(sizeof(structsdshdr)));returnsh->len;}

當然還有空間分配檢查伍派、空間預(yù)分配江耀、空間惰性釋放等,這些都是?SDS?結(jié)構(gòu)化字符串帶來的強大的擴展能力诉植。

鏈表(linked list)

鏈表數(shù)據(jù)結(jié)構(gòu)我們是比較熟悉的祥国,最大的特點就是節(jié)點的增、刪非常靈活晾腔。redis List?數(shù)據(jù)類型底層就是基于鏈表來實現(xiàn)舌稀。這是?redis 3.0?實現(xiàn)。

typedefstructlist{listNode *head;? ? listNode *tail;void*(*dup)(void*ptr);void(*free)(void*ptr);int(*match)(void*ptr,void*key);unsignedlonglen;}list;

typedefstructlistNode{structlistNode*prev;structlistNode*next;void*value;} listNode;

在?redis 3.2.0?版本的時候引入了?quicklist?鏈表結(jié)構(gòu)灼擂,結(jié)合了?linkedlist?和?ziplist?的優(yōu)勢壁查。

typedefstructquicklist{quicklistNode *head;? ? quicklistNode *tail;unsignedlongcount;/* total count of all entries in all ziplists */unsignedintlen;/* number of quicklistNodes */intfill :16;/* fill factor for individual nodes */unsignedintcompress :16;/* depth of end nodes not to compress;0=off */} quicklist;

typedefstructquicklistNode{structquicklistNode*prev;structquicklistNode*next;unsignedchar*zl;unsignedintsz;/* ziplist size in bytes */unsignedintcount :16;/* count of items in ziplist */unsignedintencoding :2;/* RAW==1 or LZF==2 */unsignedintcontainer :2;/* NONE==1 or ZIPLIST==2 */unsignedintrecompress :1;/* was this node previous compressed? */unsignedintattempted_compress :1;/* node can't compress; too small */unsignedintextra :10;/* more bits to steal for future usage */} quicklistNode;

quicklist?提供了靈活性同時也兼顧了?ziplist?的壓縮能力,quicklist->encoding?指定了兩種壓縮算法剔应。?quicklist->compress?表示我們可以進行?quicklist node?的深度壓縮能力睡腿。redis 提供了兩個有關(guān)于壓縮的配置语御。

list-max-ziplist-size:ziplist長度控制

list-compress-depth:控制鏈表兩端節(jié)點的壓縮個數(shù),越是靠近兩端的節(jié)點被訪問的機率越大席怪,所以可以將訪問機率大的節(jié)點不壓縮应闯,其他節(jié)點進行壓縮

對比?redis 3.2?的?quicklist?與?redis 3.0?,很明顯?quicklist?提供了更加豐富的壓縮功能挂捻。redis 3.0?的版本是每個?listnode?直接緩存值碉纺,而?quicklistnode?還有強大的有關(guān)于壓縮能力。

LPUSHlist:products:mall100200300(integer)3

OBJECT encodinglist:products:mall"quicklist"

歡迎工作一到五年的Java工程師朋友們加入Java架構(gòu)開發(fā): 854393687

群內(nèi)提供免費的Java架構(gòu)學習資料(里面有高可用刻撒、高并發(fā)骨田、高性能及分布式、Jvm性能調(diào)優(yōu)疫赎、Spring源碼,MyBatis碎节,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多個知識點的架構(gòu)資料)合理利用自己每一分每一秒的時間來學習提升自己捧搞,不要再用"沒有時間“來掩飾自己思想上的懶惰!趁年輕狮荔,使勁拼胎撇,給未來的自己一個交代!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末殖氏,一起剝皮案震驚了整個濱河市晚树,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌雅采,老刑警劉巖爵憎,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異婚瓜,居然都是意外死亡宝鼓,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進店門巴刻,熙熙樓的掌柜王于貴愁眉苦臉地迎上來愚铡,“玉大人,你說我怎么就攤上這事胡陪×ち龋” “怎么了?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵柠座,是天一觀的道長邑雅。 經(jīng)常有香客問我,道長妈经,這世上最難降的妖魔是什么蒂阱? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任锻全,我火速辦了婚禮,結(jié)果婚禮上录煤,老公的妹妹穿的比我還像新娘鳄厌。我一直安慰自己,他們只是感情好妈踊,可當我...
    茶點故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布了嚎。 她就那樣靜靜地躺著,像睡著了一般廊营。 火紅的嫁衣襯著肌膚如雪歪泳。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天露筒,我揣著相機與錄音呐伞,去河邊找鬼。 笑死慎式,一個胖子當著我的面吹牛伶氢,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播瘪吏,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼癣防,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了掌眠?” 一聲冷哼從身側(cè)響起蕾盯,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蓝丙,沒想到半個月后级遭,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡渺尘,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年装畅,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片沧烈。...
    茶點故事閱讀 38,605評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡掠兄,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出锌雀,到底是詐尸還是另有隱情蚂夕,我是刑警寧澤,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布腋逆,位于F島的核電站婿牍,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏惩歉。R本人自食惡果不足惜等脂,卻給世界環(huán)境...
    茶點故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一俏蛮、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧上遥,春花似錦搏屑、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至模软,卻和暖如春伟骨,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背燃异。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工腔呜, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留哨查,地道東北人溺健。 一個月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓棍郎,卻偏偏與公主長得像,于是被迫代替她去往敵國和親鲫剿。 傳聞我的和親對象是個殘疾皇子鳄逾,可洞房花燭夜當晚...
    茶點故事閱讀 43,472評論 2 348

推薦閱讀更多精彩內(nèi)容

  • Redis的內(nèi)存優(yōu)化 聲明:本文內(nèi)容來自《Redis開發(fā)與運維》一書第八章稻轨,如轉(zhuǎn)載請聲明灵莲。 Redis所有的數(shù)據(jù)都...
    meng_philip123閱讀 18,879評論 2 29
  • 參考來源 Redis的內(nèi)存優(yōu)化 Redis所有的數(shù)據(jù)都在內(nèi)存中,而內(nèi)存又是非常寶貴的資源殴俱。對于如何優(yōu)化內(nèi)存使用一直...
    秦漢郵俠閱讀 1,282評論 0 2
  • 轉(zhuǎn)自 hzlzh Best-App: 1. 付費軟件篇 (Mac OS) Mac OS平臺下有眾多優(yōu)秀的軟件工具政冻。...
    organnn閱讀 16,859評論 1 47
  • 一首歌 酗酒的好處就是完全不知道昨晚發(fā)生了什么,但醒來是痛苦的线欲,頭疼明场,胃也難受。特別是頂著它們?nèi)ド习喔且患纯嗟?..
    七月江南閱讀 316評論 0 4
  • 一年了李丰,宋離還在怡樂縣苦锨。 怡樂縣這個地方是我編出來的,我不知道世界上是否真的有這個地方趴泌。 我總是先寫一句話舟舒,再否定...
    阿貍貓貓閱讀 388評論 0 1