快取數據庫Redis

2020-08-08 12:05:49

一、Redis相關介紹

1.數據庫分類

關係型:mysql、oracle、sqlserver、db2、postgresql

非關係型:redis、mongo、ES

2.Redis的主要特性

(1)速度快
   c語言編寫
   程式碼簡潔優雅
   單執行緒架構 

(2)支援多種數據結構
   字串、雜湊、列表、集合、有序集合

(3)豐富的功能
   天然計數器
   鍵過期功能
   訊息佇列

(4)支援用戶端語言
   php、java、python

(5)數據持久化
   所有的數據都執行在記憶體中
   支援2種格式持久化數據:AOF&RDB

(6)自帶多種高可用架構
   主從
   哨兵
   叢集

3.Redis應用場景

1.快取--鍵過期時間
(1)把session對談存在redis,過期刪除;
(2)快取使用者資訊,快取Mysql部分數據,使用者先存取redis,沒有再存取mysql,然後
回寫給redis;
(3)商城優惠捲過期時間;

2.排行榜--列表&有序集合
(1)熱度/點選數排行榜
(2)直播間禮物積分排行

3.計數器-天然支援計數器
(1)貼文瀏覽數
(2)視訊播放數
(3)評論數
(4)點贊/踩

4.社羣網路-集合
(1)粉絲
(2)共同好友 
(3)興趣愛好
(4)標籤

5.訊息佇列-發佈訂閱
(1)配合ELK快取收集來的日誌

二、安裝Redis

1.準備安裝和數據目錄

[root@redis1 ~]# mkdir -p /data/soft
[root@redis1 ~]# mkdir -p /opt/redis_cluster/redis_6379/{conf,logs,pid}

2.下載redis安裝包

[root@redis1 ~]# cd /data/soft
[root@redis1 soft]# wget http://download.redis.io/releases/redis-5.0.7.tar.gz

3.解壓redis到/opt/redis_cluster/

[root@redis1 soft]# tar xf redis-5.0.7.tar.gz -C /opt/redis_cluster/
[root@redis1 soft]# ln -s /opt/redis_cluster/redis-5.0.7 /opt/redis_cluster/redis

4.切換目錄安裝redis

[root@redis1 soft]# cd /opt/redis_cluster/redis
[root@redis1 redis]# yum -y install gcc gcc-c++
[root@redis1 redis]# make && make install 

5.編寫組態檔

[root@redis1 redis]# vim /opt/redis_cluster/redis_6379/conf/6379.conf
新增:
bind 127.0.0.1 192.168.1.102
port 6379
daemonize yes
pidfile /opt/redis_cluster/redis_6379/pid/redis_6379.pid
logfile /opt/redis_cluster/redis_6379/logs/redis_6379.log
databases 16
dbfilename redis.rdb
dir /opt/redis_cluster/redis_6379

6.啓動當前redis服務

[root@redis1 redis]# redis-server /opt/redis_cluster/redis_6379/conf/6379.conf

三、Redis基本操作命令

1.全域性命令
登入Redis的命令爲

[root@redis1 redis]# redis-cli
KEYS *  #列出所有鍵值名,但在企業環境禁止使用(鍵值全部顯示過多會造成伺服器崩潰)

DBSIZE  #檢視有多少鍵值數

EXISTS  #檢視鍵值是否存在

EXPIRE k2 20  #設定K2過期時間爲20秒,20秒後k2自動取消

PERSIST k2  #取消k2的過期時間

TTL k2  #檢視k2的生命週期

TYPE  #檢視數據型別

2.字串型別:string

SET	k3 3  #建立鍵值

GET	k3  #檢視鍵值

DEL	k2  #刪除鍵值 

INCR k3  #鍵值k3爲整數,遞增加1

INCRBY k3 10  #遞增k3的量值10 

MSET k4 4 k5 5 k6 6 k7 7  #批次建立鍵值

MGET k4 k5 k6 k7  #批次檢視鍵值

3.列表:list

RPUSH list1 1 2 3 4  #建立列表list1,值爲1 2 3 4

RPUSH list1 5 6 7 8	 #在list1右側新增5 6 7 8

LPUSH list1 0  #在list1左側新增0

LRANGE list1 0  -1  #檢視list1所有值

RPOP list1  #刪除右側最後一個值

LPOP list1  #刪除左側第一個值

LTRIM list1 0 2  #僅保留前3位,其他值刪除(擷取前三位保留)

4.雜湊:hash

HMSET user:1000 username lisi age 17 job it  #建立hash鍵值user:1000 

HGET user:1000 username  #檢視鍵值中username參數

HGET user:1000 age  #檢視鍵值中age參數

HGET user:1000 job  #檢視鍵值中job參數

HMSET user:1000 tel 18866668888  #新增值tel

5.集合:set

SADD set1 1 2 3  #建立集合set1

SMEMBERS set1  #檢視集合set1

SADD set1 1 4  #爲集合set1新增值1 4 ,但集合特性是去除重複,所以1無法再新增

SREM set1 1 4  #刪除集合的值1 4

SADD set2 1 4 5  #建立第二個集合set2

SDIFF set1 set2  #求差集

SINTER set1 set2  #求合集(交集)

SUNION set1 set2  #求並集

四、Redis持久化的實現方法

1.redis持久化:

RDB:生成時間點快照,儲存於硬碟。
	優點:速度快,適合做備份,能做主從複製,單開子進程進行rdb操作不影響主業務;
	缺點:會有部分數據丟失;
		
AOF:記錄所有寫操作命令,通過再次執行這些命令還原數據。
	優點:最大程度保證數據不丟失;
	缺點:日誌記錄量太大;

2.RDB設定:

[root@redis1 redis]# vim /opt/redis_cluster/redis_6379/conf/6379.conf	
新增:
save 900 1  #在900秒(15分鐘)後至少有1個key發生變化則dump記憶體快照;
save 300 10  #在300秒(5分鐘)後至少有10個key發生變化,則dump記憶體快照;
save 60 10000  #在60秒(1分鐘)後至少有10000個key發生變化,則dump記憶體快照;
儲存退出
[root@redis1 redis]# redis-cli  #登錄redis
[root@redis1 redis]# bgsave  #rdb儲存命令

3.AOF設定:

[root@redis1 redis]# vim /opt/redis_cluster/redis_6379/conf/6379.conf
新增:
appendonly yes  #啓用AOF持久化
appendfilename "redis.aof"	 #指定AOF檔名
appendfsync everysec  #每秒同步一次

4.重新啓動redis

[root@redis1 redis]# redis-cli shutdown
[root@redis1 redis]# redis-server /opt/redis_cluster/redis_6379/conf/6379.conf
五、Redis主從伺服器的搭建

環境準備

主伺服器:192.168.229.161

從伺服器:192.168.229.167

1.redis主從複製
爲解決單點故障把數據複製到一個或多個副本伺服器(從伺服器),實現故障恢復和負載均衡。
2.開啓第二臺伺服器,安裝redis
(1)把第一臺伺服器的redis安裝目錄scp到第二臺伺服器上

[root@redis1 redis]# scp -rp /opt/redis_cluster/ [email protected]:/opt

(2)在第二臺伺服器上,make install安裝redis

[root@redis2 ~]# cd /opt/redis_cluster/redis
[root@redis2 redis]# make install
[root@redis2 redis]# vim /opt/redis_cluster/redis_6379/conf/6379.conf 
修改:
bind 127.0.0.1 192.168.229.167
末尾新增:
slaveof 192.168.229.161 6379

(3)啓動服務

[root@redis2 redis]# redis-server /opt/redis_cluster/redis_6379/conf/6379.conf

(4)主伺服器上新建鍵值,測試從伺服器自動同步
(5)從伺服器在同步過程中,只能複製主數據庫的數據,不能手動新增修改數據;
如果從伺服器非要修改數據,需要斷開同步:

[root@redis2 redis]# redis-cli slaveof no one 

如需再次連線:

[root@redis2 redis]# redis-cli slaveof 192.168.229.161 6379

如果主伺服器出現問題,則只需要把從伺服器的組態檔slaveof那一行去掉就可以變成主伺服器。

六、Redis叢集的搭建

1.redis叢集簡介
Redis Cluster是redis的分佈式解決方案,在3.0版本正式推出。
當遇到單機、記憶體、併發、流量等瓶頸時,可以採用Cluster架構方案達到負載均衡的目的。
Redis Cluster之前的分佈式方案有兩種

(1)用戶端分割區方案:
優點:分割區邏輯可控;
缺點:需要自己處理數據路由、高可用和故障轉移等。

(2)代理方案:
優點:簡化用戶端分佈式邏輯和升級維護便利;
缺點:加重架構部署和效能消耗。
官方提供的Redis Cluster叢集方案,很好的解決了叢集方面的問題。

2.數據分佈
分佈式數據庫首先要解決把整個數據庫集按照分割區規則對映到多個節點的問題,即把數據集劃分到多個節點上,每個節點負責整體數據的一個子集,需要關注的是數據分片規則,Redis Cluster採用雜湊分片規則。

3.目錄規劃

#redis安裝目錄
/opt/redis_cluster/redis_{PORT}/{conf,logs,pid}

#redis數據目錄
/data/redis_cluster/redis_{PORT}/redis_{PORT}.rdb

#redis運維指令碼
/root/scripts/redis_shell.sh

4.叢集拓撲

redis1 192.168.229.160
redis2 192.168.229.161
redis3 192.168.229.167

5.手動搭建部署叢集
思路:
先部署一臺伺服器上的2個叢集節點,
把檔案發送到其他主機修改IP地址,啓動服務。
具體操作如下
(1)redis1操作

[root@redis1 ~]# mkdir -p /opt/redis_cluster/redis_{6380,6381}/{conf,logs,pid}
[root@redis1 ~]# mkdir –p /data/redis_cluster/redis_{6380,6381}

(2)安裝redis

[root@redis1 ~]# wget http://download.redis.io/releases/redis-5.0.7.tar.gz
[root@redis1 ~]# tar xf redis-5.0.7.tar.gz -C /opt/redis_cluster/
[root@redis1 ~]# ln -s /opt/redis_cluster/redis-5.0.7 /opt/redis_cluster/redis
[root@redis1 ~]# cd /opt/redis_cluster/redis
[root@redis1 redis]# yum -y install gcc gcc-c++
[root@redis1 redis]# make && make install
[root@redis1 redis]# vim /opt/redis_cluster/redis_6380/conf/redis_6380.conf
新增:
bind 192.168.229.160
port 6380
daemonize yes
pidfile "/opt/redis_cluster/redis_6380/pid/redis_6380.pid"
logfile "/opt/redis_cluster/redis_6380/logs/redis_6380.log"
dbfilename "redis_6380.rdb"
dir "/data/redis_cluster/redis_6380/"
cluster-enabled yes
cluster-config-file nodes_6380.conf
cluster-node-timeout 15000
[root@redis1 redis]# cd /opt/redis_cluster/
[root@redis1 redis_cluster]# cp redis_6380/conf/redis_6380.conf redis_6381/conf/redis_6381.conf
[root@redis1 redis_cluster]# sed -i 's/6380/6381/g' redis_6381/conf/redis_6381.conf 
[root@redis1 redis_cluster]# redis-server /opt/redis_cluster/redis_6380/conf/redis_6380.conf
[root@redis1 redis_cluster]# redis-server /opt/redis_cluster/redis_6381/conf/redis_6381.conf

(3)複製redis1的安裝和數據目錄到redis2、redis3

[root@redis1 redis_cluster]# scp -rp /opt/redis_cluster/ [email protected]:/opt
[root@redis1 redis_cluster]# scp -rp /opt/redis_cluster/ [email protected]:/opt

(4)redis2操作:

[root@redis2 ~]# cd /opt/redis_cluster/redis
[root@redis2 redis]# make install 
[root@redis2 redis]# find /opt/redis_cluster/redis_638* -type f -name "*.conf" |xargs sed -i "s/160/161/g"
[root@redis2 redis]# mkdir –p /data/redis_cluster/redis_{6380,6381}
[root@redis2 redis]# redis-server /opt/redis_cluster/redis_6380/conf/redis_6380.conf
[root@redis2 redis]# redis-server /opt/redis_cluster/redis_6381/conf/redis_6381.conf

(5)redis3操作

[root@redis3 ~]# cd /opt/redis_cluster/redis
[root@redis3 redis]# make install
[root@redis3 redis]# find /opt/redis_cluster/redis_638* -type f -name "*.conf" |xargs sed -i 's/160/167/g'
[root@redis3 redis]# mkdir –p /data/redis_cluster/redis_{6380,6381}
[root@redis3 redis]# redis-server /opt/redis_cluster/redis_6380/conf/redis_6380.conf
[root@redis3 redis]# redis-server /opt/redis_cluster/redis_6381/conf/redis_6381.conf

6.手動設定節點發現
(1)當把所有節點都啓動後檢視進程會有cluster的字樣,但是登錄後執行CLUSTER NODES命令會發現只有每個節點自己的ID,目前叢集內的節點還沒有互相發現,所以搭建redis叢集我們第一步要做的就是讓叢集內的節點互相發現。

在執行節點發現命令之前我們先檢視一下叢集的數據目錄會發現有生成叢集的組態檔;

[root@redis1 redis_6380]# cat /data/redis_cluster/redis_6380/nodes_6380.conf
[root@redis1 redis_6380]# redis-cli -h 192.168.229.160 -p 6380
192.168.229.160:6380> cluster nodes

檢視後發現只有自己的節點內容,等節點全部發現後會把所發現的節點ID寫入這個檔案;

叢集模式的Redis除了原有的組態檔之外又加了一份叢集組態檔.當叢集內節點
資訊發生變化,如新增節點,節點下線,故障轉移等.節點會自動儲存叢集狀態到組態檔;
需要注意的是,Redis自動維護叢集組態檔,不需要手動修改,防止節點重新啓動時產生錯亂。

節點發現使用命令:

CLUSTER MEET {IP} {PORT}

提示:在叢集內任意一臺機器執行此命令就可以。
可以編寫登錄指令碼

[root@redis1 redis]# vim redis_shell.sh
#!/bin/bash

USAG(){
    echo "sh $0 {start|stop|restart|login|ps|tail} PORT"
}
if [ "$#" = 1 ]
then
    REDIS_PORT='6379'
elif 
    [ "$#" = 2 -a -z "$(echo "$2"|sed 's#[0-9]##g')" ]
then
    REDIS_PORT="$2"
else
    USAG
    exit 0
fi

REDIS_IP=$(hostname -I|awk '{print $1}')
PATH_DIR=/opt/redis_cluster/redis_${REDIS_PORT}/
PATH_CONF=/opt/redis_cluster/redis_${REDIS_PORT}/conf/redis_${REDIS_PORT}.conf
PATH_LOG=/opt/redis_cluster/redis_${REDIS_PORT}/logs/redis_${REDIS_PORT}.log

CMD_START(){
    redis-server ${PATH_CONF}
}

CMD_SHUTDOWN(){
    redis-cli -c -h ${REDIS_IP} -p ${REDIS_PORT} shutdown
}

CMD_LOGIN(){
    redis-cli -c -h ${REDIS_IP} -p ${REDIS_PORT}
}

CMD_PS(){
    ps -ef|grep redis
}

CMD_TAIL(){
    tail -f ${PATH_LOG}
}

case $1 in
    start)
        CMD_START
        CMD_PS
        ;;
    stop)
        CMD_SHUTDOWN
        CMD_PS
        ;;
    restart)
        CMD_START
        CMD_SHUTDOWN
        CMD_PS
        ;;
    login)
        CMD_LOGIN
        ;;
    ps)
        CMD_PS
        ;;
    tail)
        CMD_TAIL
        ;;
    *)
        USAG
esac
[root@redis1 redis]# chmod +x redis_shell.sh
[root@redis1 redis]# sh redis_shell.sh login 6380
192.168.1.102:6380> CLUSTER MEET 192.168.229.160 6381
OK
192.168.1.102:6380> CLUSTER MEET 192.168.229.161 6380
OK
192.168.1.102:6380> CLUSTER MEET 192.168.229.167 6380
OK
192.168.1.102:6380> CLUSTER MEET 192.168.229.161 6381
OK
192.168.1.102:6380> CLUSTER MEET 192.168.229.167 6381
OK
192.168.229.160:6380> CLUSTER NODES
098d20bfacb5c8d926aa46455fe11942de083643 192.168.229.161:6380@16380 master - 0 1595914581766 2 connected
38d0a92b60d00ab1ce1149d32aaef0fbb29bb6ab 192.168.229.167:6380@16380 master - 0 1595914579000 5 connected
391ddc472dfed2cc65846f9ef55ddc14a9f02e88 192.168.229.167:6381@16381 master - 0 1595914579742 4 connected
c23e23467e6e45d3bd783f0bbbf784252292400e 192.168.229.161:6381@16381 master - 0 1595914580000 3 connected
cb94deff8ec6d686172f012e064ab98c9f0edfc3 192.168.229.160:6380@16380 myself,master - 0 1595914581000 0 connected
7eb1d0435165f2657a722022887fd1c453c36d3d 192.168.229.160:6381@16381 master - 0 1595914580753 1 connected

節點都發現完畢後我們再次檢視叢集組態檔;
可以看到,發現到的節點的ID也被寫入到了叢集的組態檔裡。
(2)Redis Cluster通訊流程
在分佈式儲存中需要提供維護節點元數據資訊的機制 機製,所謂元數據是指:節點負責哪些數據,是否出現故障燈狀態資訊,redis叢集採用Gossip(流言)協定,Gossip協定工作原理就是節點彼此不斷交換資訊,一段時間後所有的節點都會知道叢集完整資訊,這種方式類似流言傳播。
通訊過程

1.叢集中的每一個節點都會單獨開闢一個tcp通道,用於節點之間彼此通訊,防火牆放行(埠號+10000);

2.每個節點在固定週期內通過特定規則選擇結構節點發送ping訊息;

3.接收到ping訊息的節點用pong訊息作爲響應。叢集中每個節點通過一定規則挑選要通訊的節點,每個節點可能知道全部節點,也可能僅知道部分節點,只要這些節點彼此可以正常通訊,最終他們會打成一致的狀態,當節點出現故障,新節點加入,主從角色變化等,它能夠給不斷的ping/pong訊息,從而達到同步目的。

通訊訊息型別

Gossip
	Gossip協定職責就是資訊交換,資訊交換的載體就是節點間彼此發送Gossip訊息;
常見Gossip訊息分爲:ping、pong、meet、fail等;

meet
	meet訊息:用於通知新節點加入,訊息發送者通知接受者加入到當前叢集,meet訊息通訊正常完成後,接收節點會加入到叢集中並進行ping、pong訊息交換;

ping
	ping訊息:叢集內交換最頻繁的訊息,叢集內每個節點每秒想多個其他節點發送ping訊息,用於檢測節點是否線上和交換彼此資訊;

pong
	Pong訊息:當接收到ping、meet訊息時,作爲相應訊息回覆 回復給發送方確認訊息正常通訊,節點也可以向叢集內廣播自身的pong訊息來通知整個叢集對自身狀態進行更新;

fail
	fail訊息:當節點判定叢集內另一個節點下線時,迴向叢集內廣播一個fail訊息,其他節點收到fail訊息之後把對應節點更新爲下線狀態;

(3)Redis Cluster手動分配槽位
雖然節點之間已經互相發現了,但是此時叢集還是不可用的狀態,因爲並沒有給節點分配槽位,而且必須是所有的槽位都分配完畢後整個叢集纔是可用的狀態.反之,也就是說只要有一個槽位沒有分配,那麼整個叢集就是不可用的.
測試命令

[root@redis1 redis]# sh redis_shell.sh login 6380
192.168.229.160:6380> set k1 1
(error) CLUSTERDOWN Hash slot not served
192.168.229.160:6380> cluster info
cluster_state:fail
cluster_slots_assigned:0
cluster_slots_ok:0
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:0
cluster_current_epoch:5
cluster_my_epoch:0
cluster_stats_messages_ping_sent:940
cluster_stats_messages_pong_sent:969
cluster_stats_messages_meet_sent:5
cluster_stats_messages_sent:1914
cluster_stats_messages_ping_received:969
cluster_stats_messages_pong_received:945
cluster_stats_messages_received:1914

前面說了,我們雖然有6個節點,但是真正負責數據寫入的只有3個節點,其他3個節點只是作爲主節點的從節點,也就是說,只需要分配期中三個節點的槽位就可以了。
分配槽位的方法:
分配槽位需要在每個主節點上來設定,此時有2種方法執行:
分別登錄到每個主節點的用戶端來執行命令
在其中一臺機器上用redis用戶端遠程登錄到其他機器的主節點上執行命令
每個節點執行命令:

[root@redis1 redis]# redis-cli -h 192.168.229.160 -p 6380 cluster addslots {0..5461}
OK
[root@redis1 redis]# redis-cli -h 192.168.229.161 -p 6380 cluster addslots {5462..10922}
OK
[root@redis1 redis]# redis-cli -h 192.168.229.167 -p 6380 cluster addslots {10923..16383}
OK

分配完所有槽位之後我們再檢視一下叢集的節點狀態和叢集狀態,可以看到三個節點都分配了槽位,而且叢集的狀態是OK的。
(4)手動設定叢集高可用
雖然這時候叢集是可用的了,但是整個叢集只要有一臺機器壞掉了,那麼整個叢集都是不可用了,所以這時候需要用到其他三個節點分別作爲現在三個主節點的從節點,以應對叢集主節點故障時可以進行自動切換以保證叢集持續可用。
注意:

1.不要讓複製節點複製本機器的主節點, 因爲如果那樣的話機器掛了叢集還是不可用狀態, 所以複製節點要複製其他伺服器的主節點。

2.使用redis-trid工具自動分配的時候會出現複製節點和主節點在同一臺機器上的情況,需要注意。

(5)測試叢集
這一次我們採用在一臺機器上使用redis用戶端遠端操作叢集其他節點
注意:

1.需要執行命令的是每個伺服器的從節點

2.注意主從的ID不要搞混了

執行命令

[root@redis1 redis]# redis-cli -h 192.168.229.160 -p 6381 cluster replicate 098d20bfacb5c8d926aa46455fe11942de083643  (第二臺Redis的6380ID)
OK
[root@redis1 redis]# redis-cli -h 192.168.229.161 -p 6381 cluster replicate 38d0a92b60d00ab1ce1149d32aaef0fbb29bb6ab  (第三臺Redis的6380ID)
OK
[root@redis1 redis]# redis-cli -h 192.168.229.167 -p 6381 cluster replicate cb94deff8ec6d686172f012e064ab98c9f0edfc3  (第一臺Redis的6380ID)
OK

(6)Redis Cluster測試叢集
我們使用常規插入redis數據的方式往叢集裡寫入數據看看會發生什麼

[root@redis1 redis]# redis-cli -h 192.168.229.160 -p 6380 set k1 1
(error) MOVED 12706 192.168.229.167:6380

結果提示error, 但是給出了叢集另一個節點的地址
那麼這條數據到底有沒有寫入呢? 我們登錄這兩個節點分別檢視

[root@redis1 redis]# redis-cli -h 192.168.229.167 -p 6380 get k1
(nil)

結果沒有,這是因爲使用集羣後由於數據被分片了,所以並不是說在那臺機器上寫入數據就會在哪臺機器的節點上寫入,叢集的數據寫入和讀取就涉及到了另外一個概念,ASK路由。
(7)Redis Cluster ASK路由介紹
在叢集模式下,Redis接受任何鍵相關命令時首先會計算鍵對應的槽,再根據槽找出所對應的節點,如果節點是自身,則處理鍵命令;否則回覆 回復MOVED重定向錯誤,通知用戶端請求正確的節點,這個過程稱爲Mover重定向。
知道了ask路由後,我們使用-c選項批次插入一些數據

[root@redis1 redis]# vim input_key.sh 
#!/bin/bash
for i in $(seq 1 1000)
do
    redis-cli -c -h 192.168.229.160 -p 6380 set k_${i} v_${i} && echo "set k_${i} is ok"
done

寫入後我們同樣使用-c選項來讀取剛纔插入的鍵值,然後檢視下redis會不會幫我們路由到正確的節點上。

[root@redis1 redis]# redis-cli -c -h 192.168.229.160 -p 6380
192.168.229.160:6380> get k_1
"v_1"
192.168.229.160:6380> get k_100
-> Redirected to slot [5541] located at 192.168.229.161:6380
"v_100"

(8)模擬故障轉移
至此,我們已經手動的把一個redis高可用的叢集部署完畢了, 但是還沒有模擬過故障
這裏我們就模擬故障,停掉期中一臺主機的redis節點,然後檢視一下叢集的變化,我們使用暴力的kill -9(真實環境禁止使用,建議使用kill或pkill)殺掉,redis2上的redis叢集節點,然後觀察節點狀態;理想情況應該是redis1上的6381從節點升級爲主節點,在redis1上檢視叢集節點狀態。
雖然我們已經測試了故障切換的功能,但是節點修復後還是需要重新上線,所以這裏測試節點重新上線後的操作,重新啓動redis2的6380,然後觀察日誌。
觀察redis1上的日誌,這時假如我們想讓修復後的節點重新上線,可以在想變成主庫的從庫執行CLUSTER FAILOVER命令,這裏我們在redis2的6380上執行。
操作命令
中止redis2的服務:

[root@redis2 redis]# pkill redis-server

檢視日誌:

[root@redis1 redis]# sh redis_shell.sh tail 6380

再啓動redis2的服務

[root@redis2 redis]# redis-server /opt/redis_cluster/redis_6380/conf/redis_6380.conf
[root@redis2 redis]# redis-server /opt/redis_cluster/redis_6381/conf/redis_6381.conf

redis2重回master:

[root@redis2 redis]# redis-cli -h 192.168.229.161 -p 6380 CLUSTER FAILOVER

7.使用工具自動搭建部署Redis Cluster
手動搭建叢集便於理解叢集建立的流程和細節,不過手動搭建叢集需要很多步驟,當叢集節點衆多時,必然會加大搭建叢集的複雜度和運維成本,因此官方提供了redis-trib.rb的工具方便我們快速搭建叢集。redis-trib.rb是採用Ruby實現的redis叢集管理工具,內部通過Cluster相關命令幫我們簡化叢集建立、檢查、槽遷移和均衡等常見運維操作,使用前要安裝ruby依賴環境。
前提準備
停掉所有的節點,然後清空數據,恢復成一個全新的叢集,所有機器執行命令:

[root@redis1 redis]# pkill redis
[root@redis1 redis]# rm -rf /data/redis_cluster/redis_6380/*
[root@redis1 redis]# rm -rf /data/redis_cluster/redis_6381/*

全部清空之後啓動所有的節點,所有機器執行:

[root@redis1 redis]# redis-server /opt/redis_cluster/redis_6380/conf/redis_6380.conf
[root@redis1 redis]# redis-server /opt/redis_cluster/redis_6381/conf/redis_6381.conf

(1)安裝命令:注意新版本redis不需安裝,直接採用步驟(2)

yum makecache fast
yum install rubygems
gem sources --remove https://rubygems.org/
gem sources -a http://mirrors.aliyun.com/rubygems/
gem update –system
gem install redis -v 3.3.5

redis1執行建立叢集命令

cd /opt/redis_cluster/redis/src/
./redis-trib.rb create --replicas 1 192.168.229.160:6380 192.168.229.161:6380 192.168.229.167:6380 192.168.229.160:6381 192.168.229.161:6381 192.168.229.167:6381

檢查叢集完整性

./redis-trib.rb check 192.168.229.160:6380

(2)或直接使用redis-cli命令***
建立羣集選擇yes進行建立

[root@redis1 redis]# redis-cli --cluster create --cluster-replicas 1 192.168.229.160:6380 192.168.229.161:6380 192.168.229.167:6380 192.168.229.160:6381 192.168.229.161:6381 192.168.229.167:6381

檢查完整性:

[root@redis1 redis]# redis-cli --cluster check 192.168.229.160:6380

8.工具擴容節點
Redis叢集的擴容操作可分爲以下幾個步驟

1)準備新節點

2)加入叢集

3)遷移槽和數據

擴容流程
我們在redis1上建立2個新節點;

[root@redis1 redis]# mkdir -p /opt/redis_cluster/redis_{6390,6391}/{conf,logs,pid}
[root@redis1 redis]# mkdir -p /data/redis_cluster/redis_{6390,6391}
[root@redis1 redis]# cd /opt/redis_cluster/
[root@redis1 redis_cluster]# cp redis_6380/conf/redis_6380.conf redis_6390/conf/redis_6390.conf
[root@redis1 redis_cluster]# cp redis_6380/conf/redis_6380.conf redis_6391/conf/redis_6391.conf
[root@redis1 redis_cluster]# sed -i 's/6380/6390/g' redis_6390/conf/redis_6390.conf
[root@redis1 redis_cluster]# sed -i 's/6380/6391/g' redis_6391/conf/redis_6391.conf

啓動節點

[root@redis1 redis]# bash redis_shell.sh start 6390
[root@redis1 redis]# bash redis_shell.sh start 6391

發現節點

[root@redis1 redis]# redis-cli -c -h 192.168.229.160 -p 6380 cluster meet 192.168.229.160 6390
OK
[root@redis1 redis]# redis-cli -c -h 192.168.229.160 -p 6380 cluster meet 192.168.229.160 6391
OK

在redis1上使用工具擴容;注意新版本使用步驟(2)
(1)舊版本3…
cd /opt/redis_cluster/redis/src/
./redis-trib.rb add-node 192.168.229.160:6390 192.168.229.160:6380
./redis-trib.rb add-node 192.168.229.160:6391 192.168.229.160:6380
./redis-trib.rb reshard 192.168.229.160:6380

(2)直接使用redis-cli命令完成

[root@redis1 redis]# redis-cli --cluster add-node 192.168.229.160:6390 192.168.229.160:6380
[root@redis1 redis]# redis-cli --cluster add-node 192.168.229.160:6391 192.168.229.160:6380
[root@redis1 redis]# redis-cli --cluster reshard 192.168.229.160:6380

列印出進羣每個節點資訊後,reshard命令需要確認遷移的槽數量,這裏我們輸入4096個:
How many slots do you want to move (from 1 to 16384)? 4096
輸入6390的節點ID作爲目標節點,也就是要擴容的節點,目標節點只能指定一個
What is the receiving node ID? 6390的ID號
之後輸入源節點的ID,這裏分別輸入每個主節點的6380的ID最後輸入done,或者直接輸入all
Source node #1:all
遷移完成後命令會自動退出,這時候我們檢視一下叢集的狀態

舊版本
[root@redis1 redis]# ./redis-trib.rb rebalance 192.168.229.160:6380

新版本
[root@redis1 redis]# redis-cli --cluster rebalance 192.168.229.160:6380

9.工具收縮節點
流程說明

1)首先需要確定下線節點是否有負責的槽;如果是,需要把槽遷移到其他節點,保證節點下線後整個叢集槽節點對映的完整性.

2)當下線節點不再負責槽或者本身是從節點時,就可以通知叢集內其他節點忘記下線節點,當所有的節點忘記該節點後可以正常關閉.

這裏我們準備將剛纔新新增的節點下線,也就是6390和6391
收縮和擴容遷移的方向相反,6390變爲源節點,其他節點變爲目標節點,源節點把自己負責的4096個槽均勻的遷移到其他節點上;由於redis-trib.rb reshard命令只能有一個目標節點,因此需要執行3次reshard命令,分別遷移1365,1365,1366個槽。
操作命令

[root@redis1 redis]# cd /opt/redis_cluster/redis/src/
[root@redis1 src]# ./redis-trib.rb reshard 192.168.229.160:6380
How many slots do you want to move (from 1 to 16384)? 1365
輸入6380的id
輸入6390的id
done

忘記節點
由於我們的叢集是做了高可用的,所以當主節點下線的時候從節點也會頂上,所以最好我們先下線從節點,然後在下線主節點;

[root@redis1 redis]# cd /opt/redis_cluster/redis/src/
[root@redis1 src]# ./redis-trib.rb del-node 192.168.229.160:6391 ID
[root@redis1 src]# ./redis-trib.rb del-node 192.168.229.160:6390 ID

10.Redis叢集常用命令

叢集(cluster)
CLUSTER INFO 列印叢集的資訊
CLUSTER NODES 列出叢集當前已知的所有節點(node),以及這些節點的相關資訊。 

節點(node)
CLUSTER MEET <ip> <port> 將ip和port所指定的節點新增到叢集當中,讓它成爲叢集的一份子。
CLUSTER FORGET <node_id> 從叢集中移除node_id指定的節點。
CLUSTER REPLICATE <node_id> 將當前節點設定爲node_id指定的節點的從節點。
CLUSTER SAVECONFIG 將節點的組態檔儲存到硬盤裏面。

槽(slot)
CLUSTER ADDSLOTS <slot> [slot ...] 將一個或多個槽(slot)指派(assign)給當前節點。
CLUSTER DELSLOTS <slot> [slot ...] 移除一個或多個槽對當前節點的指派。
CLUSTER FLUSHSLOTS 移除指派給當前節點的所有槽,讓當前節點變成一個沒有指派任何槽的節點。
CLUSTER SETSLOT <slot> NODE <node_id> 將槽slot指派給node_id指定的節點,如果槽已經指派給另一個節點,那麼先讓另一個節點刪除該槽,然後再進行指派。
CLUSTER SETSLOT <slot> MIGRATING <node_id> 將本節點的槽slot遷移到node_id指定的節點中。
CLUSTER SETSLOT <slot> IMPORTING <node_id> 從node_id指定的節點中匯入槽slot到本節點。
CLUSTER SETSLOT <slot> STABLE 取消對槽slot的匯入(import)或者遷移(migrate)。

鍵 (key)
CLUSTER KEYSLOT <key> 計算鍵key應該被放置在哪個槽上。
CLUSTER COUNTKEYSINSLOT <slot> 返回槽slot目前包含的鍵值對數量。CLUSTER GETKEYSINSLOT <slot> <count> 返回count個slot槽中的鍵。

11.Redis運維工具
(1)運維指令碼

[root@redis1 ~]# cat redis_shell.sh 
#!/bin/bash

USAG(){
    echo "sh $0 {start|stop|restart|login|ps|tail} PORT"
}
if [ "$#" = 1 ]
then
    REDIS_PORT='6379'
elif 
    [ "$#" = 2 -a -z "$(echo "$2"|sed 's#[0-9]##g')" ]
then
    REDIS_PORT="$2"
else
    USAG
    exit 0
fi

REDIS_IP=$(hostname -I|awk '{print $1}')
PATH_DIR=/opt/redis_cluster/redis_${REDIS_PORT}/
PATH_CONF=/opt/redis_cluster/redis_${REDIS_PORT}/conf/redis_${REDIS_PORT}.conf
PATH_LOG=/opt/redis_cluster/redis_${REDIS_PORT}/logs/redis_${REDIS_PORT}.log

CMD_START(){
    redis-server ${PATH_CONF}
}

CMD_SHUTDOWN(){
    redis-cli -c -h ${REDIS_IP} -p ${REDIS_PORT} shutdown
}

CMD_LOGIN(){
    redis-cli -c -h ${REDIS_IP} -p ${REDIS_PORT}
}

CMD_PS(){
    ps -ef|grep redis
}

CMD_TAIL(){
    tail -f ${PATH_LOG}
}

case $1 in
    start)
        CMD_START
        CMD_PS
        ;;
    stop)
        CMD_SHUTDOWN
        CMD_PS
        ;;
    restart)
        CMD_START
        CMD_SHUTDOWN
        CMD_PS
        ;;
    login)
        CMD_LOGIN
        ;;
    ps)
        CMD_PS
        ;;
    tail)
        CMD_TAIL
        ;;
    *)
        USAG
esac

(2)數據匯入導出工具
需求背景
剛切換到redis叢集的時候肯定會面臨數據匯入的問題,所以這裏推薦使用redis-migrate-tool工具來匯入單節點數據到叢集裡;
官方地址:http://www.oschina.net/p/redis-migrate-tool
安裝工具

[root@redis1 ~]# cd /opt/redis_cluster/
[root@redis1 redis_cluster]# yum -y install git
[root@redis1 redis_cluster]# git clone https://github.com/vipshop/redis-migrate-tool.git
[root@redis1 redis_cluster]# cd redis-migrate-tool/
[root@redis1 redis-migrate-tool]# yum -y install install autoconf automake libtool
[root@redis1 redis-migrate-tool]# autoreconf -fvi
[root@redis1 redis-migrate-tool]# ./configure
[root@redis1 redis-migrate-tool]# make && make install 

建立組態檔

[root@redis1 redis-migrate-tool]# vim redis_6380_to_6381.conf    
[source]
type: single
servers:
- 192.168.229.160:6380
 
[target]
type: redis cluster
servers:
- 192.168.229.160:6381 
 
[common]
listen: 0.0.0.0:8888
source_safe: true

生成測試數據

[root@redis1 ~]# cat input_key.sh 
#!/bin/bash
for i in $(seq 1 1000)
do
    redis-cli -c -h 192.168.229.160 -p 6380 set k_${i} v_${i} && echo "set k_${i} is ok"
done

執行匯入命令

[root@redis1 ~]# redis-migrate-tool -c redis_6380_to_6381.conf 

數據校驗

[root@redis1 ~]# redis-migrate-tool -c redis_6380_to_6381.conf -C redis_check

(3)分析鍵值大小
需求背景
redis的記憶體使用太大鍵值太多,不知道哪些鍵值佔用的容量比較大,而且線上分析會影響效能。
安裝工具

[root@redis1 ~]# yum install python-pip gcc python-devel 
[root@redis1 ~]# cd /opt/
[root@redis1 opt]# git clone https://github.com/sripathikrishnan/redis-rdb-tools
[root@redis1 opt]# cd redis-rdb-tools
[root@redis1 redis-rdb-tools]# python setup.py install

使用方法

[root@redis1 redis-rdb-tools]# cd /data/redis_cluster/redis_6380/
[root@redis1 redis_6380]# rdb -c memory redis_6380.rdb -f redis_6380.rdb.csv

分析rdb並導出

[root@redis1 redis_6380]# awk -F ',' '{print $4,$2,$3,$1}' redis_6380.rdb.csv |sort > 6380.txt

(4)監控過期鍵
需求背景
因爲開發重複提交,導致電商網站優惠捲過期時間失效
問題分析
如果一個鍵已經設定了過期時間,這時候在set這個鍵,過期時間就會取消
解決思路
如何在不影響機器效能的前提下批次獲取需要監控鍵過期時間

1.Keys * 查出來匹配的鍵名。然後回圈讀取ttl時間

2.scan * 範圍查詢鍵名。然後回圈讀取ttl時間

Keys 重操作,會影響伺服器效能,除非是不提供服務的從節點
Scan 負擔小,但是需要去多次才能 纔能取完,需要寫指令碼

指令碼內容:

[root@redis1 redis_6380]# vim 01get_key.sh 
#!/bin/bash
key_num=0
> key_name.log
for line in $(cat key_list.txt)
do
    while true
    do
        scan_num=$(redis-cli -h 192.168.229.160 -p 6380 SCAN ${key_num} match ${line}\* count 1000|awk 'NR==1{print $0}')
        key_name=$(redis-cli -h 192.168.229.160 -p 6380 SCAN ${key_num} match ${line}\* count 1000|awk 'NR>1{print $0}')
        echo ${key_name}|xargs -n 1 >> key_name.log
        ((key_num=scan_num))
        if [ ${key_num} == 0 ]
           then
           break
        fi
    done
done