集群的概念早在 redis 3.0 之前討論了,3.0 才在原始碼中出現。redis 集群要考慮的問題:
節點之間怎麼據的同步,如何做到資料一致性。一主一備的模式,可以用 redis 內部實現的主從備份實現資料同步。但節點不斷增多,存在多個 master 的時候,同步的難度會越大。
如何做到負載均衡?請求量大的時候,如何將請求盡量均分到各個伺服器節點,負載均衡演算法做的不好會導致雪崩。
如何做到平滑拓展?當業務量增加的時候,能否通過簡單的配置即讓新的 redis 節點變為可用。
可用性如何?當某些節點鼓掌,能否快速恢復伺服器集群的工作能力。……
乙個穩健的後台系統需要太多的考慮。
通常,業務量較大的時候,考慮到效能的問題(索引速度慢和訪問量過大),不會把所有的資料存放在乙個 redis 伺服器上。這裡需要將一堆的鍵值均分儲存到多個 redis 伺服器,可以通過:
target = hash(key)\%n
,其中 target 為目標節點,key 為鍵,n 為 redis 節點的個數雜湊取餘的方式會將不同的 key 分發到不同的伺服器上。
但考慮如下場景:
業務量突然增加,現有伺服器不夠用。增加伺服器節點後,依然通過上面的計算方式:hash(key)%(n+1)
做資料分片和分發,但之前的 key 會被分發到與之前不同的伺服器上,導致大量的資料失效,需要重新寫入(set)redis 伺服器。
其中的乙個伺服器掛了。如果不做及時的修復,大量被分發到此伺服器請求都會失效。
這也是兩個問題。
設定乙個圓環上 0-2^3̂2-1 的點,每個點對應乙個快取區,每個鍵值對儲存的位置也經雜湊計算後對應到環上節點。但現實中不可能有如此多的節點,所以倘若鍵值對經雜湊計算後對應的位置沒有節點,那麼順時針找乙個節點儲存它。
考慮增加伺服器節點的情況,該節點順時針方向的資料仍然被儲存到順時針方向的節點上,但它逆時針方向的資料被儲存到它自己。這時候只有部分資料會失效,被對映到新的快取區。
考慮節點減少的情況。該缺失節點順時針方向上的資料仍然被儲存到其順時針方向上的節點,設為 beta,其逆時針方向上的資料會被儲存到 beta 上。同樣,只有有部分資料失效,被重新對映到新的伺服器節點。
這種情況比較麻煩,上面圖中 gamma 節點失效後,會有大量資料對映到 alpha 節點,最怕 alpha 扛不住,接下去 beta 也扛不住,這就是多公尺諾骨牌效應;)。這裡涉及到資料平衡性和負載均衡的話題。資料平衡性是說,資料盡可能均分到每個節點上去,儲存達到均衡。
虛擬節點簡介
將多個虛擬節點對應到乙個真實的節點,儲存可以達到更均衡的效果。之前的對映方案為:
key -> node
中間多了乙個層虛擬節點後,多了一層對映關係:
key -> -> node
虛擬節點的設計有什麼好處?假設有四個節點如下:
節點 3 突然宕機,這時候原本在節點 3 的資料,會被定向到節點 4。在三個節點中節點 4 的請求量是最大的。這就導致節點與節點之間請求量是不均衡的。
為了達到節點與節點之間請求訪問的均衡,嘗試將原有節點 3 的資料平均定向到到節點 1,2,4. 如此達到負載均衡的效果,如下:
總之,一致性雜湊演算法是希望在增刪節點的時候,讓盡可能多的快取資料不失效。
一致性雜湊演算法,既可以在客戶端實現,也可以在中介軟體上實現(如 proxy)。在客戶端實現中,當客戶端初始化的時候,需要初始化一張預備的 redis 節點的對映表:hash(key)=> . 這有乙個缺點,假設有多個客戶端,當對映表發生變化的時候,多個客戶端需要同時拉取新的對映表。
另乙個種是中介軟體(proxy)的實現方法,即在客戶端和 redis 節點之間加多乙個**,**經過雜湊計算後將對應某個 key 的請求分發到對應的節點,一致性雜湊演算法就在中介軟體裡面實現。可以發現,twemproxy 就是這麼做的。
twemproxy 是 twitter 開源的乙個輕量級的後端**,相容 redis/memcache 協議,可用以管理 redis/memcache 集群。
twemproxy 內部有實現一致性雜湊演算法,對於客戶端而言,twemproxy 相當於是快取資料庫的入口,它無需知道後端的部署是怎樣的。twemproxy 會檢測與每個節點的連線是否健康,出現異常的節點會被剔除;待一段時間後,twemproxy 會再次嘗試連線被剔除的節點。
通常,乙個 redis 節點池可以分由多個 twemproxy 管理,少數 twemproxy 負責寫,多數負責讀。twemproxy 可以實時獲取節點池內的所有 redis 節點的狀態,但其對故障修復的支援還有待提高。解決的方法是可以借助 redis sentinel 來實現自動的主從切換,當主機 down 掉後,sentinel 會自動將從機配置為主機。而 twemproxy 可以定時向 redis sentinel 拉取資訊,從而替換出現異常的節點。
twemproxy 的更多細節,這裡不再做深入的討論。
最新版本的 redis 也開始支援集群特性了,再也不用靠著外援過日子了。基本的思想是,集群裡的每個 redis 都只儲存一定的鍵值對,這個「一定」可以通過預設或自定義的雜湊函式來決定,當乙個 redis 收到請求後,會首先檢視此鍵值對是否該由自己來處理,是則繼續往下執行;否則會產生乙個類似於 http 3xx 的重定向,要求客戶端去請求集群中的另乙個 redis。
redis 每乙個例項都會通過遵守一定的協議來維護這個集群的可用性,穩定性。有興趣可前往官網了解 redis 集群的實現細則。
Redis一致性方案
儘管到目前為止,我在專案中很少遇到快取不一致問題,僅有一次是因為 原因。就是那次讓我考慮快取不一致的解決方案,網上有很方案,例如加鎖,訊息佇列,或延遲刪除,還有監控binlog日誌,以及用lua實現樂觀鎖,但我以為這些方案都不是太理想,要麼增加了系統的複雜度,要麼不能做到實時一致性。一天我漫步在乙個...
redis集群方案 一致性hash演算法
前奏集群的概念早在 redis 3.0 之前討論了,3.0 才在原始碼中出現。redis 集群要考慮的問題 節點之間怎麼據的同步,如何做到資料一致性。一主一備的模式,可以用 redis 內部實現的主從備份實現資料同步。但節點不斷增多,存在多個 master 的時候,同步的難度會越大。如何做到負載均衡...
最終一致性方案
訊息傳送一致性 微服務架構下,需要通過網路進行通訊,就自然引入了資料傳輸的不確定性,也就是cap原理中的p 分割槽容錯,而這裡的訊息傳送一致性是可靠訊息的保證。生成訊息的業務動作與訊息傳送的一致 e.g 如果業務操作成功,那麼由這個業務操作所產生的訊息一定會成功投遞出去,否則就丟失訊息 如上圖,保證...