標(biāo)簽: redis 緩存 主從 哨兵 集群
本文簡單的介紹redis三種模式在linux的安裝部署和數(shù)據(jù)存儲的總結(jié),希望可以相互交流相互提升。
一. redis安裝
1、安裝單機版redis
對于Centos7在安裝redis之前需要進行一些常用工具的安裝:
sudo yum install net-tools 網(wǎng)絡(luò)工具,比如ifconfig
sudo yum -y install lrzsz 文件的上傳下載
關(guān)閉防火墻
systemctl stop firewalld.service #停止firewall
systemctl disable firewalld.service #禁止firewall開機啟動
firewall-cmd --state #查看默認(rèn)防火墻狀態(tài)(關(guān)閉后顯示notrunning,開啟后顯示running)
正式安裝redis
使用命令的模式進行redis的安裝(文件down到/usr/local/sftp/)
安裝前需要進行tcl的安裝,否則在make的時候報錯
wget http://downloads.sourceforge.net/tcl/tcl8.6.1-src.tar.gz
tar -zxvf tcl8.6.1-src.tar.gz
cd /usr/local/tcl8.6.1/unix/
./configure
make && make install
使用redis-3.2.8.tar.gz(截止2017年4月的最新穩(wěn)定版)
tar -zxvf redis-3.2.8.tar.gz
cd redis-3.2.8
make && make test && make install
2. redis 的make test出現(xiàn)異常解決
在redis進行maketest時候會出現(xiàn)一系列的異常,有如下解決方案:
- You need tcl 8.5 or newer in order to run the Redis test
解決方案:前面已經(jīng)安裝了tcl;
- [exception]: Executing test client: NOREPLICAS Not enough good slaves to write..
NOREPLICAS Not enough good slaves to write.
解決方案:vim tests/integration/replication-2.tcl
將其中的第一個if里面的after 1000修改成after 10000,延長測試時間 - [err]: Slave should be able to synchronize with the master in tests/integration/replication-psync.tcl
Replication not started.
解決方案:重新make test一次就好了; - [err]: Test replication partial resync: ok psync (diskless: yes, reconnect: 1) in tests/integration/replication-psync.tcl
解決方案:vim tests/integration/replication-psync.tcl
將其中的after 100修改成after 1000就好了。
3. redis的生產(chǎn)環(huán)境啟動方案
用redis-server啟動一下redis,做一些實驗沒什么意義。
要把redis作為一個系統(tǒng)的daemon進程去運行的,每次系統(tǒng)啟動,redis進程一起啟動,操作不走如下:
- redis utils目錄下,有個redis_init_script腳本
- 將redis_init_script腳本拷貝到linux的/etc/init.d目錄中,將redis_init_script重命名為redis_6379,6379是我們希望這個redis實例監(jiān)聽的端口號
- 修改redis_6379腳本的第6行的REDISPORT,設(shè)置為相同的端口號(默認(rèn)就是6379)
- 創(chuàng)建兩個目錄:/etc/redis(存放redis的配置文件),/var/redis/6379(存放redis的持久化文件)
- 修改redis配置文件(默認(rèn)在根目錄下,redis.conf),拷貝到/etc/redis目錄中,修改名稱為6379.conf
- 修改redis.conf中的部分配置為生產(chǎn)環(huán)境
daemonize yes 讓redis以daemon進程運行
pidfile /var/run/redis_6379.pid 設(shè)置redis的pid文件位置
port 6379 設(shè)置redis的監(jiān)聽端口號
dir /var/redis/6379 設(shè)置持久化文件的存儲位置 - 啟動redis,執(zhí)行cd /etc/init.d, chmod 777 redis_6379,./redis_6379 start
- 確認(rèn)redis進程是否啟動,ps -ef | grep redis
9.讓redis跟隨系統(tǒng)啟動自動啟動 sudo update-rc.d reds_6379 defaults(7 無法執(zhí)行 可以使用下面的方式)
在redis_6379腳本中,最上面,加入兩行注釋
# chkconfig: 2345 90 10
# description: Redis is a persistent key-value database
chkconfig redis_6379 on
4. redis cli的使用
redis-cli SHUTDOWN,連接本機的6379端口停止redis進程
redis-cli -h 127.0.0.1 -p 6379 SHUTDOWN,制定要連接的ip和端口號
redis-cli PING,ping redis的端口,看是否正常
redis-cli,進入交互式命令行
二. redis 之 RDB 和 AOF
RDB和AOF是redis的一種數(shù)據(jù)持久化的機制。持久化是為了避免系統(tǒng)在發(fā)生災(zāi)難性的系統(tǒng)故障時導(dǎo)致的系統(tǒng)數(shù)據(jù)丟失。我們一般會將數(shù)據(jù)存放在本地磁盤,還會定期的將數(shù)據(jù)上傳到云服務(wù)器。
RDB 是redis的snapshotting,通過redis.conf中的save配置進行設(shè)置,如 save 60 1000:
表示每隔60s,如果有超過1000個key發(fā)生了變更,那么就生成一個新的dump.rdb文件,就是當(dāng)前redis內(nèi)存中完整的數(shù)據(jù)快照,這個操作也被稱之為snapshotting,也可以手動調(diào)用save或者bgsave命令,同步或異步執(zhí)行rdb快照生成
AOF 是以appendonly方式進行數(shù)據(jù)的儲存的,開啟AOF模式后,所有存進redis內(nèi)存的數(shù)據(jù)都會進入os cache中,然后默認(rèn)1秒執(zhí)行一次fsync寫入追加到appendonly.aof文件中。一般我們配置redis.conf中的一下指令:
appendonly yes 可以打開AOF持久化機制,在生產(chǎn)環(huán)境里面,一般來說AOF都是要打開的;
appendfsync everysec 每秒將os cache中的數(shù)據(jù)fsync到磁盤,這個最常用的,生產(chǎn)環(huán)境一般都這么配置,性能很高,QPS可以上萬;還有另外兩種參數(shù)always和no,前者持續(xù)寫入,性能低,數(shù)據(jù)保存完整,后者os cache自己控制寫入時間,那樣可能丟失數(shù)據(jù)很多;
rewrite策略:
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
表示在第一次將緩存中的數(shù)據(jù)追加到aof文件中后記錄次文件的大小,比如128MB,在追加數(shù)據(jù)到文件大小是上次文件的100%,也就是2倍,此時需要判斷文件是否大于64mb,大于min-size則進行rewrite。
AOF和RDB模式我們一般在生產(chǎn)環(huán)境都會打開,一般而言,redis服務(wù)掛掉后進行重啟會優(yōu)先家在aof中的文件。
三. redis 之 主從配置
1. 主從架構(gòu)的核心原理
當(dāng)啟動一個slave node的時候,它會發(fā)送一個PSYNC命令給master node,如果這是slave node重新連接master node,那么master node僅僅會復(fù)制給slave部分缺少的數(shù)據(jù);否則如果是slave node第一次連接master node,那么會觸發(fā)一次full resynchronization;
開始full resynchronization的時候,master會啟動一個后臺線程,開始生成一份RDB快照文件,同時還會將從客戶端收到的所有寫命令緩存在內(nèi)存中。RDB文件生成完畢之后,master會將這個RDB發(fā)送給slave,slave會先寫入本地磁盤,然后再從本地磁盤加載到內(nèi)存中。然后master會將內(nèi)存中緩存的寫命令發(fā)送給slave,slave也會同步這些數(shù)據(jù)。
slave node如果跟master node有網(wǎng)絡(luò)故障,斷開了連接,會自動重連。master如果發(fā)現(xiàn)有多個slave node都來重新連接,僅僅會啟動一個rdb save操作,用一份數(shù)據(jù)服務(wù)所有slave node。
2. 主從復(fù)制的斷點續(xù)傳
從redis 2.8開始,就支持主從復(fù)制的斷點續(xù)傳,如果主從復(fù)制過程中,網(wǎng)絡(luò)連接斷掉了,那么可以接著上次復(fù)制的地方,繼續(xù)復(fù)制下去,而不是從頭開始復(fù)制一份。
master node會在內(nèi)存中常見一個backlog,master和slave都會保存一個replica offset還有一個master id,offset就是保存在backlog中的。如果master和slave網(wǎng)絡(luò)連接斷掉了,slave會讓master從上次的replica offset開始繼續(xù)復(fù)制,但是如果沒有找到對應(yīng)的offset,那么就會執(zhí)行一次resynchronization。
3. 無磁盤化復(fù)制
master在內(nèi)存中直接創(chuàng)建rdb,然后發(fā)送給slave,不會在自己本地落地磁盤了,可以有如下配置:
repl-diskless-sync
repl-diskless-sync-delay 等待一定時長再開始復(fù)制,因為要等更多slave重新連接過來
4. 過期key處理
slave不會過期key,只會等待master過期key。如果master過期了一個key,或者通過LRU淘汰了一個key,那么會模擬一條del命令發(fā)送給slave。
5. 主從架構(gòu)redis配置
- 打開slaveof參數(shù)
在slave node上配置:slaveof masterip masterport
- redis slave node只讀,默認(rèn)開啟,slave-read-only
- master上啟用安全認(rèn)證,requirepass (master 配置)
slave連接master口令,masterauth(slave node 配置)
四. redis 之哨兵模式
1. 哨兵主要功能
- 集群監(jiān)控,負(fù)責(zé)監(jiān)控redis master和slave進程是否正常工作
- 消息通知,如果某個redis實例有故障,那么哨兵負(fù)責(zé)發(fā)送消息作為報警通知給管理員
- 故障轉(zhuǎn)移,如果master node掛掉了,會自動轉(zhuǎn)移到slave node上
- 配置中心,如果故障轉(zhuǎn)移發(fā)生了,通知client客戶端新的master地址
2. reids 對于異步復(fù)制和腦裂數(shù)據(jù)丟失問題解決
min-slaves-to-write 3
min-slaves-max-lag 10
在redis.conf配置文件中,上面的參數(shù)代表至少需要3個slaves節(jié)點與master節(jié)點進行連接,并且master和每個slave的數(shù)據(jù)同步延遲不能超過10秒。一旦上面的設(shè)定沒有匹配上,則master不在提供相應(yīng)的服務(wù)。
3. 哨兵模式的核心機制
- 3.1 sdown和odown轉(zhuǎn)換機制
sdown和odown兩種失敗狀態(tài):
- sdown是主觀宕機,就一個哨兵如果自己覺得一個master宕機了,那么就是主觀宕機;
- odown是客觀宕機,如果quorum數(shù)量的哨兵都覺得一個master宕機了,那么就是客觀宕機;
sdown達(dá)成的條件很簡單,如果一個哨兵ping一個master,超過了is-master-down-after-milliseconds指定的毫秒數(shù)之后,就主觀認(rèn)為master宕機
sdown到odown轉(zhuǎn)換的條件很簡單,如果一個哨兵在指定時間內(nèi),收到了quorum指定數(shù)量的其他哨兵也認(rèn)為那個master是sdown了,那么就認(rèn)為是odown了,客觀認(rèn)為master宕機
- 3.2 哨兵集群的自動發(fā)現(xiàn)機制
哨兵互相之間的發(fā)現(xiàn),是通過redis的pub/sub系統(tǒng)實現(xiàn)的,每個哨兵都會往sentinel:hello這個channel里發(fā)送一個消息,這時候所有其他哨兵都可以消費到這個消息,并感知到其他的哨兵的存在。
每隔兩秒鐘,每個哨兵都會往自己監(jiān)控的某個master+slaves對應(yīng)的sentinel:hello channel里發(fā)送一個消息,內(nèi)容是自己的host、ip和runid還有對這個master的監(jiān)控配置。
每個哨兵也會去監(jiān)聽自己監(jiān)控的每個master+slaves對應(yīng)的sentinel:hello channel,然后去感知到同樣在監(jiān)聽這個master+slaves的其他哨兵的存在。
每個哨兵還會跟其他哨兵交換對master的監(jiān)控配置,互相進行監(jiān)控配置的同步。
3.3 slave配置的自動糾正
哨兵會負(fù)責(zé)自動糾正slave的一些配置,比如slave如果要成為潛在的master候選人,哨兵會確保slave在復(fù)制現(xiàn)有master的數(shù)據(jù);如果slave連接到了一個錯誤的master上,比如故障轉(zhuǎn)移之后,那么哨兵會確保它們連接到正確的master上。3.4 slave->master選舉算法
如果一個master被認(rèn)為odown了,而且majority哨兵都允許了主備切換,那么某個哨兵就會執(zhí)行主備切換操作,此時首先要選舉一個slave來作為新的master。
選舉會考慮slave的一些信息
- 跟master斷開連接的時長
- slave優(yōu)先級
- 復(fù)制offset
- run id
如果一個slave跟master斷開連接已經(jīng)超過了down-after-milliseconds的10倍,外加master宕機的時長,那么slave就被認(rèn)為不適合選舉為master
(down-after-milliseconds * 10) + milliseconds_since_master_is_in_SDOWN_state
接下來會對slave進行排序
- 按照slave優(yōu)先級進行排序,slave priority越低,優(yōu)先級就越高
- 如果slave priority相同,那么看replica offset,哪個slave復(fù)制了越多的數(shù)據(jù),offset越靠后,優(yōu)先級就越高
- 如果上面兩個條件都相同,那么選擇一個run id比較小的那個slave
- 3.5 quorum和majority
每次一個哨兵要做主備切換,首先需要quorum數(shù)量的哨兵認(rèn)為odown,然后選舉出一個slave來做切換,這個slave還得得到majority哨兵的授權(quán),才能正式執(zhí)行切換;
如果quorum < majority,比如5個哨兵,majority就是3,quorum設(shè)置為2,那么就3個哨兵授權(quán)就可以執(zhí)行切換;
但是如果quorum >= majority,那么必須quorum數(shù)量的哨兵都授權(quán),比如5個哨兵,quorum是5,那么必須5個哨兵都同意授權(quán),才能執(zhí)行切換
- 3.6 configuration epoch
哨兵會對一套redis master+slave進行監(jiān)控,有相應(yīng)的監(jiān)控的配置,執(zhí)行切換的那個哨兵,會從要切換到的新master(salve->master)那里得到一個configuration epoch,這就是一個version號,每次切換的version號都必須是唯一的.
如果第一個選舉出的哨兵切換失敗了,那么其他哨兵,會等待failover-timeout時間,然后接替繼續(xù)執(zhí)行切換,此時會重新獲取一個新的configuration epoch,作為新的version號。
- 3.7 configuraiton傳播
哨兵完成切換之后,會在自己本地更新生成最新的master配置,然后同步給其他的哨兵,就是通過之前說的pub/sub消息機制
這里之前的version號就很重要了,因為各種消息都是通過一個channel去發(fā)布和監(jiān)聽的,所以一個哨兵完成一次新的切換之后,新的master配置是跟著新的version號的,其他的哨兵都是根據(jù)版本號的大小來更新自己的master配置的。
4. 經(jīng)典的三哨兵集群搭建
- 4.1 修改sentinel.conf配置文件如下參數(shù):
- 創(chuàng)建如下文件夾
mkdir /etc/sentinal
mkdir -p /var/sentinal/5000
- 移動配置文件位置
/etc/sentinel/5000.conf - 修改相關(guān)配置信息
綁定端口
port 5000綁定本級ip
bind 192.168.xxx.xxx
dir /var/sentinal/5000設(shè)定哨兵masterip
sentinel monitor mymaster 192.168.xxx.xxx 6379 2
sentinel down-after-milliseconds mymaster 30000
sentinel failover-timeout mymaster 60000
sentinel parallel-syncs mymaster 1 - 生產(chǎn)環(huán)境額外部署
后臺啟動
daemonize yes日志保存路徑
logfile /var/log/sentinal/5000/sentinel.log
mkdir -p /var/log/sentinal/5000
- 4.2 啟動哨兵集群,并查看相關(guān)信息
- 啟動哨兵client端
redis-cli -h 192.168.xxx.xxx -p 5000
- 查看相關(guān)信息
sentinel master mymaster
SENTINEL slaves mymaster
SENTINEL sentinels mymaster
SENTINEL get-master-addr-by-name mymaster
- 4.3 哨兵的增加刪除和slave永久下線
4.3.1 哨兵節(jié)點的增加和刪除
增加sentinal,會自動發(fā)現(xiàn);
刪除sentinal的步驟:
(1)停止sentinal進程
(2)SENTINEL RESET *,在所有sentinal上執(zhí)行,清理所有的master狀態(tài)
(3)SENTINEL MASTER mastername,在所有sentinal上執(zhí)行,查看所有sentinal對數(shù)量是否達(dá)成了一致
4.3.2 slave的永久下線
讓master摘除某個已經(jīng)下線的slave:SENTINEL RESET mastername,在所有的哨兵上面執(zhí)行.
五. redis 之集群模式
redis的集群模式為了解決系統(tǒng)的橫向擴展以及海量數(shù)據(jù)的存儲問題,如果你的數(shù)據(jù)量很大,那么就可以用redis cluster。
redis cluster可以支撐N個redis master,一個master上面可以掛載多個slave,一般情況我門掛載一個到兩個slave,master在掛掉以后會主動切換到slave上面,或者當(dāng)一個master上面的slave都掛掉后,集群會從其他master上面找到冗余的slave掛載到這個master上面,達(dá)到了系統(tǒng)的高可用性。
1. redis cluster 的hash slot 算法
redis cluster有固定的16384個hash slot,對每個key計算CRC16值,然后對16384取模,可以獲取key對應(yīng)的hash slot;
redis cluster中每個master都會持有部分slot,比如有3個master,那么可能每個master持有5000多個hash slot;
hash slot讓node的增加和移除很簡單,增加一個master,就將其他master的hash slot移動部分過去,減少一個master,就將它的hash slot移動到其他master上去,移動hash slot的成本非常低;
2. redis cluster 簡單配置
2.1 redis cluster的重要配置
cluster-enabled <yes/no>
cluster-config-file <filename>:這是指定一個文件,供cluster模式下的redis實例將集群狀態(tài)保存在那里,包括集群中其他機器的信息,比如節(jié)點的上線和下限,故障轉(zhuǎn)移,不是我們?nèi)ゾS護的,給它指定一個文件,讓redis自己去維護.
cluster-node-timeout <milliseconds>:節(jié)點存活超時時長,超過一定時長,認(rèn)為節(jié)點宕機,master宕機的話就會觸發(fā)主備切換,slave宕機就不會提供服務(wù).
2.2 在三臺機器上啟動6個redis實例
-
修改redis.conf配置文件
mkdir -p /etc/redis-cluster
mkdir -p /var/log/redis
mkdir -p /var/redis/7001port 7001
cluster-enabled yes
cluster-config-file /etc/redis-cluster/node-7001.conf
cluster-node-timeout 15000
daemonize yes
pidfile /var/run/redis_7001.pid
dir /var/redis/7001
logfile /var/log/redis/7001.log
bind 192.168.xxx.xxx
appendonly yes
將上面的配置文件,在/etc/redis下放6個,分別為: 7001.conf,7002.conf,7003.conf,7004.conf,7005.conf,7006.conf
- 準(zhǔn)備生產(chǎn)環(huán)境的啟動腳本
在/etc/init.d下,放6個啟動腳本,分別為: redis_7001, redis_7002, redis_7003, redis_7004, redis_7005, redis_7006
每個啟動腳本內(nèi),都修改對應(yīng)的端口號
- 分別在3臺機器上,啟動6個redis實例
將每個配置文件中的slaveof給刪除(不要開啟從節(jié)點配置)
2.3 創(chuàng)建集群
-
使用如下命令時報錯
yum install -y ruby
yum install -y rubygems
gem install redis
redis requires Ruby version >= 2.2.2的報錯,查了資料發(fā)現(xiàn)是Centos默認(rèn)支持ruby到2.0.0,可gem 安裝redis需要最低是2.2.2
解決辦法是 先安裝rvm,再把ruby版本提升至2.3.3
- 安裝curl(centos7 已經(jīng)安裝不用重新安裝)
sudo yum install curl
- 安裝RVM
gpg2 --keyserver hkp://keys.gnupg.net --recv-keys D39DC0E3
curl -L get.rvm.io | bash -s stable
- 查詢rvm文件所在位置,并加載rvm配置
find / -name rvm -print
source /usr/local/rvm/scripts/rvm
- 查看rvm庫中已知的ruby版本,并安裝一個ruby版本
rvm list known
rvm install 2.3.4
- 使用一個ruby版本是指為默認(rèn),移除舊版本
rvm use 2.3.4 --default
rvm remove 2.0.0
ruby --version
- 安裝redis
gem install redis
使用redis-trib.rb命令創(chuàng)建集群
cp /usr/local/sftp/redis-3.2.8/src/redis-trib.rb /usr/local/bin
redis-trib.rb create --replicas 1 192.168.199.141:7001 192.168.199.141:7002 192.168.199.142:7003 192.168.199.142:7004 192.168.199.143:7005 192.168.199.143:7006
--replicas: 表示每個master有幾個slave
redis-trib.rb check 192.168.31.187:7001 查看狀體
3. 集群模式master擴容和節(jié)點移除
3.1 加入新master
mkdir -p /var/redis/7007
port 7007
cluster-enabled yes
cluster-config-file /etc/redis-cluster/node-7007.conf
cluster-node-timeout 15000
daemonize yes
pidfile /var/run/redis_7007.pid
dir /var/redis/7007
logfile /var/log/redis/7007.log
bind 192.168.199.144
appendonly yes
以上相同配置完成后,設(shè)置啟動腳本進行啟動;然后用如下命令進行node節(jié)點添加:
redis-trib.rb add-node 192.168.199.144:7007 192.168.199.141:7001
redis-trib.rb check 192.168.199.141:7001
3.2 reshard一些數(shù)據(jù)過去
resharding的意思就是把一部分hash slot從一些node上遷移到另外一些node上
redis-trib.rb reshard 192.168.199.141:7001
3.3 添加node作為slave
進行上面的相同配置后,設(shè)定啟動腳本,執(zhí)行如下命令(其中masterid可以通過check命令進行查看):
redis-trib.rb add-node --slave --master-id 28927912ea0d59f6b790a50cf606602a5ee48108 192.168.199.144:7008 192.168.199.141:7001
3.4 刪除node
先用resharding將數(shù)據(jù)都移除到其他節(jié)點,確保node為空之后,才能執(zhí)行remove操作
redis-trib.rb del-node 192.168.199.141:7001 bd5a40a6ddccbd46a0f4a2208eb25d2453c2a8db