Redis基礎(chǔ)教程

本文摘抄至大鵬的redis教程

redis是一種kv存儲(chǔ)系統(tǒng)杆融,value支持五種數(shù)據(jù)類型:

  • 字符串(strings)
  • 字符串列表(lists)
  • 字符串集合(sets)
  • 有序字符串集合(sorted sets)
  • 哈希(hashes)
    key則是字符串類型累澡,其中key一般以如下方式命名吉嫩,用于保存盡可能多的信息微驶。例如user:10000:passwd

strings

strings是redis的基礎(chǔ)類型熏版,例子如下:

set mystr "hello world!" //設(shè)置字符串類型
get mystr //讀取字符串類型

字符串類型的用法就是這么簡(jiǎn)單咖驮,因?yàn)槭?strong>二進(jìn)制安全的,所以你完全可以把一個(gè)圖片文件的內(nèi)容作為字符串來(lái)存儲(chǔ)启妹。

另外筛严,我們還可以通過字符串類型進(jìn)行數(shù)值操作:

127.0.0.1:6379> set mynum "2"
OK
127.0.0.1:6379> get mynum
"2"
127.0.0.1:6379> incr mynum
(integer) 3
127.0.0.1:6379> get mynum
"3"

在遇到數(shù)值操作時(shí),redis會(huì)將字符串類型轉(zhuǎn)換成數(shù)值饶米。

由于INCR等指令本身就具有原子操作的特性桨啃,所以我們完全可以利用redis的INCR、INCRBY檬输、DECR照瘾、DECRBY等指令來(lái)實(shí)現(xiàn)原子計(jì)數(shù)的效果,假如丧慈,在某種場(chǎng)景下有3個(gè)客戶端同時(shí)讀取了mynum的值(值為2)析命,然后對(duì)其同時(shí)進(jìn)行了加1的操作,那么逃默,最后mynum的值一定是5鹃愤。不少網(wǎng)站都利用redis的這個(gè)特性來(lái)實(shí)現(xiàn)業(yè)務(wù)上的統(tǒng)計(jì)計(jì)數(shù)需求。

lists

Lists(列表)是Redis另外一個(gè)重要的數(shù)據(jù)結(jié)構(gòu)完域。redis中的lists在底層實(shí)現(xiàn)上并不是數(shù)組软吐,而是鏈表,也就是說對(duì)于一個(gè)具有上百萬(wàn)個(gè)元素的lists來(lái)說吟税,在頭部和尾部插入一個(gè)新元素凹耙,其時(shí)間復(fù)雜度是常數(shù)級(jí)別的鸟蟹,比如用LPUSH在10個(gè)元素的lists頭部插入新元素,和在上千萬(wàn)元素的lists頭部插入新元素的速度應(yīng)該是相同的使兔。

雖然lists有這樣的優(yōu)勢(shì),但同樣有其弊端藤韵,那就是虐沥,鏈表型lists的元素定位會(huì)比較慢,而數(shù)組型lists的元素定位就會(huì)快得多泽艘。

lists的常用操作包括LPUSH欲险、RPUSH、LRANGE等匹涮。我們可以用LPUSH在lists的左側(cè)插入一個(gè)新元素天试,用RPUSH在lists的右側(cè)插入一個(gè)新元素,用LRANGE命令從lists中指定一個(gè)范圍來(lái)提取元素然低。我們來(lái)看幾個(gè)例子:

//新建一個(gè)list叫做mylist喜每,并在列表頭部插入元素"1"
127.0.0.1:6379> lpush mylist "1" 
//返回當(dāng)前mylist中的元素個(gè)數(shù)
(integer) 1 
//在mylist右側(cè)插入元素"2"
127.0.0.1:6379> rpush mylist "2" 
(integer) 2
//在mylist左側(cè)插入元素"0"
127.0.0.1:6379> lpush mylist "0" 
(integer) 3
//列出mylist中從編號(hào)0到編號(hào)1的元素
127.0.0.1:6379> lrange mylist 0 1 
1) "0"
2) "1"
//列出mylist中從編號(hào)0到倒數(shù)第一個(gè)元素
127.0.0.1:6379> lrange mylist 0 -1 
1) "0"
2) "1"
3) "2"

lists的應(yīng)用相當(dāng)廣泛,隨便舉幾個(gè)例子:

  • 我們可以利用lists來(lái)實(shí)現(xiàn)一個(gè)消息隊(duì)列雳攘,而且可以確保先后順序带兜。
  • 利用LRANGE還可以很方便的實(shí)現(xiàn)分頁(yè)的功能。

set

redis的集合吨灭,是一種無(wú)序的集合刚照,集合中的元素沒有先后順序。
集合相關(guān)的操作也很豐富喧兄,如添加新元素无畔、刪除已有元素、取交集吠冤、取并集浑彰、取差集等。我們來(lái)看例子:

//向集合myset中加入一個(gè)新元素"one"
127.0.0.1:6379> sadd myset "one" 
(integer) 1
127.0.0.1:6379> sadd myset "two"
(integer) 1
//列出集合myset中的所有元素
127.0.0.1:6379> smembers myset 
1) "one"
2) "two"
//判斷元素1是否在集合myset中咨演,返回1表示存在
127.0.0.1:6379> sismember myset "one" 
(integer) 1
//判斷元素3是否在集合myset中闸昨,返回0表示不存在
127.0.0.1:6379> sismember myset "three" 
(integer) 0
//新建一個(gè)新的集合yourset
127.0.0.1:6379> sadd yourset "1" 
(integer) 1
127.0.0.1:6379> sadd yourset "2"
(integer) 1
127.0.0.1:6379> smembers yourset
1) "1"
2) "2"
//對(duì)兩個(gè)集合求并集
127.0.0.1:6379> sunion myset yourset 
1) "1"
2) "one"
3) "2"
4) "two"

對(duì)于集合的使用,也有一些常見的方式薄风,比如饵较,QQ有一個(gè)社交功能叫做“好友標(biāo)簽”,大家可以給你的好友貼標(biāo)簽遭赂,比如“大美女”循诉、“土豪”、“歐巴”等等撇他,這時(shí)就可以使用redis的集合來(lái)實(shí)現(xiàn)茄猫,把每一個(gè)用戶的標(biāo)簽都存儲(chǔ)在一個(gè)集合之中狈蚤。

有序集合

redis不但提供了無(wú)需集合(sets),還很體貼的提供了有序集合(sorted sets)划纽。有序集合中的每個(gè)元素都關(guān)聯(lián)一個(gè)序號(hào)(score)脆侮,這便是排序的依據(jù)

很多時(shí)候勇劣,我們都將redis中的有序集合叫做zsets靖避,這是因?yàn)樵趓edis中,有序集合相關(guān)的操作指令都是以z開頭的比默,比如zrange幻捏、zadd、zrevrange命咐、zrangebyscore等等

老規(guī)矩篡九,我們來(lái)看幾個(gè)生動(dòng)的例子:

//新增一個(gè)有序集合myzset,并加入一個(gè)元素baidu.com醋奠,給它賦予的序號(hào)是1
127.0.0.1:6379> zadd myzset 1 baidu.com 
(integer) 1
//向myzset中新增一個(gè)元素360.com榛臼,賦予它的序號(hào)是3
127.0.0.1:6379> zadd myzset 3 360.com 
(integer) 1
//向myzset中新增一個(gè)元素google.com,賦予它的序號(hào)是2
127.0.0.1:6379> zadd myzset 2 google.com 
(integer) 1
//列出myzset的所有元素窜司,同時(shí)列出其序號(hào)讽坏,可以看出myzset已經(jīng)是有序的了。
127.0.0.1:6379> zrange myzset 0 -1 with scores 
1) "baidu.com"
2) "1"
3) "google.com"
4) "2"
5) "360.com"
6) "3"
//只列出myzset的元素
127.0.0.1:6379> zrange myzset 0 -1 
1) "baidu.com"
2) "google.com"
3) "360.com"

哈希

最后要給大家介紹的是hashes例证,即哈希路呜。hashes存的是字符串和字符串值之間的映射,比如一個(gè)用戶要存儲(chǔ)其全名织咧、姓氏胀葱、年齡等等,就很適合使用哈希笙蒙。
我們來(lái)看一個(gè)例子:

//建立哈希抵屿,并賦值
127.0.0.1:6379> HMSET user:001 username antirez password P1pp0 age 34 OK
//列出哈希的內(nèi)容
127.0.0.1:6379> HGETALL user:001
1) "username"
2) "antirez"
3) "password"
4) "P1pp0"
5) "age"
6) "34"
//更改哈希中的某一個(gè)值
127.0.0.1:6379> HSET user:001 password 12345
 (integer) 0
//再次列出哈希的內(nèi)容
127.0.0.1:6379> HGETALL user:001
1) "username"
2) "antirez"
3) "password"
4) "12345"
5) "age"
6) "34"

Redis持久化

redis提供了兩種持久化的方式,分別是RDB和AOF捅位。

  • RDB轧葛,簡(jiǎn)而言之,就是在不同的時(shí)間點(diǎn)艇搀,將redis存儲(chǔ)的數(shù)據(jù)生成快照并存儲(chǔ)到磁盤等介質(zhì)上尿扯;
  • AOF,則是換了一個(gè)角度來(lái)實(shí)現(xiàn)持久化焰雕,那就是將redis執(zhí)行過的所有寫指令記錄下來(lái)衷笋,在下次redis重新啟動(dòng)時(shí),只要把這些寫指令從前到后再重復(fù)執(zhí)行一遍矩屁,就可以實(shí)現(xiàn)數(shù)據(jù)恢復(fù)了辟宗。

其實(shí)RDB和AOF兩種方式也可以同時(shí)使用爵赵,在這種情況下,如果redis重啟的話泊脐,則會(huì)優(yōu)先采用AOF方式來(lái)進(jìn)行數(shù)據(jù)恢復(fù)空幻,這是因?yàn)?strong>AOF方式的數(shù)據(jù)恢復(fù)完整度更高。
如果你沒有數(shù)據(jù)持久化的需求容客,也完全可以關(guān)閉RDB和AOF方式氛悬,這樣的話,redis將變成一個(gè)純內(nèi)存數(shù)據(jù)庫(kù)耘柱,就像memcache一樣

RDB

RDB方式棍现,是將redis某一時(shí)刻的數(shù)據(jù)持久化到磁盤中调煎,是一種快照式的持久化方法
redis在進(jìn)行數(shù)據(jù)持久化的過程中己肮,會(huì)先將數(shù)據(jù)寫入到一個(gè)臨時(shí)文件中士袄,待持久化過程都結(jié)束了,才會(huì)用這個(gè)臨時(shí)文件替換上次持久化好的文件谎僻。正是這種特性娄柳,讓我們可以隨時(shí)來(lái)進(jìn)行備份,因?yàn)榭煺瘴募偸峭暾捎玫摹?br> 對(duì)于RDB方式艘绍,redis會(huì)單獨(dú)創(chuàng)建(fork)一個(gè)子進(jìn)程來(lái)進(jìn)行持久化赤拒,而主進(jìn)程是不會(huì)進(jìn)行任何IO操作的,這樣就確保了redis極高的性能诱鞠。

如果需要進(jìn)行大規(guī)模數(shù)據(jù)的恢復(fù)挎挖,且對(duì)于數(shù)據(jù)恢復(fù)的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效航夺。

雖然RDB有不少優(yōu)點(diǎn)蕉朵,但它的缺點(diǎn)也是不容忽視的。如果你對(duì)數(shù)據(jù)的完整性非常敏感阳掐,那么RDB方式就不太適合你始衅,因?yàn)榧词鼓忝?分鐘都持久化一次,當(dāng)redis故障時(shí)缭保,仍然會(huì)有近5分鐘的數(shù)據(jù)丟失汛闸。所以,redis還提供了另一種持久化方式艺骂,那就是AOF蛉拙。

AOF

AOF,英文是Append Only File彻亲,即只允許追加不允許改寫的文件孕锄。
如前面介紹的吮廉,AOF方式是將執(zhí)行過的寫指令記錄下來(lái),在數(shù)據(jù)恢復(fù)時(shí)按照從前到后的順序再將指令都執(zhí)行一遍畸肆,就這么簡(jiǎn)單宦芦。

我們通過配置redis.conf中的appendonly yes就可以打開AOF功能。
如果有寫操作(如SET等)轴脐,redis就會(huì)被追加到AOF文件的末尾调卑。

默認(rèn)的AOF持久化策略是每秒鐘fsync一次(fsync是指把緩存中的寫指令記錄到磁盤中),因?yàn)樵谶@種情況下大咱,redis仍然可以保持很好的處理性能恬涧,即使redis故障,也只會(huì)丟失最近1秒鐘的數(shù)據(jù)碴巾。

如果在追加日志時(shí)溯捆,恰好遇到磁盤空間滿、inode滿或斷電等情況導(dǎo)致日志寫入不完整厦瓢,也沒有關(guān)系提揍,redis提供了redis-check-aof工具,可以用來(lái)進(jìn)行日志修復(fù)煮仇。

因?yàn)椴捎昧俗芳臃绞嚼驮荆绻蛔鋈魏翁幚淼脑挘珹OF文件會(huì)變得越來(lái)越大浙垫,為此刨仑,redis提供了AOF文件重寫(rewrite)機(jī)制,即當(dāng)AOF文件的大小超過所設(shè)定的閾值時(shí)夹姥,redis就會(huì)啟動(dòng)AOF文件的內(nèi)容壓縮贸人,只保留可以恢復(fù)數(shù)據(jù)的最小指令集。舉個(gè)例子或許更形象佃声,假如我們調(diào)用了100次INCR指令艺智,在AOF文件中就要存儲(chǔ)100條指令,但這明顯是很低效的圾亏,完全可以把這100條指令合并成一條SET指令十拣,這就是重寫機(jī)制的原理

在進(jìn)行AOF重寫時(shí)志鹃,仍然是采用先寫臨時(shí)文件夭问,全部完成后再替換的流程,所以斷電曹铃、磁盤滿等問題都不會(huì)影響AOF文件的可用性缰趋,這點(diǎn)大家可以放心。

AOF方式的另一個(gè)好處,我們通過一個(gè)“場(chǎng)景再現(xiàn)”來(lái)說明秘血。某同學(xué)在操作redis時(shí)味抖,不小心執(zhí)行了FLUSHALL,導(dǎo)致redis內(nèi)存中的數(shù)據(jù)全部被清空了灰粮,這是很悲劇的事情仔涩。不過這也不是世界末日,只要redis配置了AOF持久化方式粘舟,且AOF文件還沒有被重寫(rewrite)熔脂,我們就可以用最快的速度暫停redis并編輯AOF文件,將最后一行的FLUSHALL命令刪除柑肴,然后重啟redis霞揉,就可以恢復(fù)redis的所有數(shù)據(jù)到FLUSHALL之前的狀態(tài)了。是不是很神奇晰骑,這就是AOF持久化方式的好處之一适秩。但是如果AOF文件已經(jīng)被重寫了,那就無(wú)法通過這種方法來(lái)恢復(fù)數(shù)據(jù)了些侍。

雖然優(yōu)點(diǎn)多多,但AOF方式也同樣存在缺陷政模,比如在同樣數(shù)據(jù)規(guī)模的情況下岗宣,AOF文件要比RDB文件的體積大。而且淋样,AOF方式的恢復(fù)速度也要慢于RDB方式耗式。

如果你直接執(zhí)行BGREWRITEAOF命令,那么redis會(huì)生成一個(gè)全新的AOF文件趁猴,其中便包括了可以恢復(fù)現(xiàn)有數(shù)據(jù)的最少的命令集刊咳。

如果運(yùn)氣比較差,AOF文件出現(xiàn)了被寫壞的情況儡司,也不必過分擔(dān)憂娱挨,redis并不會(huì)貿(mào)然加載這個(gè)有問題的AOF文件,而是報(bào)錯(cuò)退出捕犬。這時(shí)可以通過以下步驟來(lái)修復(fù)出錯(cuò)的文件:

1:備份被寫壞的AOF文件
2:運(yùn)行redis-check-aof –fix進(jìn)行修復(fù)
3:用diff -u來(lái)看下兩個(gè)文件的差異跷坝,確認(rèn)問題點(diǎn)
4:重啟redis,加載修復(fù)后的AOF文件

詳細(xì)介紹AOF重寫

AOF 重寫并不需要對(duì)原有的 AOF 文件進(jìn)行任何寫入和讀取碉碉, 它針對(duì)的是數(shù)據(jù)庫(kù)中鍵的當(dāng)前值柴钻。
考慮這樣一個(gè)情況, 如果服務(wù)器對(duì)鍵 list執(zhí)行了以下四條命令:

RPUSH list 1 2 3 4 // [1, 2, 3, 4]
RPOP list // [1, 2, 3]
LPOP list // [2, 3]
LPUSH list 1 // [1, 2, 3]

那么當(dāng)前列表鍵 list 在數(shù)據(jù)庫(kù)中的值就為 [1, 2, 3] 垢粮。
如果我們要保存這個(gè)列表的當(dāng)前狀態(tài)贴届, 并且盡量減少所使用的命令數(shù), 那么最簡(jiǎn)單的方式不是去 AOF 文件上分析前面執(zhí)行的四條命令, 而是直接讀取 list 鍵在數(shù)據(jù)庫(kù)的當(dāng)前值毫蚓, 然后用一條 RPUSH 1 2 3 命令來(lái)代替前面的四條命令占键。
再考慮這樣一個(gè)例子, 如果服務(wù)器對(duì)集合鍵 animal 執(zhí)行了以下命令:

SADD animal cat // {cat}
SADD animal dog panda tiger // {cat, dog, panda, tiger}
SREM animal cat // {dog, panda, tiger}
SADD animal cat lion // {cat, lion, dog, panda, tiger}

那么使用一條 SADD animal cat lion dog panda tiger命令绍些, 就可以還原 animal
集合的狀態(tài)捞慌, 這比之前的四條命令調(diào)用要大大減少筷狼。
除了列表和集合之外涯竟, 字符串、有序集慰毅、哈希表等鍵也可以用類似的方法來(lái)保存狀態(tài)氮帐, 并且保存這些狀態(tài)所使用的命令數(shù)量嗅虏, 比起之前建立這些鍵的狀態(tài)所使用命令的數(shù)量要大大減少。
根據(jù)鍵的類型上沐, 使用適當(dāng)?shù)膶懭朊顏?lái)重現(xiàn)鍵的當(dāng)前值皮服, 這就是 AOF 重寫的實(shí)現(xiàn)原理。

AOF 后臺(tái)重寫

上一節(jié)展示的 AOF 重寫程序可以很好地完成創(chuàng)建一個(gè)新 AOF 文件的任務(wù)参咙, 但是龄广, 在執(zhí)行這個(gè)程序的時(shí)候, 調(diào)用者線程會(huì)被阻塞蕴侧。
很明顯择同, 作為一種輔佐性的維護(hù)手段, Redis 不希望 AOF 重寫造成服務(wù)器無(wú)法處理請(qǐng)求净宵, 所以 Redis 決定將 AOF 重寫程序放到(后臺(tái))子進(jìn)程里執(zhí)行 敲才。不過, 使用子進(jìn)程也有一個(gè)問題需要解決: 因?yàn)?strong>子進(jìn)程在進(jìn)行 AOF 重寫期間择葡, 主進(jìn)程還需要繼續(xù)處理命令紧武, 而新的命令可能對(duì)現(xiàn)有的數(shù)據(jù)進(jìn)行修改, 這會(huì)讓當(dāng)前數(shù)據(jù)庫(kù)的數(shù)據(jù)和重寫后的 AOF 文件中的數(shù)據(jù)不一致敏储。
為了解決這個(gè)問題阻星, Redis 增加了一個(gè)AOF 重寫緩存, 這個(gè)緩存在 fork 出子進(jìn)程之后開始啟用已添, Redis 主進(jìn)程在接到新的寫命令之后迫横, 除了會(huì)將這個(gè)寫命令的協(xié)議內(nèi)容追加到現(xiàn)有的 AOF 文件之外, 還會(huì)追加到這個(gè)緩存中.
換言之酝碳, 當(dāng)子進(jìn)程在執(zhí)行 AOF 重寫時(shí)矾踱, 主進(jìn)程需要執(zhí)行以下三個(gè)工作:
1:處理命令請(qǐng)求。
2:將寫命令追加到現(xiàn)有的 AOF 文件中疏哗。
3:將寫命令追加到 AOF 重寫緩存中呛讲。
這樣一來(lái)可以保證:
現(xiàn)有的 AOF 功能會(huì)繼續(xù)執(zhí)行,即使在 AOF 重寫期間發(fā)生停機(jī),也不會(huì)有任何數(shù)據(jù)丟失贝搁。
所有對(duì)數(shù)據(jù)庫(kù)進(jìn)行修改的命令都會(huì)被記錄到 AOF 重寫緩存中吗氏。

當(dāng)子進(jìn)程完成 AOF 重寫之后, 它會(huì)向父進(jìn)程發(fā)送一個(gè)完成信號(hào)雷逆, 父進(jìn)程在接到完成信號(hào)之后弦讽, 會(huì)調(diào)用一個(gè)信號(hào)處理函數(shù), 并完成以下工作:

  • 將 AOF 重寫緩存中的內(nèi)容全部寫入到新 AOF 文件中膀哲。
  • 對(duì)新的 AOF 文件進(jìn)行改名往产,覆蓋原有的 AOF 文件。

步驟 1 執(zhí)行完畢之后某宪, 現(xiàn)有 AOF 文件仿村、新 AOF 文件和數(shù)據(jù)庫(kù)三者的狀態(tài)就完全一致了。
當(dāng)步驟 2 執(zhí)行完畢之后兴喂, 程序就完成了新舊兩個(gè) AOF 文件的交替蔼囊。
這個(gè)信號(hào)處理函數(shù)執(zhí)行完畢之后, 主進(jìn)程就可以繼續(xù)像往常一樣接受命令請(qǐng)求了衣迷。 在整個(gè) AOF 后臺(tái)重寫過程中畏鼓, 只有最后的寫入緩存和改名操作會(huì)造成主進(jìn)程阻塞, 在其他時(shí)候壶谒, AOF 后臺(tái)重寫都不會(huì)對(duì)主進(jìn)程造成阻塞云矫, 這將 AOF 重寫對(duì)性能造成的影響降到了最低。
以上就是 AOF 后臺(tái)重寫佃迄。
對(duì)于我們應(yīng)該選擇RDB還是AOF泼差,官方的建議是兩個(gè)同時(shí)使用贵少。這樣可以提供更可靠的持久化方案呵俏。

Redis的主從機(jī)制

主從結(jié)構(gòu),一是為了純粹的冗余備份滔灶,二是為了提升讀性能普碎,比如很消耗性能的SORT就可以由從服務(wù)器來(lái)承擔(dān)。
redis的主從同步是異步進(jìn)行的录平,這意味著主從同步不會(huì)影響主邏輯麻车,也不會(huì)降低redis的處理性能。
主從架構(gòu)中斗这,可以考慮關(guān)閉主服務(wù)器的數(shù)據(jù)持久化功能动猬,只讓從服務(wù)器進(jìn)行持久化,這樣可以提高主服務(wù)器的處理性能表箭。
在主從架構(gòu)中赁咙,從服務(wù)器通常被設(shè)置為只讀模式,這樣可以避免從服務(wù)器的數(shù)據(jù)被誤修改。

主從同步原理

從服務(wù)器會(huì)向主服務(wù)器發(fā)出SYNC指令彼水,當(dāng)主服務(wù)器接到此命令后崔拥,就會(huì)調(diào)用BGSAVE指令來(lái)創(chuàng)建一個(gè)子進(jìn)程專門進(jìn)行數(shù)據(jù)持久化工作,也就是將主服務(wù)器的數(shù)據(jù)寫入RDB文件中凤覆。在數(shù)據(jù)持久化期間链瓦,主服務(wù)器將執(zhí)行的寫指令都緩存在內(nèi)存中。
在BGSAVE指令執(zhí)行完成后盯桦,主服務(wù)器會(huì)將持久化好的RDB文件發(fā)送給從服務(wù)器慈俯,從服務(wù)器接到此文件后會(huì)將其存儲(chǔ)到磁盤上,然后再將其讀取到內(nèi)存中俺附。這個(gè)動(dòng)作完成后肥卡,主服務(wù)器會(huì)將這段時(shí)間緩存的寫指令再以redis協(xié)議的格式發(fā)送給從服務(wù)器

另外事镣,要說的一點(diǎn)是步鉴,即使有多個(gè)從服務(wù)器同時(shí)發(fā)來(lái)SYNC指令,主服務(wù)器也只會(huì)執(zhí)行一次BGSAVE璃哟,然后把持久化好的RDB文件發(fā)給多個(gè)下游氛琢。在redis2.8版本之前,如果從服務(wù)器與主服務(wù)器因某些原因斷開連接的話随闪,都會(huì)進(jìn)行一次主從之間的全量的數(shù)據(jù)同步阳似;而在2.8版本之后,redis支持了效率更高的增量同步策略铐伴,這大大降低了連接斷開的恢復(fù)成本撮奏。

主服務(wù)器會(huì)在內(nèi)存中維護(hù)一個(gè)緩沖區(qū),緩沖區(qū)中存儲(chǔ)著將要發(fā)給從服務(wù)器的內(nèi)容当宴。從服務(wù)器在與主服務(wù)器出現(xiàn)網(wǎng)絡(luò)瞬斷之后畜吊,從服務(wù)器會(huì)嘗試再次與主服務(wù)器連接,一旦連接成功户矢,從服務(wù)器就會(huì)把“希望同步的主服務(wù)器ID”和“希望請(qǐng)求的數(shù)據(jù)的偏移位置(replication offset)”發(fā)送出去玲献。主服務(wù)器接收到這樣的同步請(qǐng)求后,首先會(huì)驗(yàn)證主服務(wù)器ID是否和自己的ID匹配梯浪,其次會(huì)檢查“請(qǐng)求的偏移位置”是否存在于自己的緩沖區(qū)中捌年,如果兩者都滿足的話,主服務(wù)器就會(huì)向從服務(wù)器發(fā)送增量?jī)?nèi)容挂洛。

增量同步功能礼预,需要服務(wù)器端支持全新的PSYNC指令。這個(gè)指令虏劲,只有在redis-2.8之后才具有托酸。

Redis事務(wù)

眾所周知荠藤,事務(wù)是指“一個(gè)完整的動(dòng)作,要么全部執(zhí)行获高,要么什么也沒有做”哈肖。

在聊redis事務(wù)處理之前,要先和大家介紹四個(gè)redis指令念秧,即MULTI淤井、EXEC、DISCARD摊趾、WATCH币狠。這四個(gè)指令構(gòu)成了redis事務(wù)處理的基礎(chǔ)

  • MULTI用來(lái)組裝一個(gè)事務(wù)砾层;
  • EXEC用來(lái)執(zhí)行一個(gè)事務(wù)漩绵;
  • DISCARD用來(lái)取消一個(gè)事務(wù);
  • WATCH用來(lái)監(jiān)視一些key肛炮,一旦這些key在事務(wù)執(zhí)行之前被改變止吐,則取消事務(wù)的執(zhí)行。

我們來(lái)看一個(gè)MULTI和EXEC的例子:

redis> MULTI //標(biāo)記事務(wù)開始
OK
redis> INCR user_id //多條命令按順序入隊(duì)
QUEUED
redis> INCR user_id
QUEUED
redis> INCR user_id
QUEUED
redis> PING
QUEUED
redis> EXEC //執(zhí)行
1) (integer) 1
2) (integer) 2
3) (integer) 3
4) PONG

在上面的例子中侨糟,我們看到了QUEUED的字樣碍扔,這表示我們?cè)谟肕ULTI組裝事務(wù)時(shí),每一個(gè)命令都會(huì)進(jìn)入到內(nèi)存隊(duì)列中緩存起來(lái)秕重,如果出現(xiàn)QUEUED則表示我們這個(gè)命令成功插入了緩存隊(duì)列不同,在將來(lái)執(zhí)行EXEC時(shí),這些被QUEUED的命令都會(huì)被組裝成一個(gè)事務(wù)來(lái)執(zhí)行溶耘。

對(duì)于事務(wù)的執(zhí)行來(lái)說二拐,如果redis開啟了AOF持久化的話,那么一旦事務(wù)被成功執(zhí)行凳兵,事務(wù)中的命令就會(huì)通過write命令一次性寫到磁盤中去百新,如果在向磁盤中寫的過程中恰好出現(xiàn)斷電、硬件故障等問題留荔,那么就可能出現(xiàn)只有部分命令進(jìn)行了AOF持久化吟孙,這時(shí)AOF文件就會(huì)出現(xiàn)不完整的情況澜倦,這時(shí)聚蝶,我們可以使用redis-check-aof工具來(lái)修復(fù)這一問題,這個(gè)工具會(huì)將AOF文件中不完整的信息移除藻治,確保AOF文件完整可用碘勉。
有關(guān)事務(wù),大家經(jīng)常會(huì)遇到的是兩類錯(cuò)誤:

  • 調(diào)用EXEC之前的錯(cuò)誤
  • 調(diào)用EXEC之后的錯(cuò)誤

調(diào)用EXEC之前的錯(cuò)誤桩卵,有可能是由于語(yǔ)法有誤導(dǎo)致的验靡,也可能時(shí)由于內(nèi)存不足導(dǎo)致的倍宾。只要出現(xiàn)某個(gè)命令無(wú)法成功寫入緩沖隊(duì)列的情況,redis都會(huì)進(jìn)行記錄胜嗓,在客戶端調(diào)用EXEC時(shí)高职,redis會(huì)拒絕執(zhí)行這一事務(wù)。我們來(lái)看一個(gè)這樣的例子:

127.0.0.1:6379> multi
OK
127.0.0.1:6379> haha //一個(gè)明顯錯(cuò)誤的指令
(error) ERR unknown command 'haha'
127.0.0.1:6379> ping
QUEUED
127.0.0.1:6379> exec//redis無(wú)情的拒絕了事務(wù)的執(zhí)行辞州,原因是“之前出現(xiàn)了錯(cuò)誤”
(error) EXECABORT Transaction discarded because of previous errors.

而對(duì)于“調(diào)用EXEC之后的錯(cuò)誤”怔锌,redis則采取了完全不同的策略,即redis不會(huì)理睬這些錯(cuò)誤变过,而是繼續(xù)向下執(zhí)行事務(wù)中的其他命令埃元。這是因?yàn)椋瑢?duì)于應(yīng)用層面的錯(cuò)誤媚狰,并不是redis自身需要考慮和處理的問題岛杀,所以一個(gè)事務(wù)中如果某一條命令執(zhí)行失敗,并不會(huì)影響接下來(lái)的其他命令的執(zhí)行崭孤。我們也來(lái)看一個(gè)例子:

127.0.0.1:6379> multi
OK
127.0.0.1:6379> set age 23
QUEUED
//age不是集合类嗤,所以如下是一條明顯錯(cuò)誤的指令
127.0.0.1:6379> sadd age 15 
QUEUED
127.0.0.1:6379> set age 29
QUEUED
127.0.0.1:6379> exec //執(zhí)行事務(wù)時(shí),redis不會(huì)理睬第2條指令執(zhí)行錯(cuò)誤
1) OK
2) (error) WRONGTYPE Operation against a key holding the wrong kind of value
3) OK
127.0.0.1:6379> get age
"29" //可以看出第3條指令被成功執(zhí)行了

好了辨宠,我們來(lái)說說最后一個(gè)指令“WATCH”土浸,這是一個(gè)很好用的指令,它可以幫我們實(shí)現(xiàn)類似于“樂觀鎖”的效果彭羹,即CAS(check and set)黄伊。

WATCH本身的作用是“監(jiān)視key是否被改動(dòng)過”,而且支持同時(shí)監(jiān)視多個(gè)key派殷,只要還沒真正觸發(fā)事務(wù)还最,WATCH都會(huì)盡職盡責(zé)的監(jiān)視,一旦發(fā)現(xiàn)某個(gè)key被修改了毡惜,在執(zhí)行EXEC時(shí)就會(huì)返回nil拓轻,表示事務(wù)無(wú)法觸發(fā)。

127.0.0.1:6379> set age 23
OK
127.0.0.1:6379> watch age //開始監(jiān)視age
OK
127.0.0.1:6379> set age 24 //在EXEC之前经伙,age的值被修改了
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set age 25
QUEUED
127.0.0.1:6379> get age
QUEUED
127.0.0.1:6379> exec //觸發(fā)EXEC
(nil) //事務(wù)無(wú)法被執(zhí)行
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末扶叉,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子帕膜,更是在濱河造成了極大的恐慌枣氧,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,590評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件垮刹,死亡現(xiàn)場(chǎng)離奇詭異达吞,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)荒典,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,157評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門酪劫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)吞鸭,“玉大人,你說我怎么就攤上這事覆糟】贪” “怎么了?”我有些...
    開封第一講書人閱讀 169,301評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵滩字,是天一觀的道長(zhǎng)透敌。 經(jīng)常有香客問我,道長(zhǎng)踢械,這世上最難降的妖魔是什么酗电? 我笑而不...
    開封第一講書人閱讀 60,078評(píng)論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮内列,結(jié)果婚禮上撵术,老公的妹妹穿的比我還像新娘。我一直安慰自己话瞧,他們只是感情好嫩与,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,082評(píng)論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著交排,像睡著了一般划滋。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上埃篓,一...
    開封第一講書人閱讀 52,682評(píng)論 1 312
  • 那天处坪,我揣著相機(jī)與錄音,去河邊找鬼架专。 笑死同窘,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的部脚。 我是一名探鬼主播想邦,決...
    沈念sama閱讀 41,155評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼委刘!你這毒婦竟也來(lái)了丧没?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,098評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤锡移,失蹤者是張志新(化名)和其女友劉穎呕童,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體罩抗,經(jīng)...
    沈念sama閱讀 46,638評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡拉庵,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,701評(píng)論 3 342
  • 正文 我和宋清朗相戀三年灿椅,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了套蒂。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片钞支。...
    茶點(diǎn)故事閱讀 40,852評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖操刀,靈堂內(nèi)的尸體忽然破棺而出烁挟,到底是詐尸還是另有隱情,我是刑警寧澤骨坑,帶...
    沈念sama閱讀 36,520評(píng)論 5 351
  • 正文 年R本政府宣布撼嗓,位于F島的核電站,受9級(jí)特大地震影響欢唾,放射性物質(zhì)發(fā)生泄漏且警。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,181評(píng)論 3 335
  • 文/蒙蒙 一礁遣、第九天 我趴在偏房一處隱蔽的房頂上張望斑芜。 院中可真熱鬧,春花似錦祟霍、人聲如沸杏头。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,674評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)醇王。三九已至,卻和暖如春崭添,著一層夾襖步出監(jiān)牢的瞬間寓娩,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,788評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工呼渣, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留根暑,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,279評(píng)論 3 379
  • 正文 我出身青樓徙邻,卻偏偏與公主長(zhǎng)得像排嫌,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子缰犁,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,851評(píng)論 2 361

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

  • 本文將從Redis的基本特性入手帅容,通過講述Redis的數(shù)據(jù)結(jié)構(gòu)和主要命令對(duì)Redis的基本能力進(jìn)行直觀介紹颇象。之后概...
    kelgon閱讀 61,177評(píng)論 23 625
  • Redis雜談 Redis是近年來(lái)發(fā)展迅速的內(nèi)存數(shù)據(jù)庫(kù),網(wǎng)上也已經(jīng)有多Redis的文章并徘。但不管是英文還是中文遣钳,多數(shù)...
    迷失于重逢閱讀 1,568評(píng)論 0 14
  • 1.1 資料 ,最好的入門小冊(cè)子麦乞,可以先于一切文檔之前看蕴茴,免費(fèi)劝评。 作者Antirez的博客,Antirez維護(hù)的R...
    JefferyLcm閱讀 17,071評(píng)論 1 51
  • Redis 提供了多種不同級(jí)別的持久化方式: 了解 RDB 持久化和 AOF 持久化之間的異同是非常重要的倦淀, 以下...
    笑Skr人啊閱讀 469評(píng)論 0 1
  • 人生有兩種痛苦 一種是得不到撞叽,一種是得到了 人生亦有兩種快樂 一種是得到了姻成,一種是得不到 惡念要去...
    羽翎兒閱讀 304評(píng)論 0 0