redis怎么才能做到高可用
對於redis主從架構,slave可以對應多個本身可以保障高可用,但是對於一個master節點,如果宕機,整個緩存系統就無法進行寫的操作,顯然整個系統會無法做到高可用
sentinel哨兵可以監測master節點是否正常運行(會自動識別出所有的slave信息),如果出現宕機,則會在對應的slave節點中通過投票的方式來選取一個slave節點作為新的master節點,
舊的master節點恢復之后會被接管成為新的master節點的slave節點。同時sentinel哨兵節點本身也是集群的方式部署來保障自身的高可用,並且一個sentinel是可以同時監聽多個master節點
對於sentinel哨兵節點的一些核心概念:
1、sdown和odown轉換機制
sdown和odown兩種失敗狀態
sdown是主觀宕機,就一個哨兵如果自己覺得一個master宕機了,那么就是主觀宕機
odown是客觀宕機,如果quorum數量的哨兵都覺得一個master宕機了,那么就是客觀宕機
sdown達成的條件很簡單,如果一個哨兵ping一個master,超過了is-master-down-after-milliseconds指定的毫秒數之后,就主觀認為master宕機
sdown到odown轉換的條件很簡單,如果一個哨兵在指定時間內,收到了quorum指定數量的其他哨兵也認為那個master是sdown了,那么就認為是odown了,客觀認為master宕機
2、哨兵集群的自動發現機制
哨兵互相之間的發現,是通過redis的pub/sub系統實現的,每個哨兵都會往__sentinel__:hello這個channel里發送一個消息,這時候所有其他哨兵都可以消費到這個消息,並感知到其他的哨兵的存在
每隔兩秒鍾,每個哨兵都會往自己監控的某個master+slaves對應的__sentinel__:hello channel里發送一個消息,內容是自己的host、ip和runid還有對這個master的監控配置
每個哨兵也會去監聽自己監控的每個master+slaves對應的__sentinel__:hello channel,然后去感知到同樣在監聽這個master+slaves的其他哨兵的存在
每個哨兵還會跟其他哨兵交換對master的監控配置,互相進行監控配置的同步
3、slave配置的自動糾正
哨兵會負責自動糾正slave的一些配置,比如slave如果要成為潛在的master候選人,哨兵會確保slave在復制現有master的數據; 如果slave連接到了一個錯誤的master上,比如故障轉移之后,那么哨兵會確保它們連接到正確的master上
4、slave->master選舉算法
如果一個master被認為odown了,而且majority哨兵都允許了主備切換,那么某個哨兵就會執行主備切換操作,此時首先要選舉一個slave來
會考慮slave的一些信息
(1)跟master斷開連接的時長
(2)slave優先級
(3)復制offset
(4)run id
如果一個slave跟master斷開連接已經超過了down-after-milliseconds的10倍,外加master宕機的時長,那么slave就被認為不適合選舉為master
(down-after-milliseconds * 10) + milliseconds_since_master_is_in_SDOWN_state
接下來會對slave進行排序
(1)按照slave優先級進行排序,slave priority越低,優先級就越高
(2)如果slave priority相同,那么看replica offset,哪個slave復制了越多的數據,offset越靠后,優先級就越高
(3)如果上面兩個條件都相同,那么選擇一個run id比較小的那個slave
5、quorum和majority
每次一個哨兵要做主備切換,首先需要quorum數量的哨兵認為odown,然后選舉出一個哨兵來做切換,這個哨兵還得得到majority哨兵的授權,才能正式執行切換
如果quorum < majority,比如5個哨兵,majority就是3,quorum設置為2,那么就3個哨兵授權就可以執行切換
但是如果quorum >= majority,那么必須quorum數量的哨兵都授權,比如5個哨兵,quorum是5,那么必須5個哨兵都同意授權,才能執行切換
6、configuration epoch
哨兵會對一套redis master+slave進行監控,有相應的監控的配置
執行切換的那個哨兵,會從要切換到的新master(salve->master)那里得到一個configuration epoch,這就是一個version號,每次切換的version號都必須是唯一的
如果第一個選舉出的哨兵切換失敗了,那么其他哨兵,會等待failover-timeout時間,然后接替繼續執行切換,此時會重新獲取一個新的configuration epoch,作為新的version號
7、configuraiton傳播
哨兵完成切換之后,會在自己本地更新生成最新的master配置,然后同步給其他的哨兵,就是通過之前說的pub/sub消息機制
這里之前的version號就很重要了,因為各種消息都是通過一個channel去發布和監聽的,所以一個哨兵完成一次新的切換之后,新的master配置是跟着新的version號的
其他的哨兵都是根據版本號的大小來更新自己的master配置的
1redis安裝
解壓完成后可以看到INSTALL和README.md文件,查看以獲取更多有用信息。
在README文件中可以獲取到軟件的安裝步驟。以下安裝步驟基於此。
#step1 進入文件夾,執行編譯命令
[root@ redis-3.2.8]# make
#step2 為了后面開發測試的方便,把啟動腳本,配置文件,日志文件統一放到redis目錄下
[root@ redis-3.2.8]# mkdir /usr/local/redis [root@ redis-3.2.8]# mkdir /usr/local/redis/logs [root@ redis-3.2.8]# mkdir /usr/local/redis/bin [root@ redis-3.2.8]# mkdir /usr/local/redis/conf
[root@ redis-3.2.8]# mkdir /etc/sentinel
[root@ redis-3.2.8]# mkdir -p /var/sentinel/26377
[root@ redis-3.2.8]# mkdir -p /var/sentinel/26378
[root@ redis-3.2.8]# mkdir -p /var/sentinel/26379 [root@ redis-3.2.8]# cp redis.conf sentinel.conf /usr/local/redis/conf/ [root@ src]# cp redis-server redis-sentinel redis-cli /usr/local/redis/bin/
#step3 開啟Redis服務,檢測其可用性
[root@ bin]# redis-server ../conf/redis.conf
可以看到日志信息
其中有3個警告
第一個警告:The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
意思是:TCP backlog設置值,511沒有成功,因為 /proc/sys/net/core/somaxconn這個設置的是更小的128.
第二個警告:overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to/etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
意思是:overcommit_memory參數設置為0!在內存不足的情況下,后台程序save可能失敗。建議在文件 /etc/sysctl.conf 中將overcommit_memory修改為1。
第三個警告:you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix thisissue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain thesetting after a reboot. Redis must be restarted after THP is disabled.
意思是:你使用的是透明大頁,可能導致redis延遲和內存使用問題。執行 echo never > /sys/kernel/mm/transparent_hugepage/enabled 修復該問題。
臨時解決方法:
echo 511 > /proc/sys/net/core/somaxconn
echo "vm.overcommit_memory=1" > /etc/sysctl.conf
echo never > /sys/kernel/mm/transparent_hugepage/enabled。
永久解決方法:
vim /etc/sysctl.conf
net.core.somaxconn = 512
vm.overcommit_memory = 1
sysctl -p #-p 從指定的文件加載系統參數,如不指定即從/etc/sysctl.conf中加載
[root@centos224]# vi /etc/rc.local
if test -f /sys/kernel/mm/transparent_hugepage/enabled; then
echo never > /sys/kernel/mm/transparent_hugepage/enabled
fi
if test -f /sys/kernel/mm/transparent_hugepage/defrag; then
echo never > /sys/kernel/mm/transparent_hugepage/defrag
fi
Redis server使用默認端口6379啟動成功。
#step4 修改配置文件,使其以后台服務方式運行。
#what?局域網內本機IP。 #我是部署到同一機器上所以IP都一樣,端口不同 bind 127.0.0.1 #修改默認端口,避免被惡意腳本掃描。 port 9999 loglevel debug logfile /usr/local/redis/logs/redis.log.9999 #為服務設置安全密碼 requirepass redispass
#以守護進程方式運行 daemonize yes
#step5 重新啟動redis。
[root@ bin]# redis-cli -p 9999 -a redispass shutdown 我使用腳本啟動方式 啟動腳本 redis_init_script 位於位於Redis的 /utils/ 目錄下,redis_init_script腳本代碼如下:
#!/bin/sh # # Simple Redis init.d script conceived to work on Linux systems # as it does use of the /proc filesystem. #redis服務器監聽的端口 REDISPORT=9999 #服務端所處位置 EXEC=/usr/local/bin/redis-server #客戶端位置 CLIEXEC=/usr/local/bin/redis-cli #redis的PID文件位置,需要修改 PIDFILE=/var/run/redis_${REDISPORT}.pid #redis的配置文件位置,需將${REDISPORT}修改為文件名 CONF="/etc/redis/${REDISPORT}.conf" case "$1" in start) if [ -f $PIDFILE ] then echo "$PIDFILE exists, process is already running or crashed" else echo "Starting Redis server..." $EXEC $CONF fi ;; stop) if [ ! -f $PIDFILE ] then echo "$PIDFILE does not exist, process is not running" else PID=$(cat $PIDFILE) echo "Stopping ..." $CLIEXEC -p $REDISPORT shutdown while [ -x /proc/${PID} ] do echo "Waiting for Redis to shutdown ..." sleep 1 done echo "Redis stopped" fi ;; *) echo "Please use start or stop as first argument" ;; esac
可以根據你自己端口進行修改
mkdir /etc/redis cp redis.conf /etc/redis/9999.conf 將啟動腳本復制到/etc/init.d目錄下,本例將啟動腳本命名為redisd(通常都以d結尾表示是后台自啟動服務)。 cp redis_init_script /etc/init.d/redis_9999
./redis_9999 start
2開啟主從復制(master-slave)
主從模式的兩個重要目的,提升系統可靠性和讀寫分離提升性能。
這里通過修改端口的方式,再啟動端口為9997和9998的服務作為備(從)機。
備機啟動需要修改配置文件部分屬性(在9999配置的基礎上)。
port 9997 logfile /usr/local/redis/logs/redis.log.9997 #指定master ip port slaveof 127.0.0.1 9999 #認證master時需要的密碼。必須和master配置的requirepass 保持一致 masterauth redispass
requirepass redispass protected-mode no
從機9998配置同理
port 9998 logfile /usr/local/redis/logs/redis.log.9998 slaveof 127.0.0.1 9999 masterauth redispass
requirepass redispass protected-mode no
開啟從機服務
[root@ bin]# ./redis_9997 start [root@ bin]# ./redis_9998 start
查看slave 9998日志(省略部分信息),可以看出,slave在啟動時成功連接master,並接收到了104字節的同步數據。
6472:S 30 Mar 11:18:17.206 * Connecting to MASTER 127.0.0.1:9999 6472:S 30 Mar 11:18:17.206 * MASTER <-> SLAVE sync started 6472:S 30 Mar 11:18:17.223 * MASTER <-> SLAVE sync: receiving 104 bytes from master 6472:S 30 Mar 11:18:17.223 * MASTER <-> SLAVE sync: Finished with success
redis做一個基准的壓測
你如果要對自己剛剛搭建好的redis做一個基准的壓測,測一下你的redis的性能和QPS(query per second)
redis自己提供的redis-benchmark壓測工具,是最快捷最方便的,當然啦,這個工具比較簡單,用一些簡單的操作和場景去壓測
1、對redis讀寫分離架構進行壓測,單實例寫QPS+單實例讀QPS
redis-3.2.8/src ./redis-benchmark -h 127.0.0.1 -c <clients> Number of parallel connections (default 50) -n <requests> Total number of requests (default 100000) -d <size> Data size of SET/GET value in bytes (default 2)
根據你自己的高峰期的訪問量,在高峰期,瞬時最大用戶量會達到10萬+,-c 100000,-n 10000000,-d 500
1、QPS,自己不同公司,不同服務器,自己去測試,跟生產環境還有區別
生產環境,大量的網絡請求的調用,網絡本身就有開銷,你的redis的吞吐量就不一定那么高了
QPS的兩個殺手:一個是復雜操作,lrange,挺多的; value很大,2 byte,我之前用redis做大規模的緩存
做商品詳情頁的cache,可能是需要把大串數據,拼接在一起,作為一個json串,大小可能都幾k,幾個byte
2、水平擴容redis讀節點,提升度吞吐量
就按照上一節課講解的,再在其他服務器上搭建redis從節點,單個從節點讀請QPS在5萬左右,兩個redis從節點,所有的讀請求打到兩台機器上去,承載整個集群讀QPS在10萬+
3 sentinel模式故障自動遷移
Master-slave主從復制避免了數據丟失帶來的災難性后果。
但是單點故障仍然存在,在運行期間master宕機需要停機手動切換。
Sentinel很好的解決了這個問題,當Master-slave模式中的Master宕機后,能夠自主切換,選擇另一個可靠的redis-server充當master角色,使系統仍正常運行。
一般來說sentinel server需要大於等於3個。
這里通過修改端口的方式開啟3個sentinel server。修改配置文件sentinel.conf部分屬性
#服務運行端口號 port 26379
sentinel monitor mumaster 1270.0.0.1 9999 2 #mymaster為指定的master服務器起一個別名 #master IP和端口號 #2的含義:當開啟的sentinel server認為當前master主觀下線的(+sdown)數量達到2時,則sentinel server認為當前master客觀下線(+odown)系統開始自動遷移。2的計算(建議):
#sentinel server數量的大多數,至少為count(sentinel server)/2 向上取整。2>3/2(主觀下線與客觀下線?) #master別名和認證密碼。這就提醒了用戶,在master-slave系統中,各服務的認證密碼應該保持一致。 sentinel auth-pass mymaster redispass #以守護進程方式運行 daemonize yes logfile /usr/local/redis/logs/sentinel.log.26379 protected-mode no sentinel down-after-milliseconds mymaster 6000 sentinel failover-timeout mymaster 18000
(多開服務只需要在以上配置基礎上修改端口號,其它保持不變 port 26378/port 26377)
開啟Sentinel服務
redis-sentinel /etc/sentinel/26377.conf redis-sentinel /etc/sentinel/26378.conf redis-sentinel /etc/sentinel/26379.conf
啟動之后可以看到日志信息,每個哨兵都能去監控到對應的redis master,並能夠自動發現對應的slave,哨兵之間,互相會自動進行發現,用的就是之前說的pub/sub,消息發布和訂閱channel消息系統和機制
檢查哨兵狀態
redis-cli -h 127.0.0.1 -p 26377 -a "redispass"
sentinel master mymaster
SENTINEL slaves mymaster
SENTINEL sentinels mymaster
SENTINEL get-master-addr-by-name mymaster
哨兵節點相關配置
1、哨兵節點的增加和刪除
增加sentinal,會自動發現
刪除sentinal的步驟
(1)停止sentinal進程
(2)SENTINEL RESET *,在所有sentinal上執行,清理所有的master狀態
(3)SENTINEL MASTER mastername,在所有sentinal上執行,查看所有sentinal對數量是否達成了一致
2、slave的永久下線
讓master摘除某個已經下線的slave:SENTINEL RESET mastername,在所有的哨兵上面執行
3、slave切換為Master的優先級
slave->master選舉優先級:slave-priority,值越小優先級越高
4、基於哨兵集群架構下的安全認證
每個slave都有可能切換成master,所以每個實例都要配置兩個指令
master上啟用安全認證,requirepass
master連接口令,masterauth
sentinal,sentinel auth-pass <master-group-name> <pass>
5、容災演練
通過哨兵看一下當前的master:SENTINEL get-master-addr-by-name mymaster
把master節點kill -9掉,pid文件也刪除掉
查看sentinal的日志,是否出現+sdown字樣,識別出了master的宕機問題; 然后出現+odown字樣,就是指定的quorum哨兵數量,都認為master宕機了
(1)三個哨兵進程都認為master是sdown了
(2)超過quorum指定的哨兵進程都認為sdown之后,就變為odown
(3)哨兵1是被選舉為要執行后續的主備切換的那個哨兵
(4)哨兵1去新的master(slave)獲取了一個新的config version
(5)嘗試執行failover
(6)投票選舉出一個slave區切換成master,每隔哨兵都會執行一次投票
(7)讓salve,slaveof noone,不讓它去做任何節點的slave了; 把slave提拔成master; 舊的master認為不再是master了
(8)哨兵就自動認為之前的master變成slave,將投票出的slave變成master
(9)哨兵去探查了一下之前的master(變成來salve)的狀態,認為它sdown了
故障恢復,再將舊的master重新啟動,查看是否被哨兵自動切換成slave節點
查看到結果將9999 切換為slave節點
容災演練日志 Sentinel ID is ea82430cf7f6d452eb22bbf29b92fcf001c734c8 3010:X 21 Nov 22:37:31.405 # +monitor master mymaster 127.0.0.1 9999 quorum 2 3010:X 21 Nov 23:01:12.589 # +sdown master mymaster 127.0.0.1 9999 3010:X 21 Nov 23:01:12.642 # +odown master mymaster 127.0.0.1 9999 #quorum 3/2 -- 進入ODOWN狀態時。有三個哨兵認為master當機了 3010:X 21 Nov 23:01:12.642 # +new-epoch 7 -- 當前配置版本被更新時。 3010:X 21 Nov 23:01:12.642 # +try-failover master mymaster 127.0.0.1 9999 -- 嘗試故障轉移,正等待其他sentinel的選舉。 3010:X 21 Nov 23:01:12.658 # +vote-for-leader ea82430cf7f6d452eb22bbf29b92fcf001c734c8 7 -- 投票給領導 3010:X 21 Nov 23:01:12.668 # edace82644513417b676ee6eced3184771d6361d voted for ea82430cf7f6d452eb22bbf29b92fcf001c734c8 7 3010:X 21 Nov 23:01:12.668 # 7e68a54266703cbf429f5c6512a50a39ab94b943 voted for ea82430cf7f6d452eb22bbf29b92fcf001c734c8 7 3010:X 21 Nov 23:01:12.716 # +elected-leader master mymaster 127.0.0.1 9999 -- 被選舉為去執行failover的時候。 3010:X 21 Nov 23:01:12.716 # +failover-state-select-slave master mymaster 127.0.0.1 9999 -- 開始要選擇一個slave當選新master時。 3010:X 21 Nov 23:01:12.792 # +selected-slave slave 127.0.0.1:9998 127.0.0.1 9998 @ mymaster 127.0.0.1 9999 -- 找到了port:9998一個適合的slave來擔當新master -- 當把選擇為新master的slave的身份進行切換的時候。 3010:X 21 Nov 23:01:12.792 * +failover-state-send-slaveof-noone slave 127.0.0.1:9998 127.0.0.1 9998 @ mymaster 127.0.0.1 9999 -- 等待提升 9998 為新的master 3010:X 21 Nov 23:01:12.851 * +failover-state-wait-promotion slave 127.0.0.1:9998 127.0.0.1 9998 @ mymaster 127.0.0.1 9999 3010:X 21 Nov 23:01:13.699 # +promoted-slave slave 127.0.0.1:9998 127.0.0.1 9998 @ mymaster 127.0.0.1 9999 -- 提升 9998 master 3010:X 21 Nov 23:01:13.699 # +failover-state-reconf-slaves master mymaster 127.0.0.1 9999 -- Failover狀態變為reconf-slaves狀態時 3010:X 21 Nov 23:01:13.749 * +slave-reconf-sent slave 127.0.0.1:9997 127.0.0.1 9997 @ mymaster 127.0.0.1 9999 -- 重新配置 9997為slave 3010:X 21 Nov 23:01:14.770 # -odown master mymaster 127.0.0.1 9999 -- 離開ODOWN狀態時。 -- inprog 9997 slave被重新配置為9998的master的slave,但數據復制還未發生時。 3010:X 21 Nov 23:01:14.770 * +slave-reconf-inprog slave 127.0.0.1:9997 127.0.0.1 9997 @ mymaster 127.0.0.1 9999 -- done 9997 slave被重新配置為9998的master的slave,並且數據復制已經與master同步時。 3010:X 21 Nov 23:01:14.770 * +slave-reconf-done slave 127.0.0.1:9997 127.0.0.1 9997 @ mymaster 127.0.0.1 9999 3010:X 21 Nov 23:01:14.841 # +failover-end master mymaster 127.0.0.1 9999 -- 故障轉移結束 3010:X 21 Nov 23:01:14.841 # +switch-master mymaster 127.0.0.1 9999 127.0.0.1 9998 -- master由9999 替換為 9998 3010:X 21 Nov 23:01:14.841 * +slave slave 127.0.0.1:9997 127.0.0.1 9997 @ mymaster 127.0.0.1 9998 -- 檢測到9997slave並添加進slave列表時 3010:X 21 Nov 23:01:14.842 * +slave slave 127.0.0.1:9999 127.0.0.1 9999 @ mymaster 127.0.0.1 9998 -- 檢測到9999slave 3010:X 21 Nov 23:01:44.849 # +sdown slave 127.0.0.1:9999 127.0.0.1 9999 @ mymaster 127.0.0.1 9998 -- 進入SDOWN狀態時; 3010:X 21 Nov 23:04:19.457 # -sdown slave 127.0.0.1:9999 127.0.0.1 9999 @ mymaster 127.0.0.1 9998 -- 離開SDOWN狀態時