http://blog.51cto.com/mxlmgl/2065789
redis-server說明
伺服器A:192.168.1.131:8000(主)
伺服器B:192.168.1.135:8000
伺服器C:192.168.1.231:8000
伺服器D:192.168.1.241:8000
redis-sentinel說明
伺服器A:192.168.1.131:6800
伺服器B:192.168.1.135:6800
伺服器C:192.168.1.231:6800
伺服器D:192.168.1.241:6800
2.搭建redis系統
yum install -y gcc* tcl
首先下載下傳安裝redis
cd /usr/local
wget
http://download.redis.io/releases/redis-3.2.11.tar.gztar zxvf redis-3.2.11.tar.gz
mv redis-3.2.11 redis
cd redis
make && make install
如果編譯安裝過程中,出現報錯:
zmalloc.h:51:31: error: jemalloc/jemalloc.h: No such file or directory
原因:一些編譯依賴或原來編譯遺留出現的問題
解決方案:make distclean 清理一下,然後再make
或者直接 make MALLOC=libc && make install
[root@localhost redis]# cd src
[root@localhost src]#cp redis-server redis-cli redis-check-aof redis-check-rdb redis-sentinel redis-trib.rb /usr/local/bin/
[root@localhost src]# mkdir /etc/redis
[root@localhost src]# mkdir /var/redis
[root@localhost src]# mkdir /var/redis/{log,run,redis}
[root@localhost src]cd ..
[root@localhost redis]#cp redis.conf /etc/redis/redis.conf
[root@localhost redis]# vi/etc/redis/redis.conf
修改如下:
port 8000 #修改端口是安全的第一步
daemonize yes
bind 0.0.0.0
pidfile /var/run/redis-8000.pid
logfile /var/redis/log/redis_8000.log
dir /var/redis/redis //工作目錄,dump檔案所在目錄
slaveof 192.168.1.131 8000 #從redis比主redis多這一行
########################################################
redis預設的持久化方式是RDB,資料寫入到dump檔案中。如果要啟用AOF持久化,就在redis.conf檔案中配置如下:
appendonly yes #啟用AOF持久化方式
appendfilename "appendonly.aof" #AOF檔案的名稱,預設為appendonly.aof
# appendfsync always #每次收到寫指令就立即強制寫入磁盤,是最有保證的完全的持久化,但速度也是最慢的,一般不推薦使用。
appendfsync everysec #每秒鐘強制寫入磁盤一次,在性能和持久化方面做了很好的折中,是受推薦的方式。
# appendfsync no #完全依賴OS的寫入,一般為30秒左右一次,性能最好但是持久化最沒有保證,不被推薦。
[root@localhost redis]#redis-server /etc/redis/redis.conf
設定開機啟動
[root@dev ~]# echo "/usr/local/bin/redis-server /etc/redis/redis.conf" >> /etc/rc.local
關閉redis服務
[root@dev ~]# redis-cli shutdown //預設是6379端口
如果端口變化可以指定端口
[root@dev ~]# redis-cli -p 8000 shutdown
還可以通過如下方法,設定redis服務啟動腳本及開機自啟動
将redis解壓包下utils下redis啟動腳本redis_init_script拷貝至/etc/init.d/,并修改腳本名稱(也可不修改)為redis
[root@dev ~]# cp /usr/local/src/redis-stable/utils/redis_init_script /etc/init.d/redis
[root@dev ~]# chmod +x /etc/init.d/redis
修改腳本pid及conf路徑為實際路徑
[root@dev ~]# vim /etc/init.d/redis
......
REDISPORT=6379
EXEC=/usr/local/bin/redis-server
CLIEXEC=/usr/local/bin/redis-cli
PIDFILE=/var/redis/run/redis_6379.pid
CONF="/etc/redis/redis.conf"
這樣,就可以直接用下面的指令關閉和啟動redis服務了
[root@dev ~]# /etc/init.d/redis stop
Stopping ...
Redis stopped
[root@dev ~]# lsof -i:6379
[root@dev ~]# /etc/init.d/redis start
Starting Redis server...
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
redis-ser 9372 root 4u IPv4 58648940 0t0 TCP localhost:6379 (LISTEN)
設定自啟動
[root@dev ~]# chkconfig redis on
redis 服務不支援 chkconfig
這是因為沒有在啟動腳本/etc/init.d/redis裡加入redis啟動優先級資訊,可添加如下紅色字型的兩行:
[root@dev ~]# vim /etc/init.d/redis
#!/bin/sh
#
# chkconfig: 2345 90 10 //注意:後面的英文空格
# description: Redis is a persistent key-value database //注意:後面的英文空格
# Simple Redis init.d script conceived to work on Linux systems
# as it does use of the /proc filesystem.
.......
[root@dev ~]# chkconfig --list|grep redis
redis 0:關閉 1:關閉 2:啟用 3:啟用 4:啟用 5:啟用 6:關閉
驗證:
在A伺服器(主)
[root@localhost ~]# redis-cli -h 192.168.1.131 -p 8000 info replication
[root@localhost ~]# redis-cli -h 192.168.1.131 -p 8000 info replication
# Replication
role:master
connected_slaves:3
slave0:ip=192.168.1.231,port=8000,state=online,offset=462,lag=0
slave1:ip=192.168.1.241,port=8000,state=online,offset=462,lag=1
slave2:ip=192.168.1.135,port=8000,state=online,offset=462,lag=1
master_repl_offset:462
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:461
#############################################################################
[root@localhost ~]# redis-cli -h 192.168.1.131 -p 8000
[root@localhost ~]# 192.168.1.131:8000> get name thb (主,1.131)
[root@localhost redis]# redis-cli -h 192.168.1.135 -p 8000 (從。1.135)
192.168.1.135:8000> get name
"thb"
192.168.1.135:8000>
############################################################################
配置哨兵sentinel
[root@localhost redis]# cd /usr/local/redis
[root@localhost redis]# mkdir /etc/sentinel
[root@localhost redis]# cp -a sentinel.conf /etc/sentinel
[root@localhost redis]# vi /etc/sentinel/sentinel.conf (之前的都删掉,就保留下面的内容)
bind 0.0.0.0
daemonize yes
port 6800
logfile /var/log/sentinel.log
pidfile /var/run/sentinel.pid
sentinel monitor master8000 192.168.1.131 8000 2
#5秒内master6800沒有響應,就認為SDOWN
sentinel down-after-milliseconds master8000 5000
sentinel failover-timeout master8000 15000
[root@localhost redis]# redis-sentinel /etc/sentinel/sentinel.conf
[root@localhost redis]#echo "/usr/local/bin/redis-sentinel /etc/sentinel/sentinel.conf" >> /etc/rc.local
四個redis-sentinel服務啟動完畢後,連接配接任意sentinel服務可以獲知目前主redis服務資訊
[root@localhost ~]# redis-cli -h 192.168.1.131 -p 6800 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=master8000,status=ok,address=192.168.1.131:8000,slaves=3,sentinels=3
測試
1.把主redis停掉
[root@localhost ~]# redis-cli -h 192.168.1.131 -p 8000 shutdown
[root@localhost ~]# netstat -ntpl
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:58566 0.0.0.0:* LISTEN 1235/rpc.statd
tcp 0 0 0.0.0.0:111 0.0.0.0:* LISTEN 1213/rpcbind
tcp 0 0 0.0.0.0:6800 0.0.0.0:* LISTEN 1685/redis-sentinel
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1447/sshd
tcp 0 0 127.0.0.1:631 0.0.0.0:* LISTEN 1290/cupsd
tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN 1526/master
tcp 0 0 :::111 :::* LISTEN 1213/rpcbind
tcp 0 0 :::52913 :::* LISTEN 1235/rpc.statd
tcp 0 0 :::22 :::* LISTEN 1447/sshd
tcp 0 0 ::1:631 :::* LISTEN 1290/cupsd
tcp 0 0 ::1:25 :::* LISTEN 1526/master
2.檢視redis-sentinel的監控狀态
master0:name=master8000,status=ok,address=192.168.1.231:8000,slaves=3,sentinels=6
發現231這台redis-server提升為主庫。
在1.231 這台上檢視
[root@session1 ~]# redis-cli -h 192.168.1.231 -p 8000 info replication
connected_slaves:2
slave0:ip=192.168.1.241,port=8000,state=online,offset=36416,lag=1
slave1:ip=192.168.1.135,port=8000,state=online,offset=36558,lag=0
master_repl_offset:36842
repl_backlog_histlen:36841
發現role已經是master了
至此,redis的高可用方案已經搭建完成。
六、用戶端程式
用戶端程式(如PHP程式)連接配接redis時需要ip和port,但redis-server進行故障轉移時,主redis是變化的,是以ip位址也是變化的。用戶端程式如何感覺目前主redis的ip位址和端口呢?redis-sentinel提供了接口,請求任何一個sentinel,發送SENTINEL get-master-addr-by-name 就能得到目前主redis的ip和port。
[root@localhost ~]# redis-cli -h 192.168.1.131 -p 6800
192.168.1.131:6800> sentinel get-master-addr-by-name master8000
1) "192.168.1.231"
2) "8000"
192.168.1.131:6800>
擷取目前主redis的ip和port
用戶端每次連接配接redis前,先向sentinel發送請求,獲得主redis的ip和port,然後用傳回的ip和port連接配接redis。
這種方法的缺點是顯而易見的,每次操作redis至少需要發送兩次連接配接請求,第一次請求sentinel,第二次請求redis。
php請求sentinel程式代碼可參見:
https://github.com/huyanping/redis-sentinel更好的辦法是使用VIP,當然這對配置的環境有一定的要求,比如redis搭建在阿裡雲伺服器上,可能不支援VIP。
VIP方案是,redis系統對外始終是同一ip位址,當redis進行故障轉移時,需要做的是将VIP從之前的redis伺服器漂移到現在新的主redis伺服器上。
比如:目前redis系統中主redis的ip位址是192.168.56.101,那麼VIP(192.168.56.250)指向192.168.56.101,用戶端程式用VIP(192.168.56.250)位址連接配接redis,實際上連接配接的就是目前主redis,這樣就避免了向sentinel發送請求。
當主redis當機,進行故障轉移時,192.168.56.102這台伺服器上的redis提升為主,這時VIP(192.168.56.250)指向192.168.56.102,這樣用戶端程式不需要修改任何代碼,連接配接的是192.168.56.102這台主redis。
VIP指向192.168.1.131
故障轉移後,VIP漂移指向192.168.1.231
七、漂移VIP
那麼現在的問題是,如何在進行redis故障轉移時,将VIP漂移到新的主redis伺服器上。
這裡可以使用redis sentinel的一個參數client-reconfig-script,這個參數配置執行腳本,sentinel在做failover的時候會執行這個腳本,并且傳遞6個參數、 、 、 、 、 、,其中是新主redis的IP位址,可以在這個腳本裡做VIP漂移操作。
sentinel client-reconfig-script master8000 /opt/notify_master6800.sh
修改三個伺服器的redis-sentinel配置檔案/etc/sentinel.conf,增加上面一行。然後在/opt/目錄下建立notify_master6800.sh腳本檔案,這個腳本做VIP漂移操作,内容如下:
#notify_master6800.sh腳本内容
#!/bin/bash
MASTER_IP=$6 #第六個參數是新主redis的ip位址
LOCAL_IP='192.168.1.231' #其他三個伺服器上為192.168.1.131,192.168.56.135,192.168.1.241
VIP='192.168.1.251'
NETMASK='24'
INTERFACE='eth0'
if [ ${MASTER_IP} = ${LOCAL_IP} ];then
/sbin/ip addr add ${VIP}/${NETMASK} dev ${INTERFACE} #将VIP綁定到該伺服器上
/sbin/arping -q -c 3 -A ${VIP} -I ${INTERFACE}
exit 0
else
/sbin/ip addr del ${VIP}/${NETMASK} dev ${INTERFACE} #将VIP從該伺服器上删除
exit 0
fi
exit 1 #如果傳回1,sentinel會一直執行這個腳本
現在目前主redis是192.168.1.231,需要手動綁定VIP到該伺服器上。
/sbin/ip addr add 192.168.1.251/24 dev eth0
/sbin/arping -q -c 3 -A 192.168.1.251 -I eth0
然後,去另一個伺服器上通過VIP位址連接配接redis-server和redis-sentinel。
[root@localhost opt]# ifconfig
eth0 Link encap:Ethernet HWaddr 00:0C:29:34:43:27
inet addr:192.168.1.131 Bcast:192.168.1.255 Mask:255.255.255.0
inet6 addr: fe80::20c:29ff:fe34:4327/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:3830849 errors:0 dropped:0 overruns:0 frame:0
TX packets:3406249 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:444297730 (423.7 MiB) TX bytes:416136987 (396.8 MiB)
[root@localhost opt]# redis-cli -h 192.168.1.251 -p 8000 info replication
slave0:ip=192.168.1.241,port=8000,state=online,offset=18468111,lag=1
slave1:ip=192.168.1.135,port=8000,state=online,offset=18468111,lag=0
slave2:ip=192.168.1.131,port=8000,state=online,offset=18468111,lag=0
master_repl_offset:18468111
repl_backlog_first_byte_offset:17419536
[root@localhost opt]# redis-cli -h 192.168.1.251 -p 6800 info sentinel
master0:name=master8000,status=ok,address=192.168.1.231:8000,slaves=3,sentinels=4
通過VIP連接配接redis
從上面也可以看出目前主redis是192.168.1.231。
下面關閉這台redis服務,看看VIP是否漂移到另一台伺服器上。
[root@session1 opt]# redis-cli -h 192.168.1.231 -p 8000 shutdown
[root@session1 opt]# redis-cli -h 192.168.1.231 -p 6800 info sentinel
master0:name=master8000,status=ok,address=192.168.1.135:8000,slaves=3,sentinels=4
通過通路VIP連接配接redis,發現VIP确實指向了192.168.1.135。
這裡要注意腳本裡的ip和網卡名稱(eth)不能錯,要不飄移不成功。
八、總結
通過上面的操作,使用redis主從 + 哨兵(sentinel)+ 漂移VIP的方案搭建了一個redis高可用系統,但這個系統保證的是單個redis執行個體的高可用,是以适合業務比較小的應用。如果業務比較大,并發量比較高,建議搭建redis叢集,比如官方redis cluster,還有開源的codings叢集。