Redis 高可用性解決方案之哨兵與集群
前言
在開(kāi)始本章的講解之前,我們首先從宏觀角度回顧一下 Redis 實(shí)現(xiàn)高可用相關(guān)的技術(shù)。它們包括:持久化、復(fù)制、哨兵和集群,在本系列的前篇文章介紹了持久化以及復(fù)制的原理以及實(shí)現(xiàn)。本文將對(duì)剩下的兩種高可用技術(shù)哨兵、集群進(jìn)行講解,講一講它們是如何進(jìn)一步提高系統(tǒng)的高可用性?
Redis 的主從復(fù)制模式下,一旦主節(jié)點(diǎn)由于故障不能提供服務(wù),需要手動(dòng)將從節(jié)點(diǎn)晉升為主節(jié)點(diǎn),同時(shí)還要通知客戶端更新主節(jié)點(diǎn)地址,這種故障處理方式從一定程度上是無(wú)法接受的。Redis 2.8 以后提供了 Redis Sentinel 哨兵機(jī)制來(lái)解決這個(gè)問(wèn)題。
在 Redis 3.0 之前,使用哨兵(sentinel)機(jī)制來(lái)監(jiān)控各個(gè)節(jié)點(diǎn)之間的狀態(tài)。Redis Cluster 是 Redis 的分布式解決方案,在 3.0 版本正式推出,有效地解決了 Redis 在分布式方面的需求。當(dāng)遇到單機(jī)內(nèi)存、并發(fā)、流量等瓶頸時(shí),可以采用 Cluster 架構(gòu)方案達(dá)到負(fù)載均衡的目的。
Redis HA 實(shí)踐(Redis Sentinel)
Redis Sentinel 概述
Sentinel(哨崗、哨兵)是 Redis 的高可用(high availability)解決方案:由一個(gè)或多個(gè) Sentinel 實(shí)例(instance)組成的 Sentinel 系統(tǒng)(system)可以監(jiān)視任意多個(gè)主服務(wù)器,以及這些主服務(wù)器屬下的所有從服務(wù)器,并在被監(jiān)視的主服務(wù)器進(jìn)入下線狀態(tài)時(shí),自動(dòng)將下線主服務(wù)器屬下的某個(gè)從服務(wù)器升級(jí)為新的主服務(wù)器,然后由新的主服務(wù)器代替已下線的主服務(wù)器繼續(xù)處理命令請(qǐng)求。


當(dāng) server1 的下線時(shí)長(zhǎng)超過(guò)用戶設(shè)定的下線時(shí)長(zhǎng)上限時(shí),Sentinel 系統(tǒng)就會(huì)對(duì) server1 執(zhí)行故障轉(zhuǎn)移操作:
首先,Sentinel 系統(tǒng)會(huì)挑選 server1 屬下的其中一個(gè)從服務(wù)器,并將這個(gè)被選中的從服務(wù)升級(jí)為新的主服務(wù)器。
之后,Sentinel 系統(tǒng)會(huì)向 server1 屬下的所有從服務(wù)器發(fā)送新的復(fù)制指令,讓他們成為新的主服務(wù)器的從服務(wù)器,當(dāng)所有從服務(wù)器都開(kāi)始復(fù)制新的主服務(wù)器時(shí),故障轉(zhuǎn)移操作執(zhí)行完畢。
另外,Sentinel 還會(huì)繼續(xù)監(jiān)視已下線的 server1,并在它重新上線時(shí),將它設(shè)置為新的主服務(wù)器的從服務(wù)器。
Sentinel 系統(tǒng)用于管理多個(gè) Redis 服務(wù)器(instance), 該系統(tǒng)執(zhí)行以下三個(gè)任務(wù):
監(jiān)控(Monitoring):Sentinel 會(huì)不斷地檢查你的主服務(wù)器和從服務(wù)器是否運(yùn)作正常。
提醒(Notification):當(dāng)被監(jiān)控的某個(gè) Redis 服務(wù)器出現(xiàn)問(wèn)題時(shí), Sentinel 可以通過(guò) API 向管理員或者其他應(yīng)用程序發(fā)送通知。
自動(dòng)故障遷移(Automatic failover):當(dāng)一個(gè)主服務(wù)器不能正常工作時(shí), Sentinel 會(huì)開(kāi)始一次自動(dòng)故障遷移操作, 它會(huì)將失效主服務(wù)器的其中一個(gè)從服務(wù)器升級(jí)為新的主服務(wù)器, 并讓失效主服務(wù)器的其他從服務(wù)器改為復(fù)制新的主服務(wù)器;當(dāng)客戶端試圖連接失效的主服務(wù)器時(shí), 集群也會(huì)向客戶端返回新主服務(wù)器的地址, 使得集群可以使用新主服務(wù)器代替失效服務(wù)器。
Redis Sentinel 重點(diǎn)總結(jié)
Sentinel 只是一個(gè)運(yùn)行在特殊模式下的 Redis 服務(wù)器,因此初始化服務(wù)器時(shí)將普通 Redis 服務(wù)器使用的代碼替換成 Sentinel 專門代碼,它使用了和普通模式不同的命令表,所以 Sentinel 模式能夠使用的命令和普通 Redis 服務(wù)器能夠使用的命令不同。
Sentinel 會(huì)讀入用戶指定的配置文件,為每個(gè)要被監(jiān)視的主服務(wù)器創(chuàng)建相應(yīng)的實(shí)例結(jié)構(gòu),并創(chuàng)建連向主服務(wù)器的命令連接和訂閱連接,其中命令連接用于向主服務(wù)器發(fā)送命令請(qǐng)求,而訂閱連接則用于接收指定頻道的消息。
Sentinel 通過(guò)主服務(wù)器發(fā)送 INFO 命令來(lái)獲得主服務(wù)器屬下所有從服務(wù)器的地址信息,并為這些從服務(wù)器創(chuàng)建相應(yīng)的實(shí)例結(jié)構(gòu),以及連向這些從服務(wù)器的命令連接和訂閱連接。在一般情況下,Sentinel 以每十秒一次的頻率向被監(jiān)視的主服務(wù)器和從服務(wù)器發(fā)送 INFO 命令,當(dāng)主服務(wù)器處于下線狀態(tài),或者 Sentinel 正在對(duì)主服務(wù)器進(jìn)行故障轉(zhuǎn)移操作時(shí),Sentinel 向從服務(wù)器發(fā)送 INFO 命令的頻率會(huì)改為每秒一次。
對(duì)于監(jiān)視同一個(gè)主服務(wù)器和從服務(wù)器的多個(gè) Sentinel 來(lái)說(shuō),它們會(huì)以每?jī)擅胍淮蔚念l率,通過(guò)向被監(jiān)視服務(wù)器的 _sentinel_:hello 頻道發(fā)送消息來(lái)向其他 Sentinel 宣告自己的存在。每個(gè) Sentinel 也會(huì)從 _sentinel_:hello 頻道中接收其他 Sentinel 發(fā)來(lái)的消息,并根據(jù)這些消息為其他 Sentinel 創(chuàng)建相應(yīng)的實(shí)例結(jié)構(gòu)以及命令連接。Sentinel 只會(huì)與主服務(wù)器和從服務(wù)器創(chuàng)建命令連接和訂閱連接,Sentinel 與 Sentinel 之間則只創(chuàng)建命令連接。
Sentinel 以每秒一次的頻率向?qū)嵗òㄖ鞣?wù)器、從服務(wù)器、其他 Sentinel)發(fā)送 PING 命令,并根據(jù)實(shí)例對(duì) PING 命令的回復(fù)來(lái)判斷實(shí)例是否在線,當(dāng)一個(gè)實(shí)例在指定的時(shí)長(zhǎng)中連續(xù)向 Sentinel 發(fā)送無(wú)效回復(fù)時(shí),Sentinel 會(huì)將這個(gè)實(shí)例判斷為主觀下線。
當(dāng) Sentinel 將一個(gè)主服務(wù)器判斷為主觀下線時(shí),它會(huì)向同樣監(jiān)視這個(gè)主服務(wù)器的其它 Sentinel 進(jìn)行詢問(wèn),看它們是否同意這個(gè)主服務(wù)器已經(jīng)進(jìn)入主觀下線狀態(tài)。當(dāng) Sentinel 收集到足夠多的的主觀下線投票之后,它會(huì)將主服務(wù)器判斷為客觀下線,并發(fā)起一次針對(duì)主服務(wù)器的故障轉(zhuǎn)移操作。
當(dāng)一個(gè)主服務(wù)器被判斷為客觀下線時(shí),監(jiān)視這個(gè)下線主服務(wù)器的各個(gè) Sentinel 會(huì)進(jìn)行協(xié)商,選舉出一個(gè)領(lǐng)頭 Sentinel[1],并由領(lǐng)頭 Sentinel 對(duì)下線主服務(wù)器進(jìn)行故障轉(zhuǎn)移操作。
Redis Sentinel 搭建
Redis Sentinel 部署技巧及其環(huán)境
一個(gè)健壯的部署至少需要三個(gè)哨兵實(shí)例,并且使用奇數(shù)個(gè) Sentinel。
三個(gè)哨兵實(shí)例應(yīng)該放置在客戶使用獨(dú)立方式確認(rèn)故障的計(jì)算機(jī)或虛擬機(jī)中,例如不同的物理機(jī)或不同可用區(qū)域的虛擬機(jī)。
哨兵配置文件中只需要配置主從復(fù)制中的主副本 ip 和端口即可,當(dāng)主從進(jìn)行切換時(shí)哨兵會(huì)自動(dòng)修改哨兵配置文件中的主副本 ip 為新在主副本 ip。

由于本人沒(méi)有這么多服務(wù)器,因此在一臺(tái)機(jī)器上模擬一個(gè) Redis Sentinel 集群。
| 角色 | IP 地址 | 端口號(hào) |
|---|---|---|
| Redis Master | 127.0.0.1 | 6380 |
| Redis Slave-01 | 127.0.0.1 | 6381 |
| Redis Slave-02 | 127.0.0.1 | 6382 |
| Redis Slave-03 | 127.0.0.1 | 6383 |
| Redis Sentinel-01 | 127.0.0.1 | 26381 |
| Redis Sentinel-02 | 127.0.0.1 | 26382 |
| Redis Sentinel-03 | 127.0.0.1 | 26383 |
Redis Sentinel 安裝指南
1、下載 Redis 服務(wù)軟件包到服務(wù)器,解壓后并編譯安裝。
[root@VM_24_98_centos ~]# mkdir /usr/local/redis
[root@VM_24_98_centos ~]# wget http://download.redis.io/releases/redis-5.0.6.tar.gz
[root@VM_24_98_centos ~]# tar -zvxf redis-5.0.6.tar.gz -C /usr/local/redis
[root@VM_24_98_centos ~]# cd /usr/local/redis/redis-5.0.6/
[root@VM_24_98_centos redis-5.0.6]# make PREFIX=/usr/local/redis install
2、設(shè)置 Redis 主服務(wù)器
a. 創(chuàng)建目錄以及復(fù)制配置文件
[root@VM_24_98_centos redis]# mkdir -p /usr/local/redis/redis-master/redis-6380
[root@VM_24_98_centos redis-master]# cp -r /usr/local/redis/redis-5.0.6/redis.conf /usr/local/redis/redis-master/redis-6380/
[root@VM_24_98_centos redis-master]# vim /usr/local/redis/redis-master/redis-6380/redis.conf
b. 設(shè)置 Redis Master 主服務(wù)器配置環(huán)境
# 開(kāi)啟遠(yuǎn)程連接
bind 0.0.0.0
# 端口號(hào)
port 6380
# 守護(hù)進(jìn)程
daemonize yes
# 進(jìn)程文件
pidfile /usr/local/redis/redis-master/redis-6380/redis.pid
# 日志文件
logfile /usr/local/redis/redis-master/redis-6380/redis.log
# 工作目錄
dir /usr/local/redis/redis-master/redis-6380/
# 主服務(wù)器密碼
masterauth foobared
# 認(rèn)證密碼
requirepass foobared
# 開(kāi)啟 AOF 持久化
appendonly yes
# 每秒調(diào)用一次 fsync
appendfsync everysec
c. 啟動(dòng) Redis Master 主服務(wù)器
[root@VM_24_98_centos redis-6380]# /usr/local/redis/bin/redis-server /usr/local/redis/redis-master/redis-6380/redis.conf
[root@VM_24_98_centos redis-6380]# ps -ef |grep redis
d. 客戶端測(cè)試連接
[root@VM_24_98_centos ~]# /usr/local/redis/bin/redis-server /usr/local/redis/redis-master/redis-6380/redis.conf
[root@VM_24_98_centos ~]# /usr/local/redis/bin/redis-cli -h 127.0.0.1 -p 6380 -a foobared
127.0.0.1:6380> INFO REPLICATION
# Replication
role:master
connected_slaves:0
master_replid:5c1034ac4dec31d6a4ae883e1eaacca3a78bc3b6
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
3、設(shè)置 Redis 從服務(wù)器
a. 創(chuàng)建目錄以及復(fù)制配置文件
[root@VM_24_98_centos redis]# mkdir -p /usr/local/redis/redis-slave/redis-6381
[root@VM_24_98_centos redis-slave]# cp -r /usr/local/redis/redis-5.0.6/redis.conf /usr/local/redis/redis-slave/redis-6381/
[root@VM_24_98_centos redis-slave]# vim /usr/local/redis/redis-slave/redis-6381/redis.conf
b. 設(shè)置 Redis Slave 從服務(wù)器配置環(huán)境
# 開(kāi)啟遠(yuǎn)程連接
bind 0.0.0.0
# 端口號(hào)
port 6381
# 守護(hù)進(jìn)程
daemonize yes
# 進(jìn)程文件
pidfile /usr/local/redis/redis-slave/redis-6381/redis.pid
# 日志文件
logfile /usr/local/redis/redis-slave/redis-6381/redis.log
# 工作目錄
dir /usr/local/redis/redis-slave/redis-6381/
# 主從復(fù)制 Master 節(jié)點(diǎn)地址 + 端口
replicaof 127.0.0.1 6380
# 主服務(wù)器密碼
masterauth foobared
# 認(rèn)證密碼
requirepass foobared
# 開(kāi)啟 AOF 持久化
appendonly yes
# 每秒調(diào)用一次 fsync
appendfsync everysec
c. 啟動(dòng) Redis Slave 從服務(wù)器
[root@VM_24_98_centos redis-6381]# /usr/local/redis/bin/redis-server /usr/local/redis/redis-slave/redis-6381/redis.conf
[root@VM_24_98_centos redis-6381]# ps -ef |grep redis
d. 客戶端測(cè)試連接
[root@VM_24_98_centos ~]# /usr/local/redis/bin/redis-server /usr/local/redis/redis-slave/redis-6381/redis.conf
[root@VM_24_98_centos ~]# /usr/local/redis/bin/redis-cli -h 127.0.0.1 -p 6381 -a foobared
127.0.0.1:6381> INFO REPLICATION
# Replication
role:slave
master_host:127.0.0.1
master_port:6380
master_link_status:up
master_last_io_seconds_ago:5
master_sync_in_progress:0
slave_repl_offset:14
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:8ecb8d89dba51e54aabb1c7feeda42fe6e6a8dc0
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:14
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:14
e. 同理,從服務(wù)器 redis-6382、redis-6383 按照上面的步驟部署。
4、Redis Sentinel 部署
a. 創(chuàng)建目錄以及復(fù)制配置文件
[root@VM_24_98_centos redis]# mkdir -p /usr/local/redis/redis-sentinel/redis-26381
[root@VM_24_98_centos redis-sentinel]# cp -r /usr/local/redis/redis-5.0.6/sentinel.conf /usr/local/redis/redis-sentinel/redis-26381/
[root@VM_24_98_centos redis-sentinel]# vim /usr/local/redis/redis-sentinel/redis-26381/sentinel.conf
b. 設(shè)置 Redis Sentinel 哨兵服務(wù)器配置環(huán)境
# 端口號(hào)
port 26381
# 守護(hù)進(jìn)程
daemonize yes
# 進(jìn)程文件
pidfile /usr/local/redis/redis-sentinel/redis-26381/redis.pid
# 日志文件
logfile /usr/local/redis/redis-sentinel/redis-26381/redis.log
# 工作目錄
dir /usr/local/redis/redis-sentinel/redis-26381/
# 指定監(jiān)控 master{2 表示多少個(gè) sentinel 同意}
sentinel monitor mymaster 127.0.0.1 6380 2
# 安全信息
sentinel auth-pass mymaster foobared
c. 啟動(dòng) Redis Sentinel 哨兵服務(wù)器
[root@VM_24_98_centos redis-26381]# /usr/local/redis/bin/redis-sentinel /usr/local/redis/redis-sentinel/redis-26381/sentinel.conf
[root@VM_24_98_centos redis-26381]# ps -ef |grep redis
d. 客戶端測(cè)試連接
[root@VM_24_98_centos ~]# /usr/local/redis/bin/redis-cli -h 127.0.0.1 -p 26381
127.0.0.1:26381> INFO SENTINEL
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=127.0.0.1:6380,slaves=3,sentinels=1
e. 同理,哨兵服務(wù)器 redis-26382、redis-26383 按照上面的步驟部署
f. 查看 Redis Master 主服務(wù)器連接狀況
[root@VM_24_98_centos ~]# /usr/local/redis/bin/redis-cli -h 127.0.0.1 -p 6380 -a foobared
127.0.0.1:6380> INFO REPLICATION
# Replication
role:master
connected_slaves:3
slave0:ip=127.0.0.1,port=6383,state=online,offset=20836,lag=0
slave1:ip=127.0.0.1,port=6381,state=online,offset=20836,lag=0
slave2:ip=127.0.0.1,port=6382,state=online,offset=20836,lag=0
master_replid:cc8ef3fe2e51a714f5b73b2fbe3bd697cacbc453
master_replid2:8ecb8d89dba51e54aabb1c7feeda42fe6e6a8dc0
master_repl_offset:20836
second_repl_offset:1522
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:20836
Redis Sentinel 場(chǎng)景測(cè)試
模擬場(chǎng)景:Redis Master 節(jié)點(diǎn)掛掉,查看 Redis 集群狀態(tài)。
Step1、關(guān)掉 Master 節(jié)點(diǎn)
[root@VM_24_98_centos ~]# /usr/local/redis/bin/redis-cli -h 127.0.0.1 -p 6380 -a foobared
127.0.0.1:6380> SHUTDOWN
Step2、通過(guò)哨兵查看集群狀態(tài)
[root@VM_24_98_centos ~]# /usr/local/redis/bin/redis-cli -h 127.0.0.1 -p 26381
127.0.0.1:26381> INFO SENTINEL
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=127.0.0.1:6381,slaves=3,sentinels=3
通過(guò) Sentinel 信息可以看到,Master 節(jié)點(diǎn)已經(jīng)自動(dòng)切換到 6381 端口了,說(shuō)明主節(jié)點(diǎn)掛掉后,6381 Slave 節(jié)點(diǎn)自動(dòng)升級(jí)成為了 Master 節(jié)點(diǎn)。
通過(guò) Sentinel 日志文件顯示了 failover 的過(guò)程:

Step3、啟動(dòng) 6380 Redis 服務(wù),然后查看節(jié)點(diǎn)角色,此時(shí) 6380 變成了 Slave,6381 為 Master 節(jié)點(diǎn)
[root@VM_24_98_centos ~]# /usr/local/redis/bin/redis-server /usr/local/redis/redis-master/redis-6380/redis.conf
[root@VM_24_98_centos ~]# /usr/local/redis/bin/redis-cli -h 127.0.0.1 -p 6380 -a foobared
127.0.0.1:6380> INFO REPLICATION
# Replication
role:slave
master_host:127.0.0.1
master_port:6381
master_link_status:up
master_last_io_seconds_ago:1
master_sync_in_progress:0
slave_repl_offset:782228
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:84aa69ee0b191bba31162c26c4ddb1c87a705f7e
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:782228
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:777789
repl_backlog_histlen:4440
Redis HA 實(shí)踐(Redis Cluster)
Redis Cluster 概述
Redis 集群是 Redis 提供的分布式數(shù)據(jù)庫(kù)方案,集群通過(guò)分片(sharding)而非一致性哈希(consistency hashing)來(lái)進(jìn)行數(shù)據(jù)分享,并提供復(fù)制和故障轉(zhuǎn)移功能。Redis Cluster,主要是針對(duì)海量數(shù)據(jù) + 高并發(fā) + 高可用的場(chǎng)景。Redis Cluster 支撐 N 個(gè) Redis Master Node,每個(gè) Master Node 都可以掛載多個(gè) Slave Node。Redis Cluster 節(jié)點(diǎn)間采用 Gossip 協(xié)議[2]進(jìn)行通信。
節(jié)點(diǎn):一個(gè) Redis 集群通常由多個(gè)節(jié)點(diǎn)(node)組成,連接各個(gè)節(jié)點(diǎn)的工作可以使用 CLUSTER MEET <ip> <port> 命令來(lái)完成,將各個(gè)獨(dú)立的節(jié)點(diǎn)連接起來(lái),構(gòu)成一個(gè)包含多個(gè)節(jié)點(diǎn)的集群。向一個(gè)節(jié)點(diǎn) node 發(fā)送 CLUSTER MEET 命令,可以讓 node 節(jié)點(diǎn)與 ip 和 port 所指定的節(jié)點(diǎn)進(jìn)行握手(handshake),當(dāng)握手成功時(shí),node 節(jié)點(diǎn)就會(huì)將 ip 和 port 所指定的節(jié)點(diǎn)添加到 node 節(jié)點(diǎn)當(dāng)前所在的集群中。
槽指派:Redis 集群通過(guò)分片的方式來(lái)保存數(shù)據(jù)庫(kù)中的鍵值對(duì),集群的整數(shù)據(jù)庫(kù)被分為 16384 個(gè)槽(slot),數(shù)據(jù)庫(kù)中的每個(gè)鍵都屬于這 16384 個(gè)槽的其中一個(gè),集群中的每個(gè)節(jié)點(diǎn)可以處理 0 個(gè)或最多 16384 個(gè)槽。Redis 集群有固定的 16384 個(gè) hash slot,對(duì)每個(gè) key 計(jì)算 CRC16 值,然后對(duì) 16384 取模,可以獲取 key 對(duì)應(yīng)的 hash slot。當(dāng)數(shù)據(jù)庫(kù)中的 16384 個(gè)槽都有節(jié)點(diǎn)在處理時(shí),集群處于上線狀態(tài)(ok);相反地,如果數(shù)據(jù)庫(kù)中任何一個(gè)槽沒(méi)有得到處理,那么集群處于下線狀態(tài)(fail)。

Redis Cluster 重點(diǎn)總結(jié)
節(jié)點(diǎn)通過(guò)握手來(lái)將其他節(jié)點(diǎn)添加到自己所處的集群當(dāng)中。
集群中的 16384(2的14次方)個(gè)槽可以分別指派給集群中的各個(gè)節(jié)點(diǎn),每個(gè)節(jié)點(diǎn)都會(huì)記錄哪些槽指派給了自己,而哪些槽又被指派給其他節(jié)點(diǎn)。
節(jié)點(diǎn)在接到一個(gè)命令請(qǐng)求時(shí),會(huì)先檢查這個(gè)命令請(qǐng)求要處理的鍵所在的槽是否由自己負(fù)責(zé),如果不是的話,節(jié)點(diǎn)將向客戶端返回一個(gè) MOVED 錯(cuò)誤,MOVED 錯(cuò)誤攜帶的信息可以指引客戶端轉(zhuǎn)向至正在負(fù)責(zé)相關(guān)槽的節(jié)點(diǎn)。
對(duì) Redis 集群的重新分片工作是由 redis-trib 負(fù)責(zé)執(zhí)行的,重新分片的關(guān)鍵是將屬于某個(gè)槽的所有鍵值對(duì)從一個(gè)節(jié)點(diǎn)轉(zhuǎn)移至另外一個(gè)節(jié)點(diǎn)。重新分片操作可以在線(online)進(jìn)行,在重新分片的過(guò)程中,集群不需要下線,并且源節(jié)點(diǎn)和目標(biāo)節(jié)點(diǎn)都可以繼續(xù)處理命令請(qǐng)求。
如果節(jié)點(diǎn) A 正在遷移槽 i 至節(jié)點(diǎn) B,那么當(dāng)節(jié)點(diǎn) A 沒(méi)能在自己的數(shù)據(jù)庫(kù)中找到命令指定的數(shù)據(jù)庫(kù)鍵時(shí),節(jié)點(diǎn) A 會(huì)向客戶端返回一個(gè) ASK 錯(cuò)誤,指引客戶端到節(jié)點(diǎn) B 繼續(xù)查找指定的數(shù)據(jù)庫(kù)鍵。
MOVED 錯(cuò)誤表示槽的負(fù)責(zé)權(quán)已經(jīng)從一個(gè)節(jié)點(diǎn)轉(zhuǎn)移到了另外一個(gè)節(jié)點(diǎn),而 ASK 錯(cuò)誤只是兩個(gè)節(jié)點(diǎn)在遷移槽的過(guò)程中使用的一種臨時(shí)措施。
Redis 集群中的節(jié)點(diǎn)分為主節(jié)點(diǎn)(master)和從節(jié)點(diǎn)(slave),其中主節(jié)點(diǎn)用于處理槽,而從節(jié)點(diǎn)用于復(fù)制主節(jié)點(diǎn),并在主節(jié)點(diǎn)下線時(shí),代替主節(jié)點(diǎn)繼續(xù)處理命令請(qǐng)求。
集群中的節(jié)點(diǎn)通過(guò)發(fā)送和接收消息來(lái)進(jìn)行通信,常見(jiàn)的消息包括 MEET、PING、PONG、PUBLISH、FAIL 五種。
Redis Cluster 與 Redis Sentinel 區(qū)別
哨兵模式監(jiān)控權(quán)交給了哨兵系統(tǒng),集群模式中是工作節(jié)點(diǎn)自己做監(jiān)控。
哨兵模式發(fā)起選舉是選舉一個(gè) leader 哨兵節(jié)點(diǎn)來(lái)處理故障轉(zhuǎn)移,集群模式是在從節(jié)點(diǎn)中選舉一個(gè)新的主節(jié)點(diǎn),來(lái)處理故障的轉(zhuǎn)移。
Redis Cluster 搭建
Redis Cluster 部署技巧及其環(huán)境
Redis 集群至少需要 3 個(gè)節(jié)點(diǎn),因?yàn)橥镀比蒎e(cuò)機(jī)制要求超過(guò)半數(shù)節(jié)點(diǎn)認(rèn)為某個(gè)節(jié)點(diǎn)掛了該節(jié)點(diǎn)才是掛了,所以 2 個(gè)節(jié)點(diǎn)無(wú)法構(gòu)成集群。
要保證集群的高可用,需要每個(gè)節(jié)點(diǎn)都有從節(jié)點(diǎn),也就是備份節(jié)點(diǎn),即三主三從,所以 Redis 集群至少需要 6 臺(tái)服務(wù)器。
Redis 5.0 開(kāi)始不再使用 Ruby 搭建集群,而是直接使用客戶端命令 redis-cli 來(lái)創(chuàng)建。
不支持多數(shù)據(jù)庫(kù)空間,集群模式下只能使用 db0 空間。

由于資源有限,因此在一臺(tái)機(jī)器上模擬一個(gè) Redis Cluster。
| 角色 | IP 地址 | 端口號(hào) |
|---|---|---|
| Redis Cluster-Master-01-6391 | 127.0.0.1 | 6391 |
| Redis Cluster-Master-02-6393 | 127.0.0.1 | 6393 |
| Redis Cluster-Master-02-6395 | 127.0.0.1 | 6395 |
| Redis Cluster-Slave-01-6394 | 127.0.0.1 | 6394 |
| Redis Cluster-Slave-02-6396 | 127.0.0.1 | 6396 |
| Redis Cluster-Slave-03-6392 | 127.0.0.1 | 6392 |
Redis Cluster 安裝指南
1、下載 Redis 服務(wù)軟件包到服務(wù)器,解壓后并編譯安裝。
[root@VM_24_98_centos ~]# mkdir /usr/local/redis
[root@VM_24_98_centos ~]# wget http://download.redis.io/releases/redis-5.0.6.tar.gz
[root@VM_24_98_centos ~]# tar -zvxf redis-5.0.6.tar.gz -C /usr/local/redis
[root@VM_24_98_centos ~]# cd /usr/local/redis/redis-5.0.6/
[root@VM_24_98_centos redis-5.0.6]# make PREFIX=/usr/local/redis install
2、設(shè)置 Redis Cluster 服務(wù)器
a. 創(chuàng)建目錄以及復(fù)制配置文件
[root@VM_24_98_centos ~]# mkdir -p /usr/local/redis/redis-cluster/redis-6391
[root@VM_24_98_centos ~]# cp -r /usr/local/redis/redis-5.0.6/redis.conf /usr/local/redis/redis-cluster/redis-6391/
[root@VM_24_98_centos ~]# vim /usr/local/redis/redis-cluster/redis-6391/redis.conf
b. 設(shè)置 Redis Cluster 服務(wù)器配置環(huán)境
# 開(kāi)啟遠(yuǎn)程連接
bind 0.0.0.0
#
protected-mode no
# 端口號(hào)
port 6391
# 守護(hù)進(jìn)程
daemonize yes
# 進(jìn)程文件
pidfile /usr/local/redis/redis-cluster/redis-6391/redis.pid
# 日志文件
logfile /usr/local/redis/redis-cluster/redis-6391/redis.log
# 工作目錄
dir /usr/local/redis/redis-cluster/redis-6391/
# 主服務(wù)器密碼
masterauth foobared
# 認(rèn)證密碼
requirepass foobared
# 開(kāi)啟 AOF 持久化
appendonly yes
# 每秒調(diào)用一次 fsync
appendfsync everysec
# 開(kāi)啟集群
cluster-enabled yes
# 集群的配置文件,首次啟動(dòng)會(huì)自動(dòng)創(chuàng)建
cluster-config-file nodes.conf
# 集群節(jié)點(diǎn)連接超時(shí)時(shí)間,15秒
cluster-node-timeout 15000
c. 啟動(dòng) Redis Cluster 服務(wù)器
[root@VM_24_98_centos ~]# /usr/local/redis/bin/redis-server /usr/local/redis/redis-cluster/redis-6391/redis.conf
[root@VM_24_98_centos ~]# ps -ef |grep redis
d. 客戶端測(cè)試連接
[root@VM_24_98_centos ~]# /usr/local/redis/bin/redis-server /usr/local/redis/redis-cluster/redis-6391/redis.conf
[root@VM_24_98_centos ~]# /usr/local/redis/bin/redis-cli -h 127.0.0.1 -p 6391 -a foobared
127.0.0.1:6391> CLUSTER INFO
cluster_state:fail
cluster_slots_assigned:0
cluster_slots_ok:0
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:1
cluster_size:0
cluster_current_epoch:0
cluster_my_epoch:0
cluster_stats_messages_sent:0
cluster_stats_messages_received:0
e. 同理,集群服務(wù)器 redis-6392、redis-6393 、redis-6394、redis-6395、redis-6396 按照上面的步驟部署
3、Redis 5.0 開(kāi)始不再使用 ruby 搭建集群,而是直接使用客戶端命令 redis-cli 來(lái)創(chuàng)建。
a. 創(chuàng)建順序三主三從,前面三個(gè)是主后面三個(gè)是從。由于我們?cè)O(shè)置了redis集群的密碼,所以要帶上密碼。
[root@VM_24_98_centos ~]# /usr/local/redis/bin/redis-cli --cluster create 127.0.0.1:6391 127.0.0.1:6393 127.0.0.1:6395 127.0.0.1:6392 127.0.0.1:6394 127.0.0.1:6396 --cluster-replicas 1 -a foobared

b. 客戶端測(cè)試連接
[root@VM_24_98_centos ~]# /usr/local/redis/bin/redis-cli -h 127.0.0.1 -p 6391 -a foobared
127.0.0.1:6391> CLUSTER INFO
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:6
cluster_my_epoch:1
cluster_stats_messages_ping_sent:1153
cluster_stats_messages_pong_sent:1241
cluster_stats_messages_sent:2394
cluster_stats_messages_ping_received:1236
cluster_stats_messages_pong_received:1153
cluster_stats_messages_meet_received:5
cluster_stats_messages_received:2394
127.0.0.1:6391> CLUSTER NODES
cdfd726c3c35586770412cade1fe5c56d4285b0e 127.0.0.1:6394@16394 slave c54ebef126b30b5bd9cb157ccc0b6ddb952a1f50 0 1574234724000 5 connected
c8daea9291a5cfdf0b3e032bc3a80d7e3cbc75cc 127.0.0.1:6393@16393 master - 0 1574234725711 2 connected 5461-10922
43c325955c74f0ed79de6850dca8a509195acb13 127.0.0.1:6392@16392 slave 718f66ab8b3574597a97b90f8257773d0483c556 0 1574234724000 4 connected
3a32043079bf6af3723230ee3e6412e84dd66180 127.0.0.1:6396@16396 slave c8daea9291a5cfdf0b3e032bc3a80d7e3cbc75cc 0 1574234724708 6 connected
c54ebef126b30b5bd9cb157ccc0b6ddb952a1f50 127.0.0.1:6391@16391 myself,master - 0 1574234725000 1 connected 0-5460
718f66ab8b3574597a97b90f8257773d0483c556 127.0.0.1:6395@16395 master - 0 1574234723000 3 connected 10923-16383
Redis Cluster 場(chǎng)景測(cè)試
(1)模擬場(chǎng)景:Redis Cluster 中 某個(gè) Master 節(jié)點(diǎn)掛掉,查看 Redis Cluster 狀態(tài)。
Step1、關(guān)掉 Cluster-Master-6391 節(jié)點(diǎn)
[root@VM_24_98_centos ~]# /usr/local/redis/bin/redis-cli -h 127.0.0.1 -p 6391 -a foobared
127.0.0.1:6391> SHUTDOWN
Step2、查看集群狀態(tài)
[root@VM_24_98_centos ~]# /usr/local/redis/bin/redis-cli -h 127.0.0.1 -p 6393 -a foobared
127.0.0.1:6393> CLUSTER NODES
43c325955c74f0ed79de6850dca8a509195acb13 127.0.0.1:6392@16392 slave 718f66ab8b3574597a97b90f8257773d0483c556 0 1574236204772 4 connected
3a32043079bf6af3723230ee3e6412e84dd66180 127.0.0.1:6396@16396 slave c8daea9291a5cfdf0b3e032bc3a80d7e3cbc75cc 0 1574236206778 6 connected
cdfd726c3c35586770412cade1fe5c56d4285b0e 127.0.0.1:6394@16394 master - 0 1574236201000 7 connected 0-5460
718f66ab8b3574597a97b90f8257773d0483c556 127.0.0.1:6395@16395 master - 0 1574236206000 3 connected 10923-16383
c54ebef126b30b5bd9cb157ccc0b6ddb952a1f50 127.0.0.1:6391@16391 master,fail - 1574236049092 1574236047289 1 disconnected
c8daea9291a5cfdf0b3e032bc3a80d7e3cbc75cc 127.0.0.1:6393@16393 myself,master - 0 1574236204000 2 connected 5461-10922
通過(guò) CLUSTER NODES 信息可以看到,Cluster-Master-01-6391 主節(jié)點(diǎn)處于下線狀態(tài)(fail),其 Cluster-Master-01-6391 節(jié)點(diǎn)的從節(jié)點(diǎn) Cluster-Slave-01-6394 變?yōu)橹鞴?jié)點(diǎn);說(shuō)明主節(jié)點(diǎn)掛掉后,6394 Slave 節(jié)點(diǎn)自動(dòng)升級(jí)成為了 Master 節(jié)點(diǎn)。
Step3、啟動(dòng) 6391 Redis 服務(wù),然后查看節(jié)點(diǎn)角色,此時(shí) 6391 變成了 Slave,6394 為 Master 節(jié)點(diǎn)
[root@VM_24_98_centos ~]# /usr/local/redis/bin/redis-server /usr/local/redis/redis-cluster/redis-6391/redis.conf
[root@VM_24_98_centos ~]# /usr/local/redis/bin/redis-cli -h 127.0.0.1 -p 6391 -a foobared
127.0.0.1:6391> CLUSTER NODES
43c325955c74f0ed79de6850dca8a509195acb13 127.0.0.1:6392@16392 slave 718f66ab8b3574597a97b90f8257773d0483c556 0 1574238264397 4 connected
c54ebef126b30b5bd9cb157ccc0b6ddb952a1f50 127.0.0.1:6391@16391 myself,slave cdfd726c3c35586770412cade1fe5c56d4285b0e 0 1574238261000 1 connected
3a32043079bf6af3723230ee3e6412e84dd66180 127.0.0.1:6396@16396 slave c8daea9291a5cfdf0b3e032bc3a80d7e3cbc75cc 0 1574238265400 6 connected
c8daea9291a5cfdf0b3e032bc3a80d7e3cbc75cc 127.0.0.1:6393@16393 master - 0 1574238263000 2 connected 5461-10922
718f66ab8b3574597a97b90f8257773d0483c556 127.0.0.1:6395@16395 master - 0 1574238263000 3 connected 10923-16383
cdfd726c3c35586770412cade1fe5c56d4285b0e 127.0.0.1:6394@16394 master - 0 1574238264000 7 connected 0-5460
(2)模擬場(chǎng)景:為 Redis Cluster 添加一個(gè)新主(master)節(jié)點(diǎn)
Step1、按照上面的步驟新增一 Redis Cluster 服務(wù)器 Cluster-Master-04-6397
Step2、將 Cluster-Master-04-6397 節(jié)點(diǎn)加入 Redis Cluster 中(127.0.0.1:6391 為集群中任意可用的節(jié)點(diǎn))
[root@VM_24_98_centos ~]# /usr/local/redis/bin/redis-cli --cluster add-node 127.0.0.1:6397 127.0.0.1:6391 -a foobared

Step3、為節(jié)點(diǎn) Cluster-Master-04-6397 分配 slots(127.0.0.1:6391 為集群中任意可用的節(jié)點(diǎn))
[root@VM_24_98_centos redis-cluster]# /usr/local/redis/bin/redis-cli --cluster reshard 127.0.0.1:6391 -a foobared

(3)模擬場(chǎng)景:為 Redis Cluster 某個(gè) Master 節(jié)點(diǎn)添加 一個(gè)新從(slave)節(jié)點(diǎn)
Step1、按照上面的步驟新增一 Redis Cluster 服務(wù)器 Cluster-Slave-04-6398
Step2、將 Cluster-Slave-04-6398 節(jié)點(diǎn)加入 Redis Cluster 中(127.0.0.1:6391 為集群中任意可用的節(jié)點(diǎn))
// 這種方法隨機(jī)為 6398 指定一個(gè) master
[root@VM_24_98_centos ~]# /usr/local/redis/bin/redis-cli --cluster add-node 127.0.0.1:6398 127.0.0.1:6391 --cluster-slave -a foobared
// 這種方式將為 6398 指定某個(gè) master-id
[root@VM_24_98_centos ~]# /usr/local/redis/bin/redis-cli --cluster add-node 127.0.0.1:6398 127.0.0.1:6391 --cluster-slave --cluster-master-id 5cf471cf39f0104f69d06c80d0dfdcc8aaa96b7c -a foobared
Step3、查看集群狀態(tài)
[root@VM_24_98_centos ~]# /usr/local/redis/bin/redis-cli -h 127.0.0.1 -p 6391 -a foobared
127.0.0.1:6391> CLUSTER NODES
5cf471cf39f0104f69d06c80d0dfdcc8aaa96b7c 127.0.0.1:6397@16397 master - 0 1574243297701 7 connected 0-1364 5461-6826 10923-12287
207628f6fb8b3bb9a22db757507350fb880d4990 127.0.0.1:6396@16396 slave 94af5d349465be57400b6a4a1d770d56ad3d94ce 0 1574243294000 6 connected
94af5d349465be57400b6a4a1d770d56ad3d94ce 127.0.0.1:6393@16393 master - 0 1574243296700 2 connected 6827-10922
2e0134b0a87a73903d4774b6b37dd43e78e93733 127.0.0.1:6391@16391 myself,master - 0 1574243292000 1 connected 1365-5460
21a288afc7b6addebcd943ca606dd34f6b9c99db 127.0.0.1:6398@16398 slave 5cf471cf39f0104f69d06c80d0dfdcc8aaa96b7c 0 1574243295697 7 connected
63bc9da88066b475bd878a56a11dd18023b211b6 127.0.0.1:6394@16394 slave 2e0134b0a87a73903d4774b6b37dd43e78e93733 0 1574243295000 5 connected
c3d20b7f2df806ec87f3d45a7e334b5a2d3abe5b 127.0.0.1:6395@16395 master - 0 1574243296000 3 connected 12288-16383
f6a7c788d9e5d40bc62a3723ba02c25607cc2825 127.0.0.1:6392@16392 slave c3d20b7f2df806ec87f3d45a7e334b5a2d3abe5b 0 1574243293694 4 connected
參考博文
[1]. 一文搞懂 Raft 算法
[2]. Redis 哨兵模式實(shí)現(xiàn)主從故障互切換
[3]. Redis cluster tutorial
[4]. redis cluster 的Gossip協(xié)議介紹
注腳
[1]. 領(lǐng)頭 Sentinel:Sentinel 系統(tǒng)選舉領(lǐng)頭 Sentinel 的方式是對(duì) Raft 算法的領(lǐng)頭選舉方法的實(shí)現(xiàn),Raft 算法是一個(gè)共識(shí)算法,是工程上使用較為廣泛的強(qiáng)一致性、去中心化、高可用的分布式協(xié)議。
[2]. Gossip 協(xié)議:Gossip protocol 也叫 Epidemic Protocol(流行病協(xié)議),實(shí)際上它還有很多別名,比如:“流言算法”、“疫情傳播算法” 等。Gossip 過(guò)程是由種子節(jié)點(diǎn)發(fā)起,當(dāng)一個(gè)種子節(jié)點(diǎn)有狀態(tài)需要更新到網(wǎng)絡(luò)中的其他節(jié)點(diǎn)時(shí),它會(huì)隨機(jī)的選擇周圍幾個(gè)節(jié)點(diǎn)散播消息,收到消息的節(jié)點(diǎn)也會(huì)重復(fù)該過(guò)程,直至最終網(wǎng)絡(luò)中所有的節(jié)點(diǎn)都收到了消息。這個(gè)過(guò)程可能需要一定的時(shí)間,由于不能保證某個(gè)時(shí)刻所有節(jié)點(diǎn)都收到消息,但是理論上最終所有節(jié)點(diǎn)都會(huì)收到消息,因此它是一個(gè)“最終一致性協(xié)議”
source:https://morning-pro.github.io/archives/d63e1e23.html
喜歡,在看
