一、快取穿透
快取穿透是指查詢一個資料庫一定不存在的資料。
我們以前正常的使用Redis快取的流程大致是:
1、資料查詢首先進行快取查詢
2、如果資料存在則直接返回快取資料
3、如果資料不存在,就對資料庫進行查詢,並把查詢到的資料放進快取
4、如果資料庫查詢資料為空,則不放進快取
例如我們的資料表中主鍵是自增產生的,所有的主鍵值都大於0。此時如果使用者傳入的引數為-1,會是 怎麼樣?這個-1,就是一定不存在的物件。程式就會每次都去查詢資料庫,而每次查詢都是空,每次又 都不會進行快取。假如有人惡意攻擊,就可以利用這個漏洞,對資料庫造成壓力,甚至壓垮我們的資料 庫。
為了防止有人利用這個漏洞惡意攻擊我們的資料庫,我們可以採取如下措施:
如果從資料庫查詢的物件為空,也放入快取,key為使用者提交過來的主鍵值,value為null,只是設定的 快取過期時間較短,比如設定為60秒。這樣下次使用者再根據這個key查詢redis快取就可以查詢到值了 (當然值為null),從而保護我們的資料庫免遭攻擊。
二、快取雪崩
快取雪崩,是指在某一個時間段,快取集中過期失效。在快取集中失效的這個時間段對資料的訪問查 詢,都落到了資料庫上,對於資料庫而言,就會產生週期性的壓力波峰。
為了避免快取雪崩的發生,我們可以將快取的資料設定不同的失效時間,這樣就可以避免快取資料在某 個時間段集中失效。例如對於熱門的資料(訪問頻率高的資料)可以快取的時間長一些,對於冷門的數 據可以快取的時間段一些。甚至對於一些特別熱門的資料可以設定永不過期。
三、快取擊穿
快取擊穿,是指一個key非常熱點(例如雙十一期間進行搶購的商品資料),在不停的扛著大併發,大 併發集中對這一個點進行訪問,當這個key在失效的瞬間,持續的大併發就穿破快取,直接請求到資料 庫上,就像在一個屏障上鑿開了一個洞。
我們同樣可以將這些熱點資料設定永不過期就可以解決快取擊穿的問題了。
四、Redis叢集方案
單機Redis的讀寫速度非常快,能夠支援大量使用者的訪問。雖然Redis的效能很高,但是對於大型網站來 說,每秒需要獲取的資料遠遠超過單臺redis服務所能承受的壓力,所以我們迫切需要一種方案能夠解決單臺Redis服務效能不足的問題。這就需要使用到Redis的叢集了。Redis叢集有多種方案,下面分別進行講解。
1、主從複製Replication
redis支援主從複製的模式。
在主從複製模式下Redis節點分為兩種角色:主節點(也稱為master)和從節點(也稱為slave)。這種模式 叢集是由一個主節點和多個從節點構成。
原則:Master會將資料同步到slave,而slave不會將資料同步到master。Slave啟動時會連線master來 同步資料。
這是一個典型的分散式讀寫分離模型。我們可以利用master來處理寫操作,slave提供讀操作。這樣可 以有效減少單個機器的併發訪問數量。
2、哨兵sentinel
我們現在已經給Redis實現了主從複製,可將主節點資料同步給從節點,實現了讀寫分離,提高Redis的效能。但是現在還存在一個問題,就是在主從複製這種模式下只有一個主節點,一旦主節點當機,就無法再進行寫操作了。也就是說主從複製這種模式沒有實現高可用。那麼什麼是高可用呢?如何實現高可用呢?
a. 高可用介紹
高可用(HA)是分散式系統架構設計中必須考慮的因素之一,它是透過架構設計減少系統不能提供服務的時間。保證高可用通常遵循下面幾點:
注意:可能有些同學會有疑問,現在我們已經基於sentinel實現了高可用,但是如果sentinel掛了怎麼辦呢?其實sentinel本身也可以實現叢集,也就是說sentinel也是高可用的。
c. Redis sentinel使用
1.配置sentinel
cd /usr/local/redis/ # 複製sentinel配置檔案 cp /root/redis-4.0.14/sentinel.conf sentinel01.conf # 修改配置檔案: vi sentinel01.conf
在sentinel01.conf配置檔案中新增:
# 外部可以訪問 bind 0.0.0.0 sentinel monitor mymaster 127.0.0.1 6379 1 sentinel down-after-milliseconds mymaster 10000 sentinel failover-timeout mymaster 60000 sentinel parallel-syncs mymaster 1
注意:如果有sentinel monitor mymaster 127.0.0.1 6379 2配置,則註釋掉。
引數說明:
sentinel monitor mymaster 192.168.200.129 6379 1
mymaster 主節點名,可以任意起名,但必須和後面的配置保持一致。
192.168.200.128 6379 主節點連線地址。
1 將主伺服器判斷為失效需要投票,這裡設定至少需要 1個 Sentinel 同意。
sentinel down-after-milliseconds mymaster 10000
設定Sentinel認為伺服器已經斷線所需的毫秒數。
sentinel failover-timeout mymaster 60000
設定failover(故障轉移)的過期時間。當failover開始後,在此時間內仍然沒有觸發任何failover 操作,當前 sentinel 會認為此次failover失敗。
sentinel parallel-syncs mymaster 1
設定在執行故障轉移時, 最多可以有多少個從伺服器同時對新的主伺服器進行同步, 這個數字越 小,表示同時進行同步的從伺服器越少,那麼完成故障轉移所需的時間就越長。
2. 啟動sentinel
配置檔案修改後,執行以下命令,啟動sentinel:
/root/redis-4.0.14/src/redis-sentinel sentinel01.conf
效果如下:
可以看到,6379是主服務,6380和6381是從服務。
3. 測試sentinel
我們在6379執行shutdown,關閉主服務,Sentinel提示如下:
+sdown master mymaster 192.168.200.129 6379 #主節點當機 +odown master mymaster 192.168.200.129 6379 #quorum 1/1 +new-epoch 1 +try-failover master mymaster 192.168.200.129 6379 #嘗試故障轉移 +vote-for-leader 00a6933e0cfa2b1bf0c3aab0d6b7a1a6455832ec 1 #選舉領導 +elected-leader master mymaster 192.168.200.129 6379 +failover-state-select-slave master mymaster 192.168.200.129 6379 #故障轉移選擇從服務 +selected-slave slave 192.168.200.129:6380 192.168.200.129 6380 @ mymaster 192.168.200.129 6379 #故障轉移狀態傳送 傳送到6380 +failover-state-send-slaveof-noone slave 192.168.200.129:6380 192.168.200.129 6380 @ mymaster 192.168.200.129 6379 +failover-state-wait-promotion slave 192.168.200.129:6380 192.168.200.129 6380 @ mymaster 192.168.200.129 6379 +promoted-slave slave 192.168.200.129:6380 192.168.200.129 6380 @ mymaster 192.168.200.129 6379 +failover-state-reconf-slaves master mymaster 192.168.200.129 6379 +slave-reconf-sent slave 192.168.200.129:6381 192.168.200.129 6381 @ mymaster 192.168.200.129 6379 +slave-reconf-inprog slave 192.168.200.129:6381 192.168.200.129 6381 @ mymaster 192.168.200.129 6379 +slave-reconf-done slave 192.168.200.129:6381 192.168.200.129 6381 @ mymaster 192.168.200.129 6379 +failover-end master mymaster 192.168.200.129 6379 #故障轉移結束,原來的主服務是6379 +switch-master mymaster 192.168.200.129 6379 192.168.200.129 6380 #轉換主服務,由原 來的6379轉為現在的6380 +slave slave 192.168.200.129:6381 192.168.200.129 6381 @ mymaster 192.168.200.129 6380 +slave slave 192.168.200.129:6379 192.168.200.129 6379 @ mymaster 192.168.200.129 6380 +sdown slave 192.168.200.129:6379 192.168.200.129 6379 @ mymaster 192.168.200.129 6380
根據提示資訊,我們可以看到,6379故障轉移到了6380,透過投票選擇6380為新的主伺服器。
在6380執行info
# Replication role:master connected_slaves:1 slave0:ip=127.0.0.1,port=6381,state=online,offset=80531,lag=1
在6381執行info
# Replication role:slave master_host:127.0.0.1 master_port:6380 master_link_status:up
故障轉移如下圖:
3、Redis內建叢集cluster
a. Redis cluster介紹
Redis Cluster是Redis的內建叢集,在Redis3.0推出的實現方案。在Redis3.0之前是沒有這個內建叢集的。Redis Cluster是無中心節點的叢集架構,依靠Gossip協議協同自動化修復叢集的狀態。
Redis cluster在設計的時候,就考慮到了去中心化,去中介軟體,也就是說,叢集中的每個節點都是平等 的關係,都是對等的,每個節點都儲存各自的資料和整個叢集的狀態。每個節點都和其他所有節點連 接,而且這些連線保持活躍,這樣就保證了我們只需要連線叢集中的任意一個節點,就可以獲取到其他 節點的資料。
Redis cluster叢集架構圖如下:
b.雜湊槽方式分配資料
需要注意的是,這種叢集模式下叢集中每個節點儲存的資料並不是所有的資料,而只是一部分資料。那 麼資料是如何合理的分配到不同的節點上的呢?
Redis 叢集是採用一種叫做 雜湊槽 (hash slot) 的方式來分配資料的。redis cluster 預設分配了 16384 個slot,當我們set一個key 時,會用 CRC16 演算法來取模得到所屬的 slot ,然後將這個key 分到 雜湊槽區間的節點上,具體演算法就是: CRC16(key) % 16384 。
假設現在有3個節點已經組成了叢集,分別是:A, B, C 三個節點,它們可以是一臺機器上的三個埠, 也可以是三臺不同的伺服器。那麼,採用 雜湊槽 (hash slot) 的方式來分配16384個slot 的話,它們 三個節點分別承擔的slot 區間是:
節點A覆蓋0-5460 節點B覆蓋5461-10922 節點C覆蓋10923-16383
那麼,現在要設定一個key ,比如叫 my_name :
set my_name itcast
按照redis cluster的雜湊槽演算法: CRC16('my_name')%16384 = 2412 。 那麼就會把這個key 的儲存分 配到 節點A 上了。
c. Redis cluster的主從模式
redis cluster 為了保證資料的高可用性,加入了主從模式,一個主節點對應一個或多個從節點,主節點 提供資料存取,從節點則是從主節點拉取資料備份,當這個主節點掛掉後,就會在這些從節點中選取一 個來充當主節點,從而保證叢集不會掛掉。
redis cluster加入了主從模式後的效果如下:
d. Redis cluster搭建
1. 準備Redis節點
為了保證可以進行投票,需要至少3個主節點。
每個主節點都需要至少一個從節點,所以需要至少3個從節點。
一共需要6臺redis伺服器,我們這裡使用6個redis例項,埠號為7001~7006。
先準備一個乾淨的redis環境,複製原來的bin資料夾,清理後作為第一個redis節點,具體命令如下:
# 進入redis安裝目錄 cd /usr/local/redis # 複製redis mkdir cluster cp -R bin/ cluster/node1 # 刪除持久化檔案 cd cluster/node1 rm -rf dump.rdb rm -rf appendonly.aof # 刪除原來的配置檔案 rm -rf redis.conf # 複製新的配置檔案 cp /root/redis-4.0.14/redis.conf ./ # 修改配置檔案 vi redis.conf
叢集環境redis節點的配置檔案如下:
# 不能設定密碼,否則叢集啟動時會連線不上 # Redis伺服器可以跨網路訪問 bind 0.0.0.0 # 修改埠號 port 7001 # Redis後臺啟動 daemonize yes # 開啟aof持久化 appendonly yes # 開啟叢集 cluster-enabled yes # 叢集的配置 配置檔案首次啟動自動生成 cluster-config-file nodes.conf # 請求超時 cluster-node-timeout 5000
第一個redis節點node1準備好之後,再分別複製5份,
cp -R node1/ node2
修改六個節點的埠號為7001~7006,修改redis.conf配置檔案即可
編寫啟動節點的指令碼:
vi start-all.sh
內容為:
cd node1 ./redis-server redis.conf cd .. cd node2 ./redis-server redis.conf cd .. cd node3 ./redis-server redis.conf cd .. cd node4 ./redis-server redis.conf cd .. cd node5 ./redis-server redis.conf cd .. cd node6 ./redis-server redis.conf cd ..
設定指令碼的許可權,並啟動:
chmod 744 start-all.sh ./start-all.sh
使用命令 ps -ef | grep redis 檢視效果如下:
2. 啟動Redis叢集
redis叢集的管理工具使用的是ruby指令碼語言,安裝叢集需要ruby環境,先安裝ruby環境:
# 安裝ruby yum -y install ruby ruby-devel rubygems rpm-build # 升級ruby版本,redis4.0.14叢集環境需要2.2.2以上的ruby版本 yum install centos-release-scl-rh yum install rh-ruby23 -y scl enable rh-ruby23 bash # 檢視ruby版本 ruby -v
下載符合環境要求的gem,下載地址如下:
https://rubygems.org/gems/redis/versions/4.1.0
課程資料中已經提供了redis-4.1.0.gem,直接上傳安裝即可,安裝命令:
gem install redis-4.1.0.gem
進入redis安裝目錄,使用redis自帶的叢集管理指令碼,執行命令:
# 進入redis安裝包 cd /root/redis-4.0.14/src/ # 檢視叢集管理指令碼 ll *.rb # 使用叢集管理指令碼啟動叢集,下面命令中的1表示為每個主節點建立1個從節點 ./redis-trib.rb create --replicas 1 127.0.0.1:7001 127.0.0.1:7002 \ 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 127.0.0.1:7006
效果如下:
>>> Creating cluster >>> Performing hash slots allocation on 6 nodes... Using 3 masters: 192.168.200.129:7001 192.168.200.129:7002 192.168.200.129:7003 Adding replica 192.168.200.129:7005 to 192.168.200.129:7001 Adding replica 192.168.200.129:7006 to 192.168.200.129:7002 Adding replica 192.168.200.129:7004 to 192.168.200.129:7003 >>> Trying to optimize slaves allocation for anti-affinity [WARNING] Some slaves are in the same host as their master M: f0094f14b59c023acd38098336e2adcd3d434497 192.168.200.129:7001 slots:0-5460 (5461 slots) master M: 0eba44418d7e88f4d819f89f90da2e6e0be9c680 192.168.200.129:7002 slots:5461-10922 (5462 slots) master M: ac16c5545d9b099348085ad8b3253145912ee985 192.168.200.129:7003 slots:10923-16383 (5461 slots) master S: edc7a799e1cfd75e4d80767958930d86516ffc9b 192.168.200.129:7004 replicates ac16c5545d9b099348085ad8b3253145912ee985 S: cbd415973b3e85d6f3ad967441f6bcb5b7da506a 192.168.200.129:7005 replicates f0094f14b59c023acd38098336e2adcd3d434497 S: 40fdde45b16e1ac85c8a4c84db75b43978d1e4d2 192.168.200.129:7006 replicates 0eba44418d7e88f4d819f89f90da2e6e0be9c680 Can I set the above configuration? (type 'yes' to accept): yes #注意選擇為yes >>> Nodes configuration updated >>> Assign a different config epoch to each node >>> Sending CLUSTER MEET messages to join the cluster Waiting for the cluster to join.. >>> Performing Cluster Check (using node 192.168.200.129:7001) M: f0094f14b59c023acd38098336e2adcd3d434497 192.168.200.129:7001 slots:0-5460 (5461 slots) master 1 additional replica(s) M: ac16c5545d9b099348085ad8b3253145912ee985 192.168.200.129:7003 slots:10923-16383 (5461 slots) master 1 additional replica(s) S: cbd415973b3e85d6f3ad967441f6bcb5b7da506a 192.168.200.129:7005 slots: (0 slots) slave replicates f0094f14b59c023acd38098336e2adcd3d434497 S: 40fdde45b16e1ac85c8a4c84db75b43978d1e4d2 192.168.200.129:7006 slots: (0 slots) slave replicates 0eba44418d7e88f4d819f89f90da2e6e0be9c680 M: 0eba44418d7e88f4d819f89f90da2e6e0be9c680 192.168.200.129:7002 slots:5461-10922 (5462 slots) master 1 additional replica(s) S: edc7a799e1cfd75e4d80767958930d86516ffc9b 192.168.200.129:7004 slots: (0 slots) slave replicates ac16c5545d9b099348085ad8b3253145912ee985 [OK] All nodes agree about slots configuration. >>> Check for open slots... >>> Check slots coverage... [OK] All 16384 slots covered.
e.使用Redis叢集
按照redis cluster的特點,它是去中心化的,每個節點都是對等的,所以連線哪個節點都可以獲取和設 置資料。
使用redis的客戶端連線redis叢集,命令如下:
./redis-cli -h 192.168.200.129 -p 7001 -c
其中-c 一定要加,這個是redis叢集連線時,進行節點跳轉的引數。
連線到叢集后可以設定一些值,可以看到這些值根據前面提到的雜湊槽方式分散儲存在不同的節點上了。