自我介紹
我, redis ,內(nèi)存數(shù)據(jù)庫,有著比 memcached 更強(qiáng)大的功能。現(xiàn)在已經(jīng)是這個(gè)領(lǐng)域的頭把金交椅。
常規(guī)數(shù)據(jù)庫
這里所說的常規(guī)數(shù)據(jù)庫是指基于硬盤讀寫的數(shù)據(jù)庫,比如 Oracle , MySQL , Mongodb 等。基于硬盤讀寫的數(shù)據(jù)庫可以有效的保證數(shù)據(jù)的高可用性。這里的高可用性指的是操作系統(tǒng)或者數(shù)據(jù)庫崩潰之后,不會(huì)造成數(shù)據(jù)丟失,這也是對數(shù)據(jù)庫的最基本要求。
內(nèi)存數(shù)據(jù)庫
基于硬盤讀寫的數(shù)據(jù)庫雖然可以保證數(shù)據(jù)的高可用性,但是讀寫速度比較慢,這也是磁盤 I/O的天然屬性。雖然切換固態(tài)硬盤之后,性能會(huì)有顯著提升,但是經(jīng)濟(jì)成本也會(huì)隨之升高,而且固態(tài)硬盤使用壽命偏低。為了解決這個(gè)問題, Redis 做出了改變。 Redis 是基于內(nèi)存進(jìn)行讀寫的數(shù)據(jù)庫,把數(shù)據(jù)全部存儲(chǔ)在內(nèi)存中,這樣就可以大幅提高數(shù)據(jù)的讀寫速度。
memcached
說到內(nèi)存數(shù)據(jù)庫,不得不提 memcached , memcached 比 Redis 出現(xiàn)的更早,也是基于內(nèi)存進(jìn)行數(shù)據(jù)存儲(chǔ)。在十幾年前,大家通用的緩存方案就是 memcached 。 memcached 支持 Key-Value形式的數(shù)據(jù)存儲(chǔ),但是只支持 String 類型的數(shù)據(jù)結(jié)構(gòu),不支持更復(fù)雜的數(shù)據(jù)結(jié)構(gòu),也不支持集群。
操作系統(tǒng)或者 memcached 重啟后數(shù)據(jù)就會(huì)丟失。這也是基于內(nèi)存進(jìn)行數(shù)據(jù)存儲(chǔ)的最大缺點(diǎn)。
Redis
Redis 繼承了 memcached 所有的優(yōu)點(diǎn),并改進(jìn)了很多缺點(diǎn)。比如 Redis 也是基于內(nèi)存進(jìn)行數(shù)據(jù)操作,并且支持更多的數(shù)據(jù)類型,比如 List , Set 等。最最主要的,也是這篇文章的重點(diǎn), Redis 支持?jǐn)?shù)據(jù)高可用,也就是說 Redis 或者操作系統(tǒng)重啟之后,數(shù)據(jù)不會(huì)丟失。
Redis 在高可用這條路上所付出的努力,就像一個(gè)不斷努力進(jìn)取的勵(lì)志青年。
單機(jī)持久化
眾所周知,放在內(nèi)存中的數(shù)據(jù)是不穩(wěn)定的。為了解決因?yàn)橄到y(tǒng)或者 Redis 重啟造成的數(shù)據(jù)丟失問題。 Redis 提供了兩種數(shù)據(jù)持久化方案。
- 快照備份把 Redis 數(shù)據(jù)庫中的數(shù)據(jù),定時(shí)備份到磁盤中。當(dāng)數(shù)據(jù)庫重啟的時(shí)候,可以通過定時(shí)備份到磁盤文件中的快照文件進(jìn)行數(shù)據(jù)恢復(fù)。這樣 Redis 既保證了數(shù)據(jù)的讀寫速度,又保證了數(shù)據(jù)的高可用。
- AOF 同步寫快照備份有個(gè)缺點(diǎn),就是會(huì)丟失一部分?jǐn)?shù)據(jù)。比如在新的快照文件生成之前,系統(tǒng)發(fā)生了問題,那么最近一次快照之后的數(shù)據(jù)將丟失。 Redis 為了解決這個(gè)問題,提出了 AOF 解決方案。所謂的 AOF 就是將每次寫入數(shù)據(jù)的命令都以追加的方式記錄到文件中。這樣在系統(tǒng)出問題的時(shí)候,只要將這個(gè)文件中的命令全部重放一下就OK了。這樣就可以做到不丟數(shù)了。
但是如果數(shù)據(jù)寫入操作太多的話,會(huì)造成 AOF 文件過大,為了解決這個(gè)問題 Redis 提供了 AOF 自動(dòng)壓縮功能,以及去重功能,這樣可以達(dá)到對文件體積大小進(jìn)行優(yōu)化的目的。
主從復(fù)制
上面的兩種持久化方案,對于單節(jié)點(diǎn) Redis 來說,基本已經(jīng)夠用了。但是我們的系統(tǒng)總是越做越大,要求越來越多。有的時(shí)候單節(jié)點(diǎn) Redis 往往撐不住系統(tǒng)的訪問量。這種情況下 Redis 提供了主從模式。
所謂的主從模式就是一個(gè)主節(jié)點(diǎn),負(fù)責(zé)讀和寫,一個(gè)從節(jié)點(diǎn),負(fù)責(zé)將主節(jié)點(diǎn)的數(shù)據(jù)同步到從節(jié)點(diǎn),這樣主從節(jié)點(diǎn)信息就是一致的。
注意:從節(jié)點(diǎn)不支持寫操作,但是可以支持讀操作。當(dāng)其中任意一個(gè)點(diǎn)掛掉之后,數(shù)據(jù)不會(huì)損失。而且可以將讀的壓力分散到多個(gè)節(jié)點(diǎn),支持更大的訪問量。
哨兵模式
對于主從模式,這里有個(gè)最大的痛點(diǎn)。當(dāng)主節(jié)點(diǎn)掛掉后,從節(jié)點(diǎn)是不會(huì)自動(dòng)升級為主節(jié)點(diǎn)的。也就是負(fù)責(zé)往 Redis 寫入的程序會(huì)報(bào)錯(cuò),但是讀操作不會(huì)有問題。這一點(diǎn)不太符合高可用的要求。為了解決發(fā)生故障,主節(jié)點(diǎn)自動(dòng)切換的問題, Redis 又給大家提供了哨兵模式。
所謂的哨兵模式就是,提供三個(gè)哨兵節(jié)點(diǎn)(同樣是 Redis 實(shí)例,只不過不存儲(chǔ)數(shù)據(jù)),來監(jiān)控主從模式下的所有 Redis 節(jié)點(diǎn)(真正存儲(chǔ)數(shù)據(jù)的節(jié)點(diǎn))。客戶端程序通過哨兵節(jié)點(diǎn)獲取主節(jié)點(diǎn)信息。當(dāng)主節(jié)點(diǎn)掛掉后,哨兵節(jié)點(diǎn)會(huì)自動(dòng)將其中一個(gè)從節(jié)點(diǎn)升級為主節(jié)點(diǎn),提供給客戶端程序執(zhí)行寫入操作。當(dāng)發(fā)生故障的主節(jié)點(diǎn)恢復(fù)后,會(huì)自動(dòng)變?yōu)樾碌闹鞴?jié)點(diǎn)的從節(jié)點(diǎn)。
集群模式
大家可能發(fā)現(xiàn)了,無論是主從復(fù)制模式,還是哨兵模式都沒有解決分布式寫的問題,也就是說到目前為止,所有的方案都只能往一個(gè)節(jié)點(diǎn)寫數(shù)據(jù),數(shù)據(jù)存儲(chǔ)能力受單節(jié)點(diǎn)限制。哨兵模式僅僅解決了主從復(fù)制模式下,發(fā)生故障后不能自動(dòng)切換的問題。
為了解決分布式寫的問題, Redis 提供了集群功能。
Redis 集群可以實(shí)現(xiàn)分布式寫。集群中的節(jié)點(diǎn)分為主節(jié)點(diǎn)和從節(jié)點(diǎn)。主節(jié)點(diǎn)負(fù)責(zé)數(shù)據(jù)的讀寫以及集群信息的維護(hù),從節(jié)點(diǎn)負(fù)責(zé)同步主節(jié)點(diǎn)的信息。
Redis 集群利用數(shù)據(jù)分片的概念,將要操作的 Key 進(jìn)行哈希計(jì)算,根據(jù)得到的結(jié)果決定這個(gè) Key 應(yīng)該存儲(chǔ)到那個(gè)主節(jié)點(diǎn)。這樣就可以利用多個(gè)主節(jié)點(diǎn)進(jìn)行分布式寫操作。進(jìn)行讀操作的時(shí)候也會(huì)先計(jì)算 Key 的哈希值,然后找到對應(yīng)的主節(jié)點(diǎn)。
很遺憾的是,集群模式也不是百分百完美,比如 key 的批量操作會(huì)受限制,只有當(dāng)操作的 key都位于一個(gè)槽位時(shí)才能進(jìn)行操作。 還有 Keys 操作,只能在任一節(jié)點(diǎn)發(fā)生,不能 跨 節(jié)點(diǎn)。 其實(shí)這些所有缺點(diǎn),都是因?yàn)榉植际綄懺斐傻模驗(yàn)槟惆褦?shù)據(jù)分別存到了不同的 Redis 節(jié)點(diǎn)。
總結(jié)
Redis 由單節(jié)點(diǎn)的持久化,到主從復(fù)制模式,再到哨兵模式,再到最后的集群模式。一路打怪升級,不斷的完善自己。