單機/單點
- 單點故障/瓶頸:多個節點負載:面向數據:
- 一變多(一致性<弱一致,最終一致性>)》可用性
- 最終一致性:一部分角色確認 》 網絡分區(腦裂)》過半機制
鏡像:數據容量不變
切片:橫向擴展
集群分類
- 主從復制 Replication:鏡像:增刪改(主<退化到單節點>)查詢負載到從節點
高可用 Sentinel - 分布式 twemproxy:切片
集群 Cluster
Redis主從復制
主從復制 Replication
- 一個Redis服務可以有多個該服務的復制品,這個Redis服務稱為Master,其他復制品稱為Slaves
- 只要網絡連接正常,Master會一直將自己的數據更新同步給Slaves,保持主從同步
- 只有Master可以執行寫命令,Slaves只能執行讀命令
- 從服務器執行客戶端發送的讀命令,比如GET、LRANGE、SMEMMBERS、HGET、ZRANGE等等
- 客戶端可以連接Slaves執行讀請求,來降低Master的讀壓力
主從復制創建
- redis-server --slaveof <master-ip> <master-port>,配置當前服務稱為某Redis服務的Slave
- redis-server --port 6380 --slaveof 127.0.0.1 6379
- SLAVEOF host port命令,將當前服務器狀態從Master修改為別的服務器的Slave
- redis > SLAVEOF 192.168.1.1 6379,將服務器轉換為Slave
- redis > SLAVEOF NO ONE ,將服務器重新恢復到Master,不會丟棄已同步數據
- 配置方式:啟動時,服務器讀取配置文件,并自動成為指定服務器的從服務器
- slaveof <masterip> <masterport>
- slaveof 127.0.0.1 6379
主從復制演示
redis-server --slaveof <master-ip> <master-port>
redis-server --port 6380 --slaveof 127.0.0.1 6379
redis-cli -p 6380 -n 0
測試Master和Slave的讀寫SLAVEOF 命令
從服務器連接到192.168.56.201的6379端口
redis > SLAVEOF 192.168.56.201 6379
redis > SLAVEOF NO ONE ,將服務器重新恢復到Master,不會丟棄已同步數據
redis > SET n2key 5
redis > get n2key
redis > keys *
redis > SLAVEOF 192.168.56.201 6379
redis > keys *配置方式
在node2節點安裝配置redis服務,修改配置文件
slaveof 192.168.56.201 6379
啟動服務,觀察和node1的同步
redis > SLAVEOF NO ONE,觀察是否可寫set、keys *
主從復制問題
- 一個Master可以有多個Slaves
- Slave下線,只是讀請求的處理性能下降
- Master下線,寫請求無法執行
- 其中一臺Slave使用SLAVEOF no one命令成為Master,其它Slaves執行SLAVEOF命令指向這個新的Master,從它這里同步數據
以上過程是手動的,能夠實現自動,這就需要Sentinel哨兵,實現故障轉移Failover操作
Redis哨兵
高可用 Sentinel
- 官方提供的高可用方案,可以用它管理多個Redis服務實例
- 編譯后產生redis-sentinel程序文件
- Redis Sentinel是一個分布式系統,可以在一個架構中運行多個Sentinel進程
啟動 Sentinel
- 將src目錄下產生redis-sentinel程序文件復制到$REDIS_HOME/bin
- 啟動一個運行在Sentinel模式下的Redis服務實例
- redis-sentinel
- redis-server /path/to/sentinel.conf --sentinel
- Redis Sentinel是一個分布式系統,可以在一個架構中運行多個Sentinel進程
監控 Monitoring
- Sentinel會不斷檢查Master和Slaves是否正常
- 每一個Sentinel可以監控任意多個Master和該Master下的Slaves
Sentinel網絡
監控同一個Master的Sentinel會自動連接,組成一個分布式的Sentinel網絡,互相通信并交換彼此關于被監視服務器的信息。
下圖中3個Sentinel監控著S1和它的2個Slave:
服務器下線
- 當一個sentinel認為被監視的服務器已經下線時,它會向網絡中的其他Sentinel進行確認,判斷該服務器是否真的已經下線
- 如果下線的服務器為主服務器,那么sentinel網絡將對下線主服務器進行自動故障轉移,通過將下線主服務器的某個從服務器提升為新的主服務器,并讓其從服務器轉為復制新的主服務器,以此來讓系統重新回到上線的狀態
服務器下線后重新上線
Sentinel 配置文件
- 至少包含一個監控配置選項,用于指定被監控Master的相關信息
- Sentinel monitor<name><ip><port><quorum>,
例如 sentinel monitor mymaster 127.0.0.1 6379 2
監視mymaster的主服務器,服務器ip和端口,將這個主服務器判斷為下線失效至少需要2個Sentinel同意,如果多數Sentinel同意才會執行故障轉移 - Sentinel會根據Master的配置自動發現Master的Slaves
- Sentinel默認端口號為26379
Sentinel 配置舉例
- 執行以下兩條命令,將創建兩個監視主服務器s1的sentinel實例:
$redis-sentinel sentinel1.conf
$redis-sentinel sentinel2.conf - 其中sentinel1.conf的內容為:
port 26379
Sentinel monitor s1 127.0.0.1 6380 1 - sentinel2.conf的內容為:
Port 26380
Sentinel monitor s1 127.0.0.1 6379 2
Sentinel 實驗
Sentinel 總結
- 主從復制,解決了讀請求的分擔,從節點下線,會使得讀請求能力有所下降;
- Master只有一個,寫請求單點問題;
- Sentinel會在Master下線后自動執行Failover操作,提升一臺Slave為Master,并讓其他Slaves重新成為新Master的Slaves;
- 主從復制+哨兵Sentinel只解決了讀性能和高可用問題,但是沒有解決寫性能問題。
問題引出
- 主從對寫壓力沒有分擔
- 解決思路就是,使用多個節點分擔,將寫請求分散到不同節點處理
- 分片Sharding:多節點分擔的思路就是關系型數據庫處理大表的水平切分思路
Redis Twemproxy
Twemproxy
- Twitter開發,代理用戶的讀寫請求
- Twitter開發的代理服務器,他兼容Redis和Memcached,允許用戶將多個redis服務器添加到一個服務器池(pool)里面,并通過用戶選擇的散列函數和分布函數,將來自客戶端的命令請求分發給服務器池中的各個服務器
- 通過使用twemproxy我們可以將數據庫分片到多臺redis服務器上面,并使用這些服務器來分擔系統壓力以及數據庫容量:在服務器硬件條件相同的情況下,對于一個包含N臺redis服務器的池來說,池中每臺平均1/N的客戶端命令請求
- 向池里添加更多服務器可以線性的擴展系統處理命令請求的能力,以及系統能夠保存的數據量
Twemproxy配置
sxt:
listen: 192.168.56.201:22121
hash: fnv1a_64
distribution: ketama
auto_eject_hosts: true
redis: true
server_retry_timeout: 2000
server_failure_limit: 3
servers:
- 192.168.56.201:6379:1
- 192.168.56.202:6379:1
- 192.168.56.203:6379:1
Twemproxy配置說明
sxt,服務器池的名字,支持創建多個服務器池
listen: 192.168.56.201:22121,這個服務器池的監聽地址和端口號
hash: fnv1a_64,鍵散列算法,用于將鍵映射為一個散列值
distribution: ketama,鍵分布算法,決定鍵被分布到哪個服務器
redis: true,代理redis命令請求,不給定時默認代理memcached請求
servers,池中各個服務器的地址和端口號及權重
auto_eject_hosts、
server_failure_limit: twemproxy連續3次向同一個服務器發送命令請求都遇到錯誤時,twemproxy就會將該服務器標記為下線,并交由池中其他在線服務器處理
問題:如何監聽本地所有地址的某個端口
Twemproxy運行
nutcracker -d -c /opt/sxt/twemproxy/conf/nutcracker.sxt.yml
redis-cli -p 22121 -h 192.168.56.201
節點下線
經過重試次數后,將Redis置為下線
127.0.0.1:22121> get mykey
"123"
127.0.0.1:22121> get mykey
(error) ERR Connection refused
127.0.0.1:22121> get mykey
(error) ERR Connection refused
127.0.0.1:22121> get mykey
(nil)
error到nil的變化,說明代理之前是把key的訪問執行原來的服務器,置為下線后,將key的訪問交給了其它服務器處理.
節點上線
經過重試次數后,將Redis置為下線
127.0.0.1:22121> get mykey
"123"
127.0.0.1:22121> get mykey
(error) ERR Connection refused
127.0.0.1:22121> get mykey
(nil)
error到nil的變化,說明代理之前是把key的訪問執行原來的服務器,置為下線后,將key的訪問交給了其它服務器處理.
Redis服務恢復后,原來這個key的值可以再次取到
重試超時配置
server_retry_timeout <time>選項
當一個服務器被twemproxy判斷為下線之后,在time毫秒之內,twemproxy不會再嘗試向下線的服務器發送命令請求,但是在time毫秒之后,服務器會嘗試重新向下線的服務器發送命令請求
如果命令請求能夠正常執行,那么twemproxy就會撤銷對該服務器的下線判斷,并再次將鍵交給那個服務器來處理
但如果服務器還是不能正常處理命令請求,那么twemproxy就會繼續將原本應該交給下線服務器的鍵轉交給其他服務器來處理,并等待下一次重試的來臨
總結
- 前端使用 Twemproxy 做代理,后端的 Redis 數據能基本上根據 key 來進行比較均衡的分布
- 后端一臺 Redis 掛掉后,Twemproxy 能夠自動摘除。恢復后,Twemproxy 能夠自動識別、恢復并重新加入到 Redis 組中重新使用
- Redis 掛掉后,后端數據是否丟失依據 Redis 本身的持久化策略配置,與 Twemproxy 基本無關
- 如果要新增加一臺 Redis,Twemproxy 需要重啟才能生效;并且數據不會自動重新 Reblance,需要人工單獨寫腳本來實現
- 如原來已經有 2 個節點 Redis,后續有增加 2 個 Redis,則數據分布計算與原來的 Redis 分布無關,現有數據如果需要分布均勻的話,需要人工單獨處理
- 如果 Twemproxy 的后端節點數量發生變化,Twemproxy 相同算法的前提下,原來的數據必須重新處理分布,否則會存在找不到key值的情況
- 不管 Twemproxy 后端有幾臺 Redis,前端的單個 Twemproxy 的性能最大也只能和單臺 Redis 性能差不多
- 如同時部署多臺 Twemproxy 配置一樣,客戶端分別連接多臺 Twemproxy可以在一定條件下提高性能
整合方案
- redis-mgr
- 整合了通過整合復制、Sentinel以及twemproxy等組件,提供了一站式的Redis服務器部署、監控、遷移功能,網址https://github.com/changyibiao/redis-mgr
Redis集群
Redis集群
- 3.0支持
- 由多個Redis服務器組成的分布式網絡服務集群
- 每一個Redis服務器稱為節點Node,節點之間會互相通信。兩兩相連
- Redis集群無中心節點
Redis集群節點復制
- Redis集群的每個節點都有兩種角色可選:主節點master node、從節點slave node。其中主節點用于存儲數據,而從節點則是某個主節點的復制品
- 當用戶需要處理更多讀請求的時候,添加從節點可以擴展系統的讀性能,因為Redis集群重用了單機Redis復制特性的代碼,所以集群的復制行為和我們之前介紹的單機復制特性的行為是完全一樣的
Redis集群故障轉移
- Redis集群的主節點內置了類似Redis Sentinel的節點故障檢測和自動故障轉移功能,當集群中的某個主節點下線時,集群中的其他在線主節點會注意到這一點,并對已下線的主節點進行故障轉移
- 集群進行故障轉移的方法和Redis Sentinel進行故障轉移的方法基本一樣,不同的是,在集群里面,故障轉移是由集群中其他在線的主節點負責進行的,所以集群不必另外使用Redis Sentinel
Redis集群分片
- 集群將整個數據庫分為16384個槽位slot,所有key都數據這些slot中的一個,key的槽位計算公式為slot_number=crc16(key)%16384,其中crc16為16位的循環冗余校驗和函數
- 集群中的每個主節點都可以處理0個至16383個槽,當16384個槽都有某個節點在負責處理時,集群進入上線狀態,并開始處理客戶端發送的數據命令請求
舉例
三個主節點7000、7001、7002平均分片16384個slot槽位
節點7000指派的槽位為0到5060
節點7001指派的槽位為5461到10022
節點7002指派的槽位為10923到16383
節點7003指派的槽位為5061到5460,10023-10922
Redis集群Redirect轉向
- 由于Redis集群無中心節點,請求會發給任意主節點
- 主節點只會處理自己負責槽位的命令請求,其它槽位的命令請求,該主節點會返回客戶端一個轉向錯誤
- 客戶端根據錯誤中包含的地址和端口重新向正確的負責的主節點發起命令請求
Redis集群搭建
- 創建多個主節點
- 為每一個節點指派slot,將多個節點連接起來,組成一個集群
- 槽位分片完成后,集群進入上線狀態
- 6個節點:3個主節點,每一個主節點有一個從節點
Redis集群總結
- Redis集群是一個由多個節點組成的分布式服務集群,它具有復制、高可用和分片特性
- Redis的集群沒有中心節點,并且帶有復制和故障轉移特性,這可用避免單個節點成為性能瓶頸,或者因為某個節點下線而導致整個集群下線
- 集群中的主節點負責處理槽(儲存數據),而從節點則是主節點的復制品
- Redis集群將整個數據庫分為16384個槽,數據庫中的每個鍵都屬于16384個槽中的其中一個
- 集群中的每個主節點都可以負責0個至16384個槽,當16384個槽都有節點在負責時,集群進入上線狀態,可以執行客戶端發送的數據命令
- 主節點只會執行和自己負責的槽有關的命令,當節點接收到不屬于自己處理的槽的命令時,它將會處理指定槽的節點的地址返回給客戶端,而客戶端會向正確的節點重新發送
- 如果需要完整地分片、復制和高可用特性,并且要避免使用代理帶來的性能瓶頸和資源消耗,那么可以選擇使用Redis集群;如果只需要一部分特性(比如只需要分片,但不需要復制和高可用等),那么單獨選用twemproxy、Redis的復制和Redis Sentinel中的一個或多個