小碼今天去面試。
面試官:給我介紹一下Redis
叢集,
小碼:啊,平時開發用的都是單機Redis
,沒怎麼用過叢集了。
面試官:好的,出門右轉不謝。
小碼內心困惑:在小公司業務量也不大,單機的 Redis
完全夠用,也不會發生當機問題啊。面試要問到 Redis 叢集該怎麼辦呢?
Redis 為何要有叢集
很多小夥伴也有類似的困惑,自己的公司並不大。併發量、訪問量要求不高,使用單機 Redis 就能很好的解決資料請求的問題。為啥要使用叢集呢?
對於訪問量小、併發低的系統,對資料的高可用要求不高的資料,單機部署都能滿足需求。但是在大公司,隨便一個系統的QPS
都是成千上萬,對系統的高可用、高併發要求比較高,這個時候就需要要使用Redis
叢集模式了,Redis
有三種叢集模式:
- 主從複製模式
- 哨兵模式
- Cluster 模式
主從複製模式
Redis
想要不丟失資料,就需要開始持久化,資料會寫入到磁碟中,這樣即使服務關閉再重啟伺服器後,資料也能從硬碟載入到記憶體中。但是如果伺服器的硬碟出現故障,也會導致資料丟失。
為了避免硬碟故障問題,需要將資料複製的多個副本上,這樣即使一個服務出現故障,其他伺服器也能提供資料服務。
Redis
提供了主從模式,一個主資料庫master
繫結多個從資料庫slave
:
主資料可以讀和寫,從資料庫一般是隻讀,主從庫之間採用讀寫分離,主資料庫資料更新後同步複製給繫結的從資料庫,主從資料庫的資料保持一致:
資料主從同步原理
- 從資料庫啟動後,連線主資料庫,傳送
SYNC
命令。 - 主資料庫接收到SYNC命令後,開始執行
BGSAVE
命令生成RDB
檔案並使用緩衝區記錄後面執行的所有寫命令。 - 主資料庫執行完
BGSAVE
命令之後,向所有從資料庫傳送RDB
檔案。從資料庫載入RDB
檔案。 - 主資料將記錄的快取區所有的寫命令傳送給從資料庫,從資料庫執行命令。
SYNC
每次從服務重啟,都會請求所以的資料。如果服務當機再重啟還是同步所有的資料,就會造成資源的浪費,所以有了PSYNC
命令,PSYNC
有完整同步和部分同步,其中完整同步和SYNC
一致,而部分同步是根據資料偏移量複製資料。
主從複製服務搭建
Redis
單機搭建可以檢視前面寫的的教程
首先建立三個資料夾6380、6381、6382
:
mkdir 6380
mkdir 6381
mkdir 6382
複製redis.conf
到這三個資料夾裡:
cp redis.conf 6380/
cp redis.conf 6381/
cp redis.conf 6382/
配置一主兩從,6380
為主,6381、6382
為從。然後修改redis.conf
檔案:
引數 | maser (6380) | slave1 (6381) | slave2 (6382) |
---|---|---|---|
port | 6380 | 6381 | 6382 |
requirepass | requirepass "xxxx" | requirepass "xxxx" | requirepass "xxxx" |
slaveof | slaveof 本機ip 6380 | slaveof 本機ip 6380 | |
masterauth | masterauth ”xxx“ | masterauth ”xxx“ | |
pidfile | pidfile /redis_6380.pid | pidfile /redis_6381.pid | pidfile /redis_6382.pid |
logfile | logfile "redis_6380.log" | logfile "redis_6381.log" | logfile "redis_6382.log" |
設定了requirepass
,就需要設定masterauth
,三臺伺服器的密碼需要一致。
啟動伺服器:
[root@instance-3 redis]# bin/redis-server 6380/redis.conf
[root@instance-3 redis]# bin/redis-server 6381/redis.conf
[root@instance-3 redis]# bin/redis-server 6382/redis.conf
然後檢視程式,如果有以下的顯示,說明啟動成功了:
[root@instance-3 redis]# ps -ef |grep redis
root 6652 1 0 16:28 ? 00:00:00 bin/redis-server *:6380
root 6665 1 0 16:28 ? 00:00:00 bin/redis-server *:6381
root 6682 1 0 16:28 ? 00:00:00 bin/redis-server *:6382
root 7188 4291 0 16:30 pts/0 00:00:00 grep --color=auto redis
進入Redis
客戶端,使用info replication
命令檢視資料庫的資訊。
master 6380:
[root@instance-3 redis]# bin/redis-cli -p 6380
127.0.0.1:6380> auth xxxx
OK
127.0.0.1:6380> info replication
role:master
connected_slaves:2
slave0:ip=127.0.0.1,port=6381,state=online,offset=42,lag=0
slave1:ip=127.0.0.1,port=6382,state=online,offset=42,lag=1
master_replid:19ca382e3c05014988002a295078687dae9bb92e
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:42
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:42
role:master
表示 6380 是主伺服器,slave0
和salve1
表示繫結的從伺服器。
slave 6381:
role:slave
master_host:127.0.0.1
master_port:6380
master_link_status:up
master_last_io_seconds_ago:4
master_sync_in_progress:0
slave_repl_offset:126
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:19ca382e3c05014988002a295078687dae9bb92e
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:126
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:126
role:slave
表示 6381 是從伺服器,master_host
和master_port
表示繫結對應的主伺服器。
slave 6382:
role:slave
master_host:127.0.0.1
master_port:6380
master_link_status:up
master_last_io_seconds_ago:1
master_sync_in_progress:0
slave_repl_offset:476
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:19ca382e3c05014988002a295078687dae9bb92e
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:476
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:476
role:slave
表示 6382 是從伺服器,master_host
和master_port
表示繫結對應的主伺服器。
主伺服器新增資料,再從從伺服器獲取資料。
6380
伺服器新增資料:
127.0.0.1:6380> set name jeremy
OK
6381
伺服器獲取資料:
127.0.0.1:6381> get name
"jeremy"
經過以上測試,說明主伺服器的資料,從伺服器也能同步獲取。主從服務都搭建成功。
主從模式的優缺點
-
優點
- 主從模式搭建多個伺服器,即使單個服務當機,還能繼續服務。
- 讀資料壓力分解到多個伺服器下,大大緩解伺服器的壓力。
-
缺點
- 主資料庫當機了,當機後的資料無法同步到從從資料庫,導致資料庫不一致。
- 主資料庫當機了,無法自動生成新的主機,新的讀請求也無法處理。
- 每個伺服器都儲存相同的資訊,比較浪費記憶體。
- 因為這些問題,
Spring Boot
也不支援整合Redis
主從模式。
主從模式最大的問題就是無法處理主資料庫當機問題,也就無法保證
Redis
的高可用性。這就需要有一個自動的機制處理主資料庫當機問題,這就延伸出下面的模式 —— 哨兵模式。
哨兵模式
當主資料庫掛了之後,需要手動設定新的主資料庫,其他從資料庫都需要重新設定新的主資料。手動切換的成本比較大,還會導致一段時間的服務不可用。這就需要講上面的手動設定改成自動設定,也就是使用哨兵來配置。
哨兵Redis
的高可用解決方案,哨兵監控Redis
主伺服器和繫結的從伺服器,如果主伺服器當機了,自動將某個從伺服器升級為新的伺服器,然後傳送通知給其他從伺服器。
哨兵基本原理
哨兵是一個獨立的程式,和Redis一樣,它也執行一個例項。主要有三個任務:
- 監控: 週期給所有的主從資料庫傳送
PING
命令,檢查主從資料庫執行是否正常,在設定down-after-milliseconds
毫秒,沒有服務響應,就會標記主觀下線,當其他哨兵也判斷主觀下線,判斷主觀下線的數量達到設定的值後,哨兵之間會進行投票,投票同意後,進行資料庫升級。 - 自動切換主從資料庫: 當上面的投票同意後,會根據一定的規則選取一個從伺服器升級成主伺服器。更新
redis.conf
配置檔案。 - 通知:完成主伺服器升級之後,哨兵透過釋出訂閱會把新主資料庫的連線資訊傳送給其他從資料庫,修改對應配置檔案的
replicaof
命令,和新資料庫建立連線,並進行資料複製。
哨兵服務搭建
在上面的主從模式的基礎上新增哨兵,首先從解壓資料夾複製sentinel.conf
到usr/local/redis
資料夾中:
cp sentinel.conf /usr/local/redis/
修改sentinel.conf
檔案,需要修改的部分:
daemonize no
改成daemonize yes
logfile ""
改成logfile "redis_26379.log"
- 新增
sentinel monitor <master-name> <ip> <redis-port> <quorum>
,設定成sentinel monitor mymaster 127.0.0.1 6382 1
ip
主資料庫IPredis-port
主資料庫埠quorum
主從切換需要達到主動下線個數
- 如果資料庫有密碼,新增
sentinel auth-pass mymaster 123456
,表示驗證密碼mymaster
哨兵的名稱,需要唯一123456
資料庫密碼,所有主從資料庫密碼需要設定成一致。
啟動伺服器:
[root@instance-3 redis]# bin/redis-sentinel sentinel.conf
檢視logfile
啟動日誌:
看最後標記的三行,表明哨兵分別監控了主資料庫
6380
、兩個從資料庫6381
、6382
。有上面的日誌輸出表明哨兵已經成功啟動。
模擬主從切換
使用SHUTDOWN
命令關閉6380
主資料庫服務:
[root@instance-3 redis]# bin/redis-cli -p 6380
127.0.0.1:6380> shutdown
(error) NOAUTH Authentication required.
127.0.0.1:6380> a
[root@instance-3 redis]# bin/redis-cli -p 6380
127.0.0.1:6380> auth xxx
OK
127.0.0.1:6380> SHUTDOWN
透過ps -ef |grep redis
檢視6380
已經關閉:
[root@instance-3 redis]# ps -ef |grep redis
root 8822 1 0 Nov21 ? 00:00:58 /usr/local/redis/bin/redis-server *:6379
root 24707 1 0 10:35 ? 00:00:02 bin/redis-server *:6381
root 27500 1 0 10:47 ? 00:00:01 bin/redis-server *:6382
root 29247 1 0 10:54 ? 00:00:03 bin/redis-sentinel *:26379 [sentinel]
root 34131 17210 0 11:16 pts/1 00:00:00 grep --color=auto redis
檢視哨兵日誌logfile
:
表明主伺服器從
6380
成功切換到了6382
,sentinel.conf
配置檔案也修改了主從資料庫配置。如果沒有切換成功,日誌報錯-failover-abort-no-good-slave
,可能是沒有設定驗證密碼sentinel auth-pass
。
哨兵模式的優缺點
- 優點
- 哨兵模式是基於主從模式,主從模式的優點,哨兵模式都有。
- 哨兵模式使用獨立程式監控服務,自動切換當機資料庫,保障服務的高可用。
- 缺點
- 受限於單個伺服器,很難實現單節點線上擴容。
- 每個伺服器都儲存相同的資訊,比較浪費記憶體。
Cluster(官方推薦)叢集
主從模式和哨兵模式資料庫都儲存了相同的資料,比較浪費記憶體。而且當資料量增加時,在單個資料庫上很難實現線上擴容。Redis Cluster將資料分佈儲存在不同的節點上,每個節點儲存不同的資料。新增節點就能解決擴容問題。
Redis Cluster
翻譯就是Redis
叢集,Redis
叢集提供分散式解決方案,透過分片將資料拆分到不同的節點上,並提供複製和故障轉移功能。使用了水平擴充套件的方法,將資料分發到不同的資料庫中。
每個虛線圓都表示一個節點,每個節點都有一個主資料庫和多個從資料庫。任意兩個節點都是相同的(三個節點畫圖容易誤以為是一個環,四個節點容易理解),節點之間都共享資料。
分片叢集原理
Redis
分片叢集,使用了一種類似於一致性雜湊的分片技術——雜湊槽,每個鍵都有一個雜湊槽的值,Redis 叢集有16384
個雜湊嘈,對鍵的CRC16
取模16384
計算出雜湊槽,以此決定放置的雜湊嘈的位置。
Redis
叢集中每個節點都負責一部分雜湊嘈,比如,叢集有三個節點,其中:
- 節點 A 包含 0 到 5460 號雜湊槽
- 節點 B 包含 5461 到 10922 號雜湊槽
- 節點 C 包含 10923 到 16383 號雜湊槽
資料根據雜湊嘈分配到不同的資料庫中,實現資料的分片。這裡新增或者減少一個節點就比較容易了。比如,我想新增一個新的節點D
,需要將節點A、B、C
一部分資料移動到節點D
中。而刪除一個節點A
,就將原來A節點
的資料分發到其它節點上。
Redis叢集主從模式
為了保證高可用,Redis Cluster
也使用了主從模式。節點(上圖虛線圓)當機了,就無法提供繼續資料服務了。當節點引入主從模式後,主服務當機之後,從伺服器升級成主服務。但是如果一個節點的所有主從服務服務都當機了,該節點就無法提供資料服務了。
叢集模式搭建
最小叢集必須最少包含三個節點,這裡部署使用三個主節點,三個從節點。一共有六個配置檔案,埠分別是7001、7002、7003、7004、7005、7006
。
複製redis.conf
配置檔案命名redis_7001.conf
,修改以下欄位:
# 埠
port 7001
# 啟用叢集模式
cluster-enabled yes
# 儲存其他節點的名稱、狀態等資訊,命名和埠保持一致
cluster-config-file nodes_7001.conf
logfile "redis_7001.log"
daemonize yes
protected-mode no
其他五個檔案分別複製redis_7001.conf
檔案,檔名分別是:
redis_7002.conf
redis_7003.conf
redis_7004.conf
redis_7005.conf
redis_7006.conf
根據檔名修改修改port
、cluster-config-file
、logfile
三個屬性,比如redis_7002.conf
的配置修改以下欄位:
port 7001
cluster-config-file nodes_7002.conf
logfile "redis_7002.log"
其他配置檔案也修改成對應檔名的欄位。
啟動redis節點:
bin/redis-server redis_7001.conf &
bin/redis-server redis_7002.conf &
bin/redis-server redis_7003.conf &
bin/redis-server redis_7004.conf &
bin/redis-server redis_7005.conf &
bin/redis-server redis_7006.conf
然後檢視redis程式:
[root@localhost redis]# ps -ef|grep redis
root 24783 1 0 Nov15 ? 00:07:53 bin/redis-server 0.0.0.0:7001 [cluster]
root 24792 1 0 Nov15 ? 00:07:50 bin/redis-server 0.0.0.0:7002 [cluster]
root 24805 1 0 Nov15 ? 00:07:53 bin/redis-server 0.0.0.0:7003 [cluster]
root 24816 1 0 Nov15 ? 00:07:49 bin/redis-server 0.0.0.0:7004 [cluster]
root 24821 1 0 Nov15 ? 00:07:53 bin/redis-server 0.0.0.0:7005 [cluster]
root 24830 1 0 Nov15 ? 00:07:50 bin/redis-server 0.0.0.0:7006 [cluster]
--cluster-replicas 1
參數列示建立一個主節點同時也建立一個從節點。
建立redis叢集:
redis-cli --cluster 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 127.0.0.1:7006 --cluster-replicas 1
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 127.0.0.1:7004 to 127.0.0.1:7001
Adding replica 127.0.0.1:7005 to 127.0.0.1:7002
Adding replica 127.0.0.1:7006 to 127.0.0.1:7003
>>> Trying to optimize slaves allocation for anti-affinity
[WARNING] Some slaves are in the same host as their master
M: 9f8616c497aeb89e065c9ed7e260a13a499078eb 127.0.0.1:7001
slots:[0-5460] (5461 slots) master
M: 1064be46f6001390b47308fcb90832cb5eff3256 127.0.0.1:7002
slots:[5461-10922] (5462 slots) master
M: c862b3f74904891972debe055edee66d08563f6c 127.0.0.1:7003
slots:[10923-16383] (5461 slots) master
S: 51fa3d61cd6075d8a179ec5402c3d6771592d524 127.0.0.1:7004
replicates c862b3f74904891972debe055edee66d08563f6c
S: f2a18a3fd5f7097888f31cbbc3878f26699ecd09 127.0.0.1:7005
replicates 9f8616c497aeb89e065c9ed7e260a13a499078eb
S: 004d9acf71c448d93c8b3211f1fd132dd47cd5e9 127.0.0.1:7006
replicates 1064be46f6001390b47308fcb90832cb5eff3256
Can I set the above configuration? (type 'yes' to accept):
可以看到啟動六個節點,三個主節點
Master
,三個從節點Slave
,以及他們之間的主從關係。六個節點,每個節點都生成一個唯一的編碼。
輸入yes
最後有以下輸出,表示叢集搭建成功:
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
測試叢集
登入客戶端需要帶上引數-c
表示叢集環境,否則只能獲取單個節點的資料。
先在7001
新增資料
bin/redis-cli -p 7001
redis 127.0.0.1:7001> set name jeremy
OK
然後在7002
獲取資料:
bin/redis-cli -p 7002
redis 127.0.0.1:7002> get name
-> Redirected to slot [5798] located at 127.0.0.1:7001
OK
127.0.0.1:7001> get name
"jeremy"
在
7002
獲取資料,redis叢集會根據key計算雜湊槽的位置,算出資料在7001
節點,重定向到7001
節點獲取資料。
- 新增新節點
新增一個新節點,一般是新增一個空節點,將其他節點資料移動該節點資料庫中。實現資料庫的擴容。
bin/redis-cli --cluster add-node 127.0.0.1:7006 127.0.0.1:7001
將新節點地址為第一個引數,叢集中隨機一個節點地址為第二個引數。上面的命令的表示將新節點127.0.0.1:7006
新增到127.0.0.1:7001
所在的叢集中。
- 刪除節點
bin/redis-cli --cluster del-node 127.0.0.1:7001
叢集模式的優缺點
- 優點
- 具有高可用,哨兵模式的優點,他都有
- 資料分片,不重複儲存資料,佔記憶體小
- 容易實現擴容和縮容
總結
- 主從模式:
- 單機當機或者磁碟出現故障,會導致資料丟失,主從模式將資料複製給多個從伺服器上,即使一臺資料庫當機了,其他資料也能正常提供資料。
- 主從模式有一臺主資料庫,多臺從資料庫的模式。客戶端對主資料庫進行讀寫,從資料庫只能讀操作。
- 啟動主從資料庫之後,從資料庫傳送
SYNC
同步命令給主資料庫,主資料庫接收到命令之後,生成RDB
檔案。並且使用緩衝區記錄所有寫命令。寫完畢後傳送RDB
檔案給每個從資料庫解析,以及傳送快取寫命名給所以從資料庫執行。 - 主資料庫更新資料後,資料會同步更新到從資料庫中。
- 主從模式實現了簡單的可用,但是如果主資料庫當機了,手動切換主資料庫比較費力,就有了哨兵模式。
- 哨兵模式:
- 根據主從模式無法自動切換問題,就有了哨兵模式。
- 哨兵是一個獨立的程式,它主要有三個功能:監控資料庫,發現主資料庫當機了,首先標記主觀下線,當主觀下線數量達到設定的數量時,就會進行投票,透過之後就執行切換主資料庫,將一個從資料庫升級成主資料庫。並通知給其他資料庫修改主資料庫配置。
- 哨兵模式實現自動切換主資料庫,實現了服務的高可用。
- 哨兵模式和主從模式一樣,所有資料庫都存放相同的資料,比較浪費記憶體,而且受限於單機資料庫,很難實現線上擴容。
Cluster
模式Redis
叢集有16384
個雜湊嘈,對鍵的CRC16
取模16384
計算出雜湊槽。- 叢集使用分片,使用節點方式,將雜湊槽分佈在每個節點上。也就講資料分佈儲存上不同的節點上。
- 為了保證服務的高可用,每個節點都可以搭建主從。
- 資料庫擴容需要新增節點,從新計算雜湊嘈,將其他資料庫的資料,轉移到新節點上。也可以刪除節點實現資料庫的縮容,刪除節點後,該節點的資料也會根據雜湊嘈分配到其他節點上。
參考
感覺不錯的話,點個贊吧!