黑馬程序員-傳智健康項目(第十三章)


傳智健康項目


傳智健康項目 第13章

本章內容我們的主題為Redis,目前Redis在企業中的應用已經非常廣泛,同時Redis也是面試中的重點內容。

1. Redis緩存相關問題

1.1 緩存穿透

緩存穿透是指查詢一個數據庫一定不存在的數據。

我們以前正常的使用Redis緩存的流程大致是:

1、數據查詢首先進行緩存查詢

2、如果數據存在則直接返回緩存數據

3、如果數據不存在,就對數據庫進行查詢,並把查詢到的數據放進緩存

4、如果數據庫查詢數據為空,則不放進緩存

例如我們的數據表中主鍵是自增產生的,所有的主鍵值都大於0。此時如果用戶傳入的參數為-1,會是怎么樣?這個-1,就是一定不存在的對象。程序就會每次都去查詢數據庫,而每次查詢都是空,每次又都不會進行緩存。假如有人惡意攻擊,就可以利用這個漏洞,對數據庫造成壓力,甚至壓垮我們的數據庫。

為了防止有人利用這個漏洞惡意攻擊我們的數據庫,我們可以采取如下措施:

如果從數據庫查詢的對象為空,也放入緩存,key為用戶提交過來的主鍵值,value為null,只是設定的緩存過期時間較短,比如設置為60秒。這樣下次用戶再根據這個key查詢redis緩存就可以查詢到值了(當然值為null),從而保護我們的數據庫免遭攻擊。

1.2 緩存雪崩

緩存雪崩,是指在某一個時間段,緩存集中過期失效。在緩存集中失效的這個時間段對數據的訪問查詢,都落到了數據庫上,對於數據庫而言,就會產生周期性的壓力波峰。

為了避免緩存雪崩的發生,我們可以將緩存的數據設置不同的失效時間,這樣就可以避免緩存數據在某個時間段集中失效。例如對於熱門的數據(訪問頻率高的數據)可以緩存的時間長一些,對於冷門的數據可以緩存的時間段一些。甚至對於一些特別熱門的數據可以設置永不過期。

1.3 緩存擊穿

緩存擊穿,是指一個key非常熱點(例如雙十一期間進行搶購的商品數據),在不停的扛着大並發,大並發集中對這一個點進行訪問,當這個key在失效的瞬間,持續的大並發就穿破緩存,直接請求到數據庫上,就像在一個屏障上鑿開了一個洞。

我們同樣可以將這些熱點數據設置永不過期就可以解決緩存擊穿的問題了。

2. Redis集群方案

單機Redis的讀寫速度非常快,能夠支持大量用戶的訪問。雖然Redis的性能很高,但是對於大型網站來說,每秒需要獲取的數據遠遠超過單台redis服務所能承受的壓力,所以我們迫切需要一種方案能夠解決單台Redis服務性能不足的問題。這就需要使用到Redis的集群了。Redis集群有多種方案,下面分別進行講解。

2.1 主從復制Replication

redis支持主從復制的模式。

在主從復制模式下Redis節點分為兩種角色:主節點(也稱為master)和從節點(也稱為slave)。這種模式集群是由一個主節點和多個從節點構成。

原則:Master會將數據同步到slave,而slave不會將數據同步到master。Slave啟動時會連接master來同步數據。

這是一個典型的分布式讀寫分離模型。我們可以利用master來處理寫操作,slave提供讀操作。這樣可以有效減少單個機器的並發訪問數量。

要實現主從復制這種模式非常簡單,主節點不用做任何修改,直接啟動服務即可。從節點需要修改redis.conf配置文件,加入配置:slaveof <主節點ip地址> <主節點端口號>,例如master的ip地址為192.168.200.129,端口號為6379,那么slave只需要在redis.conf文件中配置slaveof 192.168.200.129 6379即可。

分別連接主節點和從節點,測試發現主節點的寫操作,從節點立刻就能看到相同的數據。但是在從節點進行寫操作,提示 READONLY You can't write against a read only slave 不能寫數據到從節點。

現在我們就可以通過這種方式配置多個從節點進行讀操作,主節點進行寫操作,實現讀寫分離。

2.2 哨兵sentinel

我們現在已經給Redis實現了主從復制,可將主節點數據同步給從節點,實現了讀寫分離,提高Redis的性能。但是現在還存在一個問題,就是在主從復制這種模式下只有一個主節點,一旦主節點宕機,就無法再進行寫操作了。也就是說主從復制這種模式沒有實現高可用。那么什么是高可用呢?如何實現高可用呢?

2.2.1 高可用介紹

高可用(HA)是分布式系統架構設計中必須考慮的因素之一,它是通過架構設計減少系統不能提供服務的時間。保證高可用通常遵循下面幾點:

  1. 單點是系統高可用的大敵,應該盡量在系統設計的過程中避免單點。
  2. 通過架構設計而保證系統高可用的,其核心准則是:冗余。
  3. 實現自動故障轉移。

2.2.2 Redis sentinel介紹

sentinel(哨兵)是用於監控redis集群中Master狀態的工具,其本身也是一個獨立運行的進程,是Redis 的高可用解決方案,sentinel哨兵模式已經被集成在redis2.4之后的版本中。

sentinel可以監視一個或者多個redis master服務,以及這些master服務的所有從服務;當某個master服務下線時,自動將該master下的某個從服務升級為master服務替代已下線的master服務繼續處理請求,並且其余從節點開始從新的主節點復制數據。

在redis安裝完成后,會有一個redis-sentinel的文件,這就是啟動sentinel的腳本文件,同時還有一個sentinel.conf文件,這個是sentinel的配置文件。

sentinel工作模式:

注意:可能有些同學會有疑問,現在我們已經基於sentinel實現了高可用,但是如果sentinel掛了怎么辦呢?其實sentinel本身也可以實現集群,也就是說sentinel也是高可用的。

2.2.3 Redis sentinel使用

2.2.3.1 配置sentinel

Sentinel在redis的安裝包中有,我們直接使用就可以了,但是先需要修改配置文件,執行命令:

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.2.3.2 啟動sentinel

配置文件修改后,執行以下命令,啟動sentinel:

/root/redis-4.0.14/src/redis-sentinel sentinel01.conf

效果如下:

可以看到,6379是主服務,6380和6381是從服務。

2.2.3.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

故障轉移如下圖:

2.3 Redis內置集群cluster

2.3.1 Redis cluster介紹

Redis Cluster是Redis的內置集群,在Redis3.0推出的實現方案。在Redis3.0之前是沒有這個內置集群的。Redis Cluster是無中心節點的集群架構,依靠Gossip協議協同自動化修復集群的狀態。

Redis cluster在設計的時候,就考慮到了去中心化,去中間件,也就是說,集群中的每個節點都是平等的關系,都是對等的,每個節點都保存各自的數據和整個集群的狀態。每個節點都和其他所有節點連接,而且這些連接保持活躍,這樣就保證了我們只需要連接集群中的任意一個節點,就可以獲取到其他節點的數據。

Redis cluster集群架構圖如下:

2.3.2 哈希槽方式分配數據

需要注意的是,這種集群模式下集群中每個節點保存的數據並不是所有的數據,而只是一部分數據。那么數據是如何合理的分配到不同的節點上的呢?

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 上了。

2.3.3 Redis cluster的主從模式

redis cluster 為了保證數據的高可用性,加入了主從模式,一個主節點對應一個或多個從節點,主節點提供數據存取,從節點則是從主節點拉取數據備份,當這個主節點掛掉后,就會在這些從節點中選取一個來充當主節點,從而保證集群不會掛掉。

redis cluster加入了主從模式后的效果如下:

2.3.4 Redis cluster搭建

2.3.4.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.3.4.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.

2.3.5 使用Redis集群

按照redis cluster的特點,它是去中心化的,每個節點都是對等的,所以連接哪個節點都可以獲取和設置數據。

使用redis的客戶端連接redis集群,命令如下:

./redis-cli -h 192.168.200.129 -p 7001 -c

其中-c 一定要加,這個是redis集群連接時,進行節點跳轉的參數。

連接到集群后可以設置一些值,可以看到這些值根據前面提到的哈希槽方式分散存儲在不同的節點上了。

視頻地址:https://www.bilibili.com/video/BV1Bo4y117zV


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM