Redis是一個高性能的key-value數據庫,現時越來越多企業與應用使用Redis作為緩存服務器。樓主是一枚JAVA后端程序員,也算是半個運維工程師了。在Linux服務器上搭建Redis,怎么可以不會呢?下面樓主就帶着大家從0開始,依次搭建:Redis單機服務器 -> Redis主從復制 -> Redis-Sentinel高可用。逐步搭建出高可用的Redis緩存服務器。
搭建Redis1. 下載並解壓
首先從Redis官網下載Redis並解壓,樓主使用的版本是4.0.2。依次執行如下命令:
cd/usr/ local/
wget http://download.redis.io/releases/redis-4.0.2.tar.gz
tar -zxvf redis-4.0.2.tar.gz
如果沒有安裝gcc依賴包,則安裝對應依賴包
yuminstall -y gcc-c++ tcl
2. 編譯並安裝
下載並解壓完畢后,則對源碼包進行編譯安裝,樓主的Redis安裝路徑為/usr/local/redis,同學們可以自行修改語句:make install PREFIX=你想要安裝的路徑
cd/usr/ local/redis-4.0.2/
make install PREFIX=/usr/ local/redis
復制Redis相關命令到/usr/sbin目錄下,這樣就可以直接執行這些命令,不用寫全路徑
cd/usr/ local/redis/bin/
sudo cp redis-cli redis-server redis-sentinel /usr/sbin/
3. 建立Redis配置文件
安裝完成之后將 Redis 配置文件拷貝到系統配置目錄/etc/下,redis.conf 是 Redis 的配置文件,redis.conf 在 Redis 源碼目錄,port默認 6379。
cp /usr/ local/redis-4.0.2/redis.conf /etc/
Redis配置文件主要參數解析參考
daemonizeno#redis進程是否以守護進程的方式運行,yes為是,no為否(不以守護進程的方式運行會占用一個終端)
pidfile /var/run/redis.pid #指定redis進程的PID文件存放位置
port 6379#redis進程的端口號
bind 127.0.0.1#綁定的主機地址
timeout 300#客戶端閑置多長時間后關閉連接,默認此參數為0即關閉此功能
loglevel verbose #redis日志級別,可用的級別有debug.verbose.notice.warning
logfile stdout #log文件輸出位置,如果進程以守護進程的方式運行,此處又將輸出文件設置為stdout的話,就會將日志信息輸出到/dev/null里面去了
databases 16#設置數據庫的數量,默認為0可以使用select <dbid>命令在連接上指定數據庫id
save <seconds> <changes> #指定在多少時間內刷新次數達到多少的時候會將數據同步到數據文件;
rdbcompression yes#指定存儲至本地數據庫時是否壓縮文件,默認為yes即啟用存儲;
dbfilename dump.db #指定本地數據庫文件名
dir ./ #指定本地數據問就按存放位置;
slaveof <masterip> <masterport> #指定當本機為slave服務時,設置master服務的IP地址及端口,在redis啟動的時候他會自動跟master進行數據同步
masterauth <master-password> #當master設置了密碼保護時,slave服務連接master的密碼;
requirepass footbared #設置redis連接密碼,如果配置了連接密碼,客戶端在連接redis是需要通過AUTH<password>命令提供密碼,默認關閉
maxclients 128#設置同一時間最大客戶連接數,默認無限制;redis可以同時連接的客戶端數為redis程序可以打開的最大文件描述符,如果設置 maxclients 0,表示不作限制。當客戶端連接數到達限制時,Redis會關閉新的連接並向客戶端返回max number of clients reached錯誤信息
maxmemory<bytes> #指定Redis最大內存限制,Redis在啟動時會把數據加載到內存中,達到最大內存后,Redis會先嘗試清除已到期或即將到期的Key,當此方法處理 后,仍然到達最大內存設置,將無法再進行寫入操作,但仍然可以進行讀取操作。Redis新的vm機制,會把Key存放內存,Value會存放在swap區
appendonly no#指定是否在每次更新操作后進行日志記錄,Redis在默認情況下是異步的把數據寫入磁盤,如果不開啟,可能會在斷電時導致一段時間內的數據丟失。因為 redis本身同步數據文件是按上面save條件來同步的,所以有的數據會在一段時間內只存在於內存中。默認為no
appendfilename appendonly.aof #指定跟新日志文件名默認為appendonly.aof
appendfsync everysec #指定更新日志的條件,有三個可選參數no:表示等操作系統進行數據緩存同步到磁盤(快),always:表示每次更新操作后手動調用fsync()將數據寫到磁盤(慢,安全), everysec:表示每秒同步一次(折衷,默認值);
3.1 設置后端啟動:
由於Redis默認是前端啟動,必須保持在當前的窗口中,如果使用ctrl + c退出,那么Redis也就退出,不建議使用。
vi/etc/redis.conf
修改Redis配置文件把舊值daemonize no 改為 新值daemonize yes
3.2 設置訪問:
Redis默認只允許本機訪問,可是有時候我們也需要 Redis 被遠程訪問。
vi/etc/redis.conf
找到 bind 那行配置,默認是: # bind 127.0.0.1
去掉#注釋並改為: bind 0.0.0.0 此設置會變成允許所有遠程訪問。如果想指定限制訪問,可設置對應的IP。
3.3 配置Redis日志記錄:
找到logfile那行配置,默認是:logfile "",改為logfile /var/log/redis_6379.log
3.4 設置 Redis 請求密碼:vi/etc/redis.conf
找到默認是被注釋的這一行:# requirepass foobared
去掉注釋,把 foobared 改為你想要設置的密碼,比如我打算設置為:123456,所以我改為:requirepass "123456"
修改之后重啟下服務
有了密碼之后,進入客戶端,就得這樣訪問:redis-cli -h 127.0.0.1 -p 6379 -a 123456
4. Redis常用操作4.1 啟動/usr/ local/redis/bin/redis-server /etc/redis.conf
4.2 關閉/usr/ local/redis/bin/redis-cli -h 127.0. 0. 1-p 6379shutdown
4.3 查看是否啟動ps-ef | grep redis
4.4 進入客戶端redis-cli
4.5 關閉客戶端redis-cli shutdown
4.6 設置開機自動啟動配置echo "/usr/local/redis/bin/redis-server /etc/redis.conf">> /etc/rc.local
4.7 開放防火牆端口添加規則:iptables -I INPUT -p tcp -m tcp --dport 6379 -j ACCEPT
保存規則:service iptables save
重啟 iptables:service iptables restart
5. 將Redis注冊為系統服務
在/etc/init.d目錄下添加Redis服務的啟動,暫停和重啟腳本:
vi/etc/init.d/redis
腳本內容如下:
#!/bin/sh
#
# redis - this starts and stops the redis-server daemon
#
# chkconfig: - 85 15
# deion: Redis is a persistent key-value database
# processname: redis-server
# config: /usr/local/redis/bin/redis-server
# config: /etc/redis.conf
# Source function library.
. /etc/rc.d/init.d/ functions
# Source networking configuration.
. /etc/sysconfig/network
# Check that networking is up.
[ "$NETWORKING"= "no"] && exit0
redis= "/usr/local/redis/bin/redis-server"
prog=$(basename $redis)
REDIS_CONF_FILE= "/etc/redis.conf"
[ -f /etc/sysconfig/redis ] && . /etc/sysconfig/redis
lockfile=/var/lock/subsys/redis
start() {
[ -x $redis] || exit5
[ -f $REDIS_CONF_FILE] || exit6
echo-n $ "Starting $prog: "
daemon $redis$REDIS_CONF_FILE
retval=$?
echo
[ $retval-eq 0 ] && touch $lockfile
return$retval
}
stop() {
echo-n $ "Stopping $prog: "
killproc $prog-QUIT
retval=$?
echo
[ $retval-eq 0 ] && rm -f $lockfile
return$retval
}
restart() {
stop
start
}
reload() {
echo-n $ "Reloading $prog: "
killproc $redis-HUP
RETVAL=$?
echo
}
force_reload() {
restart
}
rh_status() {
status $prog
}
rh_status_q() {
rh_status >/dev/null 2>&1
}
case"$1"in
start)
rh_status_q && exit0
$1
;;
stop)
rh_status_q || exit0
$1
;;
restart|configtest)
$1
;;
reload)
rh_status_q || exit7
$1
;;
force-reload)
force_reload
;;
status)
rh_status
;;
condrestart|try-restart)
rh_status_q || exit0
;;
*)
echo$ "Usage: $0{start|stop|status|restart|condrestart|try-restart| reload|orce-reload}"
exit2
esac
賦予腳本權限
chmod755/etc/init.d/redis
啟動、停止和重啟:
service redis start
service redis stop
service redis restart
至此,Redis單機服務器已搭建完畢,下面我們看看主從架構如何搭建。
搭建Redis主從架構1. redis-server說明172 .16.2.185:6379主
172 .16.2.181:6379從
2. Redis主從架構配置
- 編輯從機的 Redis 配置文件,找到 210 行(大概),默認這一行應該是注釋的: # slaveof
- 我們需要去掉該注釋,並且填寫我們自己的主機的 IP 和 端口,比如:slaveof 172.16.2.185 6379,如果主機設置了密碼,還需要找到masterauth 這一行,去掉注釋,改為masterauth主機密碼。
- 配置完成后重啟從機Redis服務
- 重啟完之后,進入主機的 redis-cli 狀態下redis-cli -h 127.0.0.1 -p 6379 -a 123456,輸入:INFO replication 可以查詢到當前主機的 Redis處於什么角色,有哪些從機已經連上主機。
主機信息172.16.2.185
# Replication
role:master
connected_slaves:1
slave0:ip=172.16.2.181,port=6379,state=online,offset=28,lag=1
master_replid:625ae9f362643da5337835beaeabfdca426198c7
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:28
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:28
從機信息172.16.2.181
# Replication
role:slave
master_host:172.16.2.185
master_port:6379
master_link_status:up
master_last_io_seconds_ago:3
master_sync_in_progress:0
slave_repl_offset:210
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:625ae9f362643da5337835beaeabfdca426198c7
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:210
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:210
此時已經完成了主從配置,我們可以測試下:
我們進入主機的 redis-cli 狀態,然后 set 某個值,比如:set myblog YouMeek.com
我們切換進入從機的 redis-cli 的狀態下,獲取剛剛設置的值看是否存在:get myblog,此時,我們可以發現是可以獲取到值的。
3. Redis主從架構總結
- 需要注意的是:從庫不具備寫入數據能力,不然會報錯。 從庫只有只讀能力。
- 主從架構的優點:除了減少主庫連接的壓力,還有可以關掉主庫的持久化功能,把持久化的功能交給從庫進行處理。
- 第一個從庫配置的信息是連上主庫,后面的第二個從庫配置的連接信息是連上第一個從庫, 假如還有第三個從庫的話,我們可以把第三個從庫的配置信息連上第二個從庫上,以此類推。
Redis Sentinel高可用架構搭建 1. 自動故障轉移
- 雖然使用主從架構配置Redis做了備份,看上去很完美。但由於Redis目前只支持主從復制備份(不支持主主復制),當主Redis掛了,從Redis只能提供讀服務,無法提供寫服務。所以,還得想辦法,當主Redis掛了,讓從Redis升級成為主Redis。
- 這就需要自動故障轉移,Redis Sentinel帶有這個功能,當一個主Redis不能提供服務時,Redis Sentinel可以將一個從Redis升級為主Redis,並對其他從Redis進行配置,讓它們使用新的主Redis進行復制備份。
注意:搭建Redis Sentinel推薦至少3台服務器,但由於樓主偷懶,下面用例只用了2台服務器。
Redis Sentinel的主要功能如下:
- 監控:哨兵不斷的檢查master和slave是否正常的運行。
- 通知:當監控的某台Redis實例發生問題時,可以通過API通知系統管理員和其他的應用程序。
- 自動故障轉移:如果一個master不正常運行了,哨兵可以啟動一個故障轉移進程,將一個slave升級成為master,其他的slave被重新配置使用新的master,並且應用程序使用Redis服務端通知的新地址。
- 配置提供者:哨兵作為Redis客戶端發現的權威來源:客戶端連接到哨兵請求當前可靠的master的地址。如果發生故障,哨兵將報告新地址。
默認情況下,每個Sentinel節點會以每秒一次的頻率對Redis節點和其它的Sentinel節點發送PING命令,並通過節點的回復來判斷節點是否在線。
如果在down-after-millisecondes毫秒內,沒有收到有效的回復,則會判定該節點為主觀下線。
如果該節點為master,則該Sentinel節點會通過sentinel is-master-down-by-addr命令向其它sentinel節點詢問對該節點的判斷,如果超過 個數的節點判定master不可達,則該sentinel節點會將master判斷為客觀下線。
這個時候,各個Sentinel會進行協商,選舉出一個領頭Sentinel,由該領頭Sentinel對master節點進行故障轉移操作。
故障轉移包含如下三個操作:
- 在所有的slave服務器中,挑選出一個slave,並將其轉換為master。
- 讓其它slave服務器,改為復制新的master。
- 將舊master設置為新master的slave,這樣,當舊的master重新上線時,它會成為新master的slave。
2. 搭建Redis Sentinel高可用架構
這里使用兩台服務器,每台服務器上開啟一個redis-server和redis-sentinel服務。
redis-server說明
172 .16.2.185:6379主
172 .16.2.181:6379從
redis-sentinel說明
172 .16.2.185:26379
172 .16.2.181:26379
2.1 建立Redis配置文件
如果要做自動故障轉移,則建議所有的redis.conf都設置masterauth,因為自動故障只會重寫主從關系,即slaveof,不會自動寫入masterauth。如果Redis原本沒有設置密碼,則可以忽略。
Redis程序上面已經安裝過了,我們只需增加redis-sentinel的相關配置即可,將 redis-sentinel的配置文件拷貝到系統配置目錄/etc/下,sentinel.conf 是 redis-sentinel的配置文件,sentinel.conf 在 Redis 源碼目錄。
cp /usr/ local/redis-4.0.2/sentinel.conf /etc/
修改sentinel.conf配置文件內容如下:
vi/etc/sentinel.conf
protected-modeno
sentinelmonitormymaster172 .16.2.1856379 2
# redis在搭建時設置了密碼,所以要進行密碼配置
sentinelauth-passmymaster“123456“
#5秒內 mymaster沒有響應,就認為 SDOWN
sentineldown-after-millisecondsmymaster5000
sentinelfailover-timeoutmymaster15000
在配置最后加上
logfile /var/ log/sentinel. log
pidfile /var/run/sentinel.pid
daemonize yes
配置文件說明:
1.port :當前Sentinel服務運行的端口
2.dir : Sentinel服務運行時使用的臨時文件夾
3.sentinel monitor master001 192.168.110.10163792:Sentinel去監視一個名為master001的主redis實例,這個主實例的IP地址為本機地址192.168.110.101,端口號為6379,而將這個主實例判斷為失效至少需要2個 Sentinel進程的同意,只要同意Sentinel的數量不達標,自動failover就不會執行
4.sentinel down-after-milliseconds master001 30000:指定了Sentinel認為Redis實例已經失效所需的毫秒數。當實例超過該時間沒有返回PING,或者直接返回錯誤,那么Sentinel將這個實例標記為主觀下線。只有一個 Sentinel進程將實例標記為主觀下線並不一定會引起實例的自動故障遷移:只有在足夠數量的Sentinel都將一個實例標記為主觀下線之后,實例才會被標記為客觀下線,這時自動故障遷移才會執行
5.sentinel parallel-syncs master001 1:指定了在執行故障轉移時,最多可以有多少個從Redis實例在同步新的主實例,在從Redis實例較多的情況下這個數字越小,同步的時間越長,完成故障轉移所需的時間就越長
6.sentinel failover-timeout master001 180000:如果在該時間(ms)內未能完成failover操作,則認為該failover失敗
7.sentinel notification- :指定sentinel檢測到該監控的redis實例指向的實例異常時,調用的報警腳本。該配置項可選,但是很常用
2.2 開放防火牆端口添加規則:iptables -I INPUT -p tcp -m tcp --dport 26379 -j ACCEPT
保存規則:service iptables save
重啟 iptables:service iptables restart
2.3 啟動redis-sentinelredis-sentinel /etc/sentinel.conf
在任意一台機子均可查看到相關服務信息
redis-cli-h127 .0.0.1-p26379
INFOsentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_s:0
sentinel_s_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=172.16.2.185:6379,slaves=1,sentinels=2
3. 自動故障轉移測試3.1 停止主Redisredis-cli-h172 .16.2.185-p6379 -a123456 shutdown
3.2 查看redis-sentinel的監控狀態# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_s:0
sentinel_s_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=172.16.2.181:6379,slaves=1,sentinels=2
發現從庫提升為主庫。
3.3 注意事項
- 如果停掉master后,Sentinel顯示足夠數量的sdown后,沒有出現odown或try-failover,則檢查密碼等配置是否正確
- 如果停掉master后,試圖切換的時候,發現日志出現 failover-abort-not-elected,則分2種情況分別解決:
1. 如果Redis實例沒有配置
protected-modeyes
bind172 .16.2.185
則在Sentinel 配置文件加上protected-mode no即可
2. 如果Redis實例有配置
protected-modeyes
bind172 .16.2.185
則在Sentinel配置文件加上
protected-modeyes
bind172 .16.2.185
至此,redis的高可用方案已經搭建完成。
VIP對外提供虛擬IP實現高可用1. 現有情況概述
客戶端程序(如JAVA程序)連接Redis時需要ip和port,但redis-server進行故障轉移時,主Redis是變化的,所以ip地址也是變化的。客戶端程序如何感知當前主Redis的ip地址和端口呢?redis-sentinel提供了接口,請求任何一個Sentinel,發送SENTINEL get-master-addr-by-name 就能得到當前主Redis的ip和port。
客戶端每次連接Redis前,先向sentinel發送請求,獲得主Redis的ip和port,然后用返回的ip和port連接Redis。
這種方法的缺點是顯而易見的,每次操作Redis至少需要發送兩次連接請求,第一次請求Sentinel,第二次請求Redis。
更好的辦法是使用VIP,當然這對配置的環境有一定的要求,比如Redis搭建在阿里雲服務器上,可能不支持VIP。
VIP方案是,Redis系統對外始終是同一ip地址,當Redis進行故障轉移時,需要做的是將VIP從之前的Redis服務器漂移到現在新的主Redis服務器上。
比如:當前Redis系統中主Redis的ip地址是172.16.2.185,那么VIP(172.16.2.250)指向172.16.2.185,客戶端程序用VIP(172.16.2.250)地址連接Redis,實際上連接的就是當前主Redis,這樣就避免了向Sentinel發送請求。
當主Redis宕機,進行故障轉移時,172.16.2.181這台服務器上的Redis提升為主,這時VIP(172.16.2.250)指向172.16.2.181,這樣客戶端程序不需要修改任何代碼,連接的是172.16.2.181這台主Redis。
2.漂移VIP實現Redis故障轉移
那么現在的問題是,如何在進行Redis故障轉移時,將VIP漂移到新的主Redis服務器上。
這里可以使用Redis Sentinel的一個參數client-reconfig-,這個參數配置執行腳本,Sentinel在做failover的時候會執行這個腳本,並且傳遞6個參數 ,其中 是新主Redis的IP地址,可以在這個腳本里做VIP漂移操作。
sentinelclient-reconfig- mymaster /opt/notify_mymaster.sh
修改兩個服務器的redis-sentinel配置文件/etc/sentinel.conf,增加上面一行。然后在/opt/目錄下創建notify_mymaster.sh腳本文件,這個腳本做VIP漂移操作,內容如下:
vi/opt/notify_mymaster.sh
#!/bin/bash
echo"File Name: $0"
echo"Quoted Values: $@"
echo"Quoted Values: $*"
echo"Total Number of Parameters : $#"
MASTER_IP= ${6}#第六個參數是新主redis的ip地址
LOCAL_IP= '172.16.2.185'#當前服務器IP,主機172.16.2.185,從機172.16.2.181
VIP= '172.16.2.250'
NETMASK= '24'
INTERFACE= 'eth1'
if[ ${MASTER_IP}= ${LOCAL_IP}]; then
sudo /sbin/ip addr add ${VIP}/ ${NETMASK}dev ${INTERFACE}#將VIP綁定到該服務器上
sudo /sbin/arping -q -c 3 -A ${VIP}-I ${INTERFACE}
exit0
else
sudo /sbin/ip addr del ${VIP}/ ${NETMASK}dev ${INTERFACE}#將VIP從該服務器上刪除
exit0
fi
exit1 #如果返回1,sentinel會一直執行這個腳本
賦予腳本權限
chmod755/opt/notify_mymaster.sh
現在當前主Redis是172.16.2.185,需要手動綁定VIP到該服務器上。
/sbin/ip addr add172.16.2.250/ 24dev eth1
/sbin/arping -q -c 3-A 172.16.2.250-I eth1
由於VIP只能綁定只有一台機子,所以建議將改為bind 0.0.0.0添加至redis.conf 中
vi/etc/redis.conf
設置bind 0.0.0.0
由於VIP只能綁定只有一台機子,所以建議將改為bind 0.0.0.0添加至sentinel.conf中
vi/etc/sentinel.conf
設置bind 0.0.0.0
重啟Redis
serviceredis restart
重啟Sentinel
redis-sentinel /etc/sentinel.conf
隨后我們在另一台機器172.16.2.181上,通過VIP訪問主機
redis-cli-h172 .16.2.250-p6379 -a123456 INFOreplication
可正常通訊,信息如下:
# Replication
role:master
connected_slaves:1
slave0:ip=172.16.2.181,port=6379,state=online,offset=0,lag=0
master_replid:325b0bccab611d329d9c2cd2c35a1fe3c01ae196
master_replid2:c1f7a7d17d2c35575a34b00eb10c8abf32df2243
master_repl_offset:22246293
second_repl_offset:22241024
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:22237293
repl_backlog_histlen:9001
訪問主機的Sentinel
redis-cli-h172 .16.2.250-p26379 INFOsentinel
可正常通訊,信息如下:
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_s:0
sentinel_s_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=172.16.2.185:6379,slaves=1,sentinels=3
下面關閉主機的Redis服務,看看VIP是否漂移到另一台服務器上。
redis-cli-h172 .16.2.185-p6379 -a123456 shutdown
查看是否已進行切換
redis-cli-h172 .16.2.250-p26379 INFOsentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_s:0
sentinel_s_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=172.16.2.181:6379,slaves=1,sentinels=3
通過查詢Sentinel發現從機172.16.2.181提升為主。
通過訪問VIP的方式連接Redis
redis-cli-h172 .16.2.250-p6379 -a123456 INFOreplication
# Replication
role:master
connected_slaves:0
master_replid:cab30a4083f35652053ffcd099d70b9aaf7a80f3
master_replid2:3da856dd33cce4bedd54926df6797b410f1ab9e8
master_repl_offset:74657
second_repl_offset:36065
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:74657
從上面信息可知,VIP已經飄移成功。
至此,高可用Redis緩存服務已搭建完畢。