redis怎麼才能作到高可用
對於redis主從架構,slave能夠對應多個自己能夠保障高可用,可是對於一個master節點,若是宕機,整個緩存系統就沒法進行寫的操做,顯然整個系統會沒法作到高可用
sentinel哨兵能夠監測master節點是否正常運行(會自動識別出全部的slave信息),若是出現宕機,則會在對應的slave節點中經過投票的方式來選取一個slave節點做爲新的master節點,
舊的master節點恢復以後會被接管成爲新的master節點的slave節點。同時sentinel哨兵節點自己也是集羣的方式部署來保障自身的高可用,而且一個sentinel是能夠同時監聽多個master節點
對於sentinel哨兵節點的一些核心概念:redis
一、sdown和odown轉換機制算法
sdown和odown兩種失敗狀態json
sdown是主觀宕機,就一個哨兵若是本身以爲一個master宕機了,那麼就是主觀宕機vim
odown是客觀宕機,若是quorum數量的哨兵都以爲一個master宕機了,那麼就是客觀宕機centos
sdown達成的條件很簡單,若是一個哨兵ping一個master,超過了is-master-down-after-milliseconds指定的毫秒數以後,就主觀認爲master宕機緩存
sdown到odown轉換的條件很簡單,若是一個哨兵在指定時間內,收到了quorum指定數量的其餘哨兵也認爲那個master是sdown了,那麼就認爲是odown了,客觀認爲master宕機安全
二、哨兵集羣的自動發現機制服務器
哨兵互相之間的發現,是經過redis的pub/sub系統實現的,每一個哨兵都會往__sentinel__:hello這個channel裏發送一個消息,這時候全部其餘哨兵均可以消費到這個消息,並感知到其餘的哨兵的存在網絡
每隔兩秒鐘,每一個哨兵都會往本身監控的某個master+slaves對應的__sentinel__:hello channel裏發送一個消息,內容是本身的host、ip和runid還有對這個master的監控配置架構
每一個哨兵也會去監聽本身監控的每一個master+slaves對應的__sentinel__:hello channel,而後去感知到一樣在監聽這個master+slaves的其餘哨兵的存在
每一個哨兵還會跟其餘哨兵交換對master的監控配置,互相進行監控配置的同步
三、slave配置的自動糾正
哨兵會負責自動糾正slave的一些配置,好比slave若是要成爲潛在的master候選人,哨兵會確保slave在複製現有master的數據; 若是slave鏈接到了一個錯誤的master上,好比故障轉移以後,那麼哨兵會確保它們鏈接到正確的master上
四、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
五、quorum和majority
每次一個哨兵要作主備切換,首先須要quorum數量的哨兵認爲odown,而後選舉出一個哨兵來作切換,這個哨兵還得獲得majority哨兵的受權,才能正式執行切換
若是quorum < majority,好比5個哨兵,majority就是3,quorum設置爲2,那麼就3個哨兵受權就能夠執行切換
可是若是quorum >= majority,那麼必須quorum數量的哨兵都受權,好比5個哨兵,quorum是5,那麼必須5個哨兵都贊成受權,才能執行切換
六、configuration epoch
哨兵會對一套redis master+slave進行監控,有相應的監控的配置
執行切換的那個哨兵,會從要切換到的新master(salve->master)那裏獲得一個configuration epoch,這就是一個version號,每次切換的version號都必須是惟一的
若是第一個選舉出的哨兵切換失敗了,那麼其餘哨兵,會等待failover-timeout時間,而後接替繼續執行切換,此時會從新獲取一個新的configuration epoch,做爲新的version號
七、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壓測工具,是最快捷最方便的,固然啦,這個工具比較簡單,用一些簡單的操做和場景去壓測
一、對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
一、QPS,本身不一樣公司,不一樣服務器,本身去測試,跟生產環境還有區別
生產環境,大量的網絡請求的調用,網絡自己就有開銷,你的redis的吞吐量就不必定那麼高了
QPS的兩個殺手:一個是複雜操做,lrange,挺多的; value很大,2 byte,我以前用redis作大規模的緩存
作商品詳情頁的cache,多是須要把大串數據,拼接在一塊兒,做爲一個json串,大小可能都幾k,幾個byte
二、水平擴容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
哨兵節點相關配置
一、哨兵節點的增長和刪除
增長sentinal,會自動發現
刪除sentinal的步驟
(1)中止sentinal進程
(2)SENTINEL RESET *,在全部sentinal上執行,清理全部的master狀態
(3)SENTINEL MASTER mastername,在全部sentinal上執行,查看全部sentinal對數量是否達成了一致
二、slave的永久下線
讓master摘除某個已經下線的slave:SENTINEL RESET mastername,在全部的哨兵上面執行
三、slave切換爲Master的優先級
slave->master選舉優先級:slave-priority,值越小優先級越高
四、基於哨兵集羣架構下的安全認證
每一個slave都有可能切換成master,因此每一個實例都要配置兩個指令
master上啓用安全認證,requirepass
master鏈接口令,masterauth
sentinal,sentinel auth-pass <master-group-name> <pass>
五、容災演練
經過哨兵看一下當前的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狀態時