分區(qū)在我的理解就是原本一個(gè)Redis處理所有的get/set請(qǐng)求,現(xiàn)在用多個(gè)Redis實(shí)例來分擔(dān)get/set 請(qǐng)求。
- 為什么要使用分區(qū)?
- 擴(kuò)容
- 提升計(jì)算能力,提高帶寬
分區(qū)標(biāo)準(zhǔn)
- 范圍分區(qū)
就是將不同范圍的對(duì)象映射到不同Redis實(shí)例。比如說,用戶ID從0到10000的都被存儲(chǔ)到R0,用戶ID從10001到20000被存儲(chǔ)到R1,依此類推。
這是一種可行方案并且很多人已經(jīng)在使用。但是這種方案也有缺點(diǎn),你需要建一張表存儲(chǔ)數(shù)據(jù)到redis實(shí)例的映射關(guān)系。這張表需要非常謹(jǐn)慎地維護(hù)并且需要為每一類對(duì)象建立映射關(guān)系,所以redis范圍分區(qū)通常并不像你想象的那樣運(yùn)行,比另外一種分區(qū)方案效率要低很多。 - Hash分區(qū)
1. 使用散列函數(shù) (如 crc32 )將鍵名稱轉(zhuǎn)換為一個(gè)數(shù)字。例:鍵foobar, 使用crc32(foobar)函數(shù)將產(chǎn)生散列值93024922。
2. 對(duì)轉(zhuǎn)換后的散列值進(jìn)行取模,以產(chǎn)生一個(gè)0到3的數(shù)字,以便可以使這個(gè)key映射到4個(gè)Redis實(shí)例當(dāng)中的一個(gè)。93024922 % 4 等于 2, 所以 foobar 會(huì)被存儲(chǔ)到第2個(gè)Redis實(shí)例。 R2 注意: 對(duì)一個(gè)數(shù)字進(jìn)行取模,在大多數(shù)編程語言中是使用運(yùn)算符%
分區(qū)的實(shí)現(xiàn)方案
- 客戶端分區(qū)
就是由客戶端自己決定要將Key存放在哪個(gè)實(shí)例,再去哪個(gè)實(shí)例獲取 - 代理分區(qū)
客戶端依賴一個(gè)代理,代理決定去哪個(gè)節(jié)點(diǎn)寫數(shù)據(jù)或者讀數(shù)據(jù)。代理根據(jù)分區(qū)規(guī)則決定請(qǐng)求哪些Redis實(shí)例,然后根據(jù)Redis的響應(yīng)結(jié)果返回給客戶端。redis和memcached的一種代理實(shí)現(xiàn)就是Twemproxy - 查詢路由
客戶端隨機(jī)地請(qǐng)求任意一個(gè)redis實(shí)例,然后由Redis將請(qǐng)求轉(zhuǎn)發(fā)給正確的Redis節(jié)點(diǎn)
分區(qū)的缺點(diǎn)
- 涉及多個(gè)key的操作通常不會(huì)被支持。例如你不能對(duì)兩個(gè)集合求交集,多個(gè)Key的事務(wù)
- 備份/恢復(fù) 復(fù)雜化
- 分區(qū)使用的粒度是key,zset 功能受到限制
- 擴(kuò)容和縮容操作復(fù)雜
用作緩存和持久化分區(qū)的不同
使用途徑不一樣Redis分區(qū)的實(shí)現(xiàn)還是有點(diǎn)不一樣的。當(dāng)把Redis當(dāng)做一個(gè)持久化存儲(chǔ)時(shí),一個(gè)key必須嚴(yán)格地每次被映射到同一個(gè)Redis實(shí)例。當(dāng)把Redis當(dāng)做一個(gè)緩存時(shí),即使Redis的其中一個(gè)節(jié)點(diǎn)不可用,就算數(shù)據(jù)發(fā)生了丟失,我們還可以去Mysql等數(shù)據(jù)庫拉取數(shù)據(jù),淡然我們可用任意的規(guī)則更改映射,提高系統(tǒng)的高可用性,比如使用一致性Hash算法,這種方法能夠?qū)崿F(xiàn)當(dāng)一個(gè)key的首選的節(jié)點(diǎn)不可用時(shí)切換至其他節(jié)點(diǎn)。同樣地,如果你增加了一個(gè)新節(jié)點(diǎn),立刻就會(huì)有新的key被分配至這個(gè)新節(jié)點(diǎn)。
- 重要結(jié)論如下:
- 如果Redis被當(dāng)做緩存使用,使用一致性哈希實(shí)現(xiàn)動(dòng)態(tài)擴(kuò)容縮容。
- 如果Redis被當(dāng)做一個(gè)持久化存儲(chǔ)使用,必須使用固定的keys-to-nodes映射關(guān)系,節(jié)點(diǎn)的數(shù)量一旦確定不能變化。否則的話(即Redis節(jié)點(diǎn)需要?jiǎng)討B(tài)變化的情況),必須使用可以在運(yùn)行時(shí)進(jìn)行數(shù)據(jù)再平衡的一套系統(tǒng),而當(dāng)前只有Redis集群可以做到這樣 - Redis 集群已經(jīng)可用 2015.4.1.
預(yù)分片
如果我們要將Redis作為持久化,一般情況下隨著時(shí)間的推移,數(shù)據(jù)存儲(chǔ)需求總會(huì)發(fā)生變化。今天可能10個(gè)Redis節(jié)點(diǎn)就夠了,但是明天可能就需要增加到50個(gè)節(jié)點(diǎn),這是十分麻煩的。為防止以后的擴(kuò)容,最好的辦法就是一開始就啟動(dòng)較多實(shí)例。即便你只有一臺(tái)服務(wù)器,你也可以一開始就讓Redis以分布式的方式運(yùn)行,使用分區(qū),在同一臺(tái)服務(wù)器上啟動(dòng)多個(gè)實(shí)例(偽集群)。
一開始就多設(shè)置幾個(gè)Redis實(shí)例,例如32或者64個(gè)實(shí)例,對(duì)大多數(shù)用戶來說這操作起來可能比較麻煩,但是從長久來看做這點(diǎn)犧牲是值得的。
這樣的話,當(dāng)你的數(shù)據(jù)不斷增長,需要更多的Redis服務(wù)器時(shí),你需要做的就是僅僅將Redis實(shí)例從一臺(tái)服務(wù)遷移到另外一臺(tái)服務(wù)器而已(而不用考慮重新分區(qū)的問題)。一旦你添加了另一臺(tái)服務(wù)器,你需要將你一半的Redis實(shí)例從第一臺(tái)機(jī)器遷移到第二臺(tái)機(jī)器。
大概的操作步驟是這樣:
- 啟動(dòng)一個(gè)空的實(shí)例
new在另外一臺(tái)機(jī)子上; - 把
new配置為你的的源實(shí)例(要擴(kuò)容的實(shí)例)的從節(jié)點(diǎn); - 關(guān)閉客戶端
- 更改客戶端的配置(連接到新機(jī)子的Ip)
- 將
new設(shè)置為主節(jié)點(diǎn)SLAVEOF NO ONE - 重啟客戶端
- 關(guān)閉源實(shí)例
分區(qū)的可選方案
- 首選Redis Cluster
- 使用推特開源的代理
twemproxy - 使用支持一致性哈希的客戶端