網站首頁 編程語言 正文
一、redis性能管理
(1) redis-cli
?127.0.0.1:6379> info memory
??
?
?(2) redis-cli info memory
- used_memory_rss:是Redis向操作系統申請的內存。
- used_memory:是Redis中的數據占用的內存。
- used_memory_peak:redis內存使用的峰值。
1.2內存碎片
內存碎片率=Redis向操作系統申請的內存 / Redis中的數據占用的內存
mem_fragmentation_ratio = used_memory_rss / used_memory
mem_fragmentation_ratio:內存碎片率。
redis-cli info memory |grep ratio
?
內存碎片產生的原因
- Redis內部有自已的內存管理器,為了提高內存使用的效率,來對內存的申請和釋放進行管理。
- Redis中的值刪除的時候,并沒有把內存直接釋放、交還給操作系統,而是交給了Redis內部有內存管理器。
- Redis中申請內存的時候,也是先看自己的內存管理器中是否有足夠的內存可用。
- Redis的這種機制,提高了內存的使用率,但是會使Redis中有部分自己沒在用,卻不釋放的內存,導致了內存碎片的發生。
內存碎片率對redis的影響?
- 內存碎片率在1到1.5之間是正常的,這個值表示內存碎片率比較低,也說明Redis 沒有發生內存交換。
- 內存碎片率超過1.5,說明Redis消耗了實際需要的物理內存的150%,其中50%是內存碎片率。
- 內存碎片率低于1的,說明Redis內存分配超出了物理內存,操作系統正在進行內存交換(使用虛擬內存,會降低性能)。需要增加可用物理內存或減少Redis內存占用。
解決碎片率過大的方法?
- 如果你的Redis版本是4.0以下的,需要在redis-cli 工具上輸入shutdown save命令,讓Redis數據庫執行保存操作并關閉Redis服務,再重啟服務器。Redis服務器重啟后,Redis 會將沒用的內存歸還給操作系統,碎片率會降下來。
- Redis4.0版本開始,可以在不重啟的情況下,線上整理內存碎片,將未使用的內存歸還給操作系統。
?config set activedefrag yes ? ?#自動碎片清理
?memory purge ? ? ? ? ? ? ? ? ? #手動碎片清理
?1.3內存使用率?
redis實例的內存使用率超過可用最大內存,操作系統將開始進行內存與swap空間交換。
避免內存交換發生的方法:
- 針對緩存數據大小選擇安裝Redis 實例
- 盡可能的使用Hash數據結構存儲
- 設置key的過期時間
1.4內回收key?
內存清理策略,保證合理分配redis有限的內存資源。
當內存使用達到設置的最大閾值時,需選擇一種key的回收策略,默認情況下回收策略是禁止刪除(noenviction)。配置文件中修改 maxmemory-policy 屬性值:
im /etc/redis/6379.conf
?---598行----
?maxmemory-policy noenviction ? #修改max-memory-policy屬性值
??
?##回收策略有以下幾種:##
?●volatile-lru
?#使用LRU算法從已設置過期時間的數據集合中淘汰數據
?(移除最近最少使用的key,針對設置了TTL的key)
??
?●volatile-ttl
?#從已設置過期時間的數據集合中挑選即將過期的數據淘汰
?(移除最近過期的key)
??
?●volatile-random
?#從已設置過期時間的數據集合中隨機挑選數據淘汰
?(在設置了TTL的key里隨機移除)
??
?●allkeys-lru
?#使用LRU算法 從所有數據集合中淘汰數據
?(移除最少使用的key,針對所有的key)
??
?●allkeys-random
?#從數據集合中任意選擇數據淘汰(隨機移除key)
??
?●noenviction
?#禁止淘汰數據(不刪除直到寫滿時報錯)
二、redis的優化策略
2.1設置Redis客戶端連接的超時時間?
vim /etc/redis/6379.conf
?-----114行------
?114 timeout 0 ? ??
?#單位為秒(s),取值范圍為0~100000。默認值為0,表示無限制,即Redis不會主動斷開連接,即使這個客戶端已經空閑了很長時間。
?#例如可設置為600,則客戶端空閑10分鐘后,Redis會主動斷開連接。
??
?#注意:在實際運行中,為了提高性能,Redis不一定會精確地按照timeout的值規定的時間來斷開符合條件的空閑連接,例如設置timeout為10s,但空閑連接可能在12s后,服務器中新增很多連接時才會被斷開。
2.2?設置redis自動碎片清理
?config set activedefrag yes ? ?#自動碎片清理
?memory purge ? ? ? ? ? ? ? ? ? #手動碎片清理
2.3設置redis最大內存閾值?
內存閾值如果不設置,則沒有限制,直到把服務器的內存干滿、之后會使用交換分區。
設置內存閾值后,不會使用swap交換分區。且如果設置了key回收策略,當內存使用達到設置的最大閾值時,系統會進行key回收。
vim /etc/redis/6379.conf
?-----567行------
?567 # maxmemory <bytes>
?568 maxmemory 1gb ? ? ? ? ? #例如設置最大內存閾值為1gb
三、redis雪崩、穿透、擊穿的原因和解決方案
(1) redis雪崩
定義:緩存雪崩是指大量的應用請求無法在 Redis 緩存中進行處理,緊接著,應用將大量請求發送到數據庫層,導致數據庫層的壓力激增。?
一個簡單的雪崩過程:
-
Redis 集群產生了大面積故障;
-
緩存失敗,此時仍有大量請求去訪問 Redis 緩存服務器;
-
在大量 Redis 請求失敗后,這些請求將會去訪問數據庫;
-
由于應用的設計依賴于數據庫和 Redis 服務,很快就會造成服務器集群的雪崩,最終導致整個系統的癱瘓。
?產生的原因:
1)緩存中有大量數據同時過期,導致大量請求無法得到處理。
2)Redis 緩存實例發生故障宕機了
解決方案:?
-
【事前】高可用緩存:高可用緩存是防止出現整個緩存故障。即使個別節點,機器甚至機房都關閉,系統仍然可以提供服務,Redis 哨兵(Sentinel) 和 Redis 集群(Cluster) 都可以做到高可用;
-
【事中】緩存降級(臨時支持):當訪問次數急劇增加導致服務出現問題時,我們如何確保服務仍然可用。在國內使用比較多的是 Hystrix,它通過熔斷、降級、限流三個手段來降低雪崩發生后的損失。只要確保數據庫不死,系統總可以響應請求,每年的春節 12306 我們不都是這么過來的嗎?只要還可以響應起碼還有搶到票的機會;
-
【事后】Redis備份和快速預熱:Redis數據備份和恢復、快速緩存預熱。
(2)redis 擊穿
?緩存擊穿是指當前熱點數據存儲到期時,多個線程同時并發訪問熱點數據。因為緩存剛過期,所有并發請求都會到數據庫中查詢數據。
解決方法:
-
將熱點數據設置為永不過期;
-
加互斥鎖:互斥鎖可以控制查詢數據庫的線程訪問,但這種方案會導致系統的吞吐量下降,需要根據實際情況使用。
?(3)緩存穿透
緩存穿透是指緩存和數據庫中都沒有的數據,而用戶不斷發起請求,如發起id為-1的數據或者特別大的不存在的數據。有可能是黑客利用漏洞攻擊從而去壓垮應用的數據庫。?
- 驗證攔截:接口層進行校驗,如鑒定用戶權限,對ID之類的字段做基礎的校驗,如
id<=0
的字段直接攔截; - 緩存空數據:當數據庫查詢到的數據為空時,也將這條數據進行緩存,但緩存的有效性設置得要較短,以免影響正常數據的緩存;
- ?使用布隆過濾器:布隆過濾器是一種比較獨特數據結構,有一定的誤差。當它指定一個數據存在時,它不一定存在,但是當它指定一個數據不存在時,那么它一定是不存在的。
二、redis的高可用的概念
在web服務器中,高可用是指服務器可以正常訪問的時間,衡量的標準是在多長時間內可以提供正常服務(99.9%、99.99%、99.999%等等)。
高可用的計算公式是1-(宕機時間)/(宕機時間+運行時間)有點類似與網絡傳輸的參數誤碼率,我們用9的個數表示可用性:
2個9:99%,一年內宕機時長:1%×365天=3.6524天=87.6h
4個9:99.99%,一年內宕機時長:0.01%×365天=52.56min
5個9:99.999%,一年內宕機時長:0.001%*365天=5.265min
11個9:幾乎一年宕機時間只有幾秒鐘
但是在Redis語境中,高可用的含義似乎要寬泛一些,除了保證提供正常服務(如主從分離、快速容災技術),還需要考慮數據容量的擴展、數據安全不會丟失等
2.1Redis的高可用技術
在Redis中,實現高可用的技術主要包括持久化、主從復制、哨兵和cluster集群,下面分別說明它們的作用,以及解決了什么樣的問題。
-
持久化:?持久化是最簡單的高可用方法(有時甚至不被歸為高可用的手段),主要作用是數據備份,即將數據存儲在硬盤,保證數據不會因進程退出而丟失。
-
主從復制:?主從復制是高可用Redis的基礎,哨兵和集群都是在主從復制基礎上實現高可用的。主從復制主要實現了數據的多機備份(和同步),以及對于讀操作的負載均衡和簡單的故障恢復。
- 缺陷:故障恢復無法自動化;寫操作無法負載均衡;存儲能力受到單機的限制。
-
哨兵:?在主從復制的基礎上,哨兵實現了自動化的故障恢復。(主掛了,找一個從成為新的主,哨兵節點進行監控)
- 缺陷:寫操作無法負載均衡;存儲能力受到單機的限制。
-
Cluster集群:?通過集群,Redis解決了寫操作無法負載均衡,以及存儲能力受到單機限制的問題,實現了較為完善的高可用方案。(6臺起步,成雙成對,3主3從)
三、redis主從復制
主從復制,是指將一臺Redis服務器的數據,復制到其他的Redis服務器。前者稱為主節點(Master),后者稱為從節點(slave);數據的復制是單向的,只能由主節點到從節點。
默認情況下,每臺Redis服務器都是主節點;且一個主節點可以有多個從節點(或沒有從節點),但一個從節點只能有一個主節點。
3.1主從復制的作用
- 據冗余:?主從復制實現了數據的熱備份,是持久化之外的一種數據冗余方式。
- 故障恢復:?當主節點出現問題時,可以由從節點提供服務,實現快速的故障恢復;實際上是一種服務的冗余。
- 負載均衡:?在主從復制的基礎上,配合讀寫分離,可以由主節點提供寫服務,由從節點提供讀服務(即寫Redis數據時應用連接主節點,讀Redis數據時應用連接從節點),分擔服務器負載;尤其是在寫少讀多的場景下,通過多個從節點分擔讀負載,可以大大提高Redis服務器的并發量。
- 高可用基石:?除了上述作用以外,主從復制還是哨兵和集群能夠實施的基礎,因此說主從復制是Redis高可用的基礎。
3.2主從復制流程
1)若啟動一個slave機器進程,則它會向Master機器發送一個sync command命令,請求同步連接。
(2)無論是第一次連接還是重新、【】連接,Master機器都會啟動一個后臺進程,將數據快照保存到數據文件中(執行rdb操作),同時Master還會記錄修改數據的所有命令并緩存在數據文件中.
(3)后臺進程完成緩存操作之后,Master機器就會向slave機器發送數據文件,slave端機器將數據文件保存到硬盤上,然后將其加載到內存中,接著Master機器就會將修改數據的所有操作一并發送給slave端機器。若slave出現故障導致宕機,則恢復正常后會自動重新連接。
(4)Master機器收到slave端機器的連接后,將其完整的數據文件發送給slave端機器,如果Mater同時收到多個slave發來的同步請求,則Master會在后臺啟動一個進程以保存數據文件,然后將其發送給所有的slave端機器,確保所有的slave端機器都正常。
四、redis一主二從的部署
實驗組件
主從 | redis的版本號 | IP地址 |
---|---|---|
master | redis-5.0.7 | 192.168.195.100 |
slave1 | redis-5.0.7 | 192.168.195.200 |
slave2 | redis-5.0.7 | 192.168.195.101 |
實驗具體步驟?
?實驗前準備好三臺源碼編譯安裝好的redis虛擬機
步驟一:修改master節點的配置文件?
vim /etc/redis/6379.conf?
?bind 0.0.0.0 ? ? ? ? ? ? ? ? ? ? ?#70行,修改監聽地址為0.0.0.0(生產環境中,尤其是多網卡最好填寫物理網卡的IP)
?daemonize yes ? ? ? ? ? ? ? ? ? ? #137行,開啟守護進程,后臺啟動?
?logfile /var/log/redis_6379.log ? #172行,指定日志文件存放目錄
?dir /var/lib/redis/6379 ? ? ? ? ? #264行,指定工作目錄
?appendonly yes ? ? ? ? ? ? ? ? ? ?#700行,開啟AOF持久化功能
?
/etc/init.d/redis_6379 restart ? ? #重啟redis服務
?
步驟二:修改slave節點的配置文件
#修改slave1的配置文件
vim /etc/redis/6379.conf?
?bind 0.0.0.0 ? ? ? ? ? ? ? ? ? ? ? ?#70行,修改監聽地址為0.0.0.0(生產環境中需要填寫物理網卡的IP)
?daemonize yes ? ? ? ? ? ? ? ? ? ? ? #137行,開啟守護進程,后臺啟動
?logfile /var/log/redis_6379.log ? ? #172行,指定日志文件目錄
?dir /var/lib/redis/6379 ? ? ? ? ? ? #264行,指定工作目錄
?replicaof 192.168.73.105 6379 ? ? ? #288行,指定要同步的Master節點的IP和端口
?appendonly yes ? ? ? ? ? ? ? ? ? ? ?#700行,修改為yes,開啟AOF持久化功能
?
#將配置文件傳給slave2
scp /etc/redis/6379.conf 192.168.73.107:/etc/redis/
?
/etc/init.d/redis_6379 restart ?#重啟redis
netstat -natp | grep redis ? ? ?#查看主從服務器是否已建立連接
實驗測試?
master寫入數據?
127.0.0.1:6379> keys * ? 127.0.0.1:6379> set name zhangsan ? 127.0.0.1:6379> get name
?從節點查詢 沒有問題
?五、Redis哨兵模式
主從切換技術的方法是:當服務器宕機后,需要手動一臺從機切換為主機,這需要人工干預,不僅費時費力而且還會造成一段時間內服務不可用。為了解決主從復制的缺點,就有了哨兵機制。
?哨兵的核心功能:在主從復制的基礎上,哨兵引入了主節點的自動故障轉移。
?哨兵模式的組成:
哨兵節點:?哨兵系統由一個或多個哨兵節點組成,哨兵節點是特殊的redis節點,不存儲數據。
數據節點:?主節點和從節點都是數據節點。
5.1? 哨兵模式的作用?
- 監控:?哨兵會不斷地檢查主節點和從節點是否運作正常。
- 自動故障轉移:?當主節點不能正常工作時,哨兵會開始自動故障轉移操,它會將失效主節點的其中一個從節點升級為新的主節點,并讓其它從節點改為復制新的主節點。
- 通知(提醒):?哨兵可以將故障轉移的結果發送給客戶端。
此外:哨兵節點也可以是單獨獨立在其他的主機上,并不需要一定安裝redis主從復制的節點服務器上 、
5.2故障轉移機制
1、由哨兵節點定期監控發現主節點是否出現了故障
每個哨兵節點每隔1秒會問主節點、從節點及其它哨兵節點發送一次ping命令做一次心檢測。如果主節點在一定時間范圍內不回復或者是回復一個錯誤消息,那么這個哨兵就會認為這個主節點主觀下線了(單方面的)。當超過半數哨兵節點認為該主節點主觀下線了,這樣就客觀下線了。
2、當主節點出現故障,此時哨兵節點會通過Raft算法(選舉算法)實現選舉機制共同選舉出一個哨兵節點為leader,來負責處理主節點的故障轉移和通知。所以整個運行哨兵的集群的數量不得少于3個節點。
3、由leader哨兵節點執行故障轉移,過程如下:
- 將某一個從節點升級為新的主節點,讓其它從節點指向新的主節點;
- 若原主節點恢復也變成從節點,并指向新的主節點;
- 通知客戶端主節點已經更換。
需要特別注意的是,客觀下線是主節點才有的概念;如果從節點和哨兵節點發生故障,被哨兵主觀下線后,不會再有后續的客觀下線和故障轉移操作
?5.3哨兵模式中主節點的選拔?
1.過濾掉不健康的(己下線的),沒有回復哨兵ping響應的從節點。
2.選擇配置文件中從節點優先級配置最高的。(replica-priority,默認值為100)
3.選擇復制偏移量最大,也就是復制最完整的從節點。
哨兵的啟動依賴于主從模式,所以須把主從模式安裝好的情況下再去做哨兵模式。
六、redis哨兵模式的部署(哨兵節點可以單獨配置或者放在數據節點一起配置)
主從 | redis的版本號 | IP地址 | 哨兵點 |
---|---|---|---|
master | redis-5.0.7 | 192.168.195.100 | Sentinel 1 |
slave1 | redis-5.0.7 | 192.168.195.200 | Sentinel 2 |
slave2 | redis-5.0.7 | 192.168.195.101 | Sentinel 3 |
實驗具體操作步驟?
?在redis主從復制的基礎上進行哨兵模式的部署
步驟一:修改哨兵節點的配置文件
哨兵的的配置文件是redis軟件中自帶的配置?
vim /opt/redis-5.0.7/sentinel.conf
......
protected-mode no ? ? ? ? ? ? ? ?#17行,取消注釋,關閉保護模式
port 26379 ? ? ? ? ? ? ? ? ? ? ? #21行,Redis哨兵默認的監聽端口
daemonize yes ? ? ? ? ? ? ? ? ? ?#26行,指定sentinel為后臺啟動
logfile "/var/log/sentinel.log" ?#36行,指定日志文件存放路徑
dir "/var/lib/redis/6379" ? ? ? ?#65行,指定數據庫存放路徑
sentinel monitor mymaster 192.168.195.100?6379 2 ?#84行,修改
#指定該哨兵節點監控192.168.195.100:6379這個主節點,該主節點的名稱是mymaster。
#最后的2的含義與主節點的故障判定有關:至少需要2個哨兵節點同意,才能判定主節點故障并進行故障轉移
?
sentinel down-after-milliseconds mymaster 3000 ?#113行,判定服務器down掉的時間周期,默認30000毫秒(30秒)
sentinel failover-timeout mymaster 180000 ?#146行,同一個sentinel對同一個master兩次failover之間的間隔時間(180秒)
?
#傳給兩外2個哨兵節點
scp /opt/redis-5.0.7/sentinel.conf ?192.168.195.200:/opt/redis-5.0.7/
scp /opt/redis-5.0.7/sentinel.conf ?192.168.195.100:/opt/redis-5.0.7/
步驟二:啟動 哨兵模式,查看其監控狀態
#啟動三臺哨兵
cd /opt/redis-5.0.7/
redis-sentinel sentinel.conf &
?
#在哨兵節點查看監控狀態
[root@localhost ~]# redis-cli -p 26379 info Sentinel
實驗測試?
?故障模擬
#在Master 上查看redis-server進程號:
[root@localhost ~]# ps -ef | grep redis
?
#殺死 Master 節點上redis-server的進程號
[root@localhost ~]# kill -9 pid號 ? ? ?#Master節點上redis-server的進程號
[root@localhost ~]# netstat -natp | grep redis
實驗結果
?[root@localhost redis-5.0.7]# tail -f /var/log/sentinel.log
?
?
#新master進行鍵值對的創建
[root@localhost redis-5.0.7]# redis-cli?
127.0.0.1:6379> set newname lisi
OK
127.0.0.1:6379> get newname
"lisi"
127.0.0.1:6379>?
?七 Redis集群模式
集群,即Redis Cluster,是Redis3.0開始引入的分布式存儲方案。
集群由多個節點(Node)組成,Redis的數據分布在這些節點中。集群中的節點分為主節點和從節點:只有主節點負責讀寫請求和集群信息的維護;從節點只進行主節點數據和狀態信息的復制。
7.1集群的作用
(1)數據分區:?數據分區(或稱數據分片)是集群最核心的功能。
- 集群將數據分散到多個節點,一方面突破了Redis單機內存大小的限制,存儲容量大大增加;另一方面每個主節點都可以對外提供讀服務和寫服務,大大提高了集群的響應能力。
- Redis單機內存大小受限問題,在介紹持久化和主從復制時都有提及;例如,如果單機內存太大,bgsave和bgrewriteaof的fork操作可能導致主進程阻塞,主從環境下主機切換時可能導致從節點長時間無法提供服務,全量復制階段主節點的復制緩沖區可能溢出。
(2)高可用:?集群支持主從復制和主節點的自動故障轉移(與哨兵類似);當任一節點發生故障時,集群仍然可以對外提供服務。
?通過集群,Redis解決了寫操作無法負載均衡,以及存儲能力受到單機限制的問題,實現了較為完善的高可用方案。
7.2Redis集群的數據分片
Redis集群引入了哈希槽的概念。
Redis集群有16384個哈希槽(編號0-16383)。
集群的每個節點負責一部分哈希槽。
每個Key通過CRC16校驗后對16384取余來決定放置哪個哈希槽,通過這個值,去找到對應的插槽所對應的節點,然后直接自動跳轉到這個對應的節點上進行存取操作。
以3個節點組成的集群為例:
- 節點A包含0到5460號哈希槽
- 節點B包含5461到10922號哈希槽
- 節點c包含10923到16383號哈希? ?槽
八redis集群的部署
真實生產環境中,redis的cluster集群至少需要六臺服務器才能實現 ,如果因為電腦性能問題
可以嘗試redis多實例部署
實驗組件的部署?
安裝包:redis-5.0.7.tar.gz
192.168.195.100? ?我們就用一臺機器來搭建
cd /etc/redis/
mkdir -p redis-cluster/redis600{1..6} ? #創建redis集群的工作目錄、和每個節點的工作目錄
ls -R redis-cluster/
到軟件包目錄,把redis配置文件分別復制到我們第二步所創建的每個節點目錄中。也要把/opt/redis-5.0.7/src下的客戶端工具redis-cli和服務端命令redis-server復制到每個節點的目錄中
cd /opt/redis-5.0.7/src/
ls
cd /opt/redis-5.0.7/
for i in {1..6}; do cp /opt/redis-5.0.7/redis.conf /etc/redis/redis-cluster/redis600$i; cp /opt/redis-5.0.7/src/redis-server /opt/redis-5.0.7/src/redis-cli /etc/redis/redis-cluster/redis600$i; done ? ? ?
#使用for循環復制可以節省很多時間
cd /etc/redis/redis-cluster/
ls -R
?
修改每個節點目錄中的redis配置文件
cd redis6001
vim redis.conf
?
#bind 127.0.0.1 ? ? ##第69行;注釋掉監聽地址,表示監聽任意地址(也可設置為0.0.0.0)
protected-mode no ? ?#修改第88行,關閉保護模式,設置為no
port 6001 ? ? ? ? ? #修改第92行,修改監聽端口為6001
daemonize yes ? ? ? #修改第136行,開啟后臺運行
appendonly yes ? ? ?#修改第699行,開啟AOF持久化
?
?
#集群模式配置
cluster-enabled yes ? ?#第832行取消注釋,開啟集群模式
cluster-config-file nodes-6001.conf ? #第840行,每個集群配置文件,取消注釋、修改對應的端口(每個節點都要設置對應的)
cluster-node-timeout 15000 ? #第846行,集群節點之間通信的超時時間;取消注釋
啟動redis服務,一定要先進入每個節點目錄中去使用redis-server命令啟動
cd ../redis6001
ls
for i in {1..6}; do cd /etc/redis/redis-cluster/redis600$i; ./redis-server redis.conf; done
ps -elf |grep redis
redis-cli --cluster create 127.0.0.1:6001 127.0.0.1:6002 127.0.0.1:6003 127.0.0.1:6004 127.0.0.1:6005 127.0.0.1:6006 --cluster-replicas 1 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? #把節點加入到集群當中
--cluster-replicas ? ?指定每個主節點有多少個從節點做主從復制
?
?
redis-cli -p 6001 ? ?#登錄redis數據庫
cluster slots ? ? ? ?#查看主從對應關系
?
驗證,鍵的插入
redis-cli -p 6001 -c ? ?
-c ?實現節點間的跳轉,如果不加會報錯
set name hj
??登錄到6004節點
redis-cli -p 6004 -c
keys *
get name
Redis集群拓展:
數據量過多如何處理?
當數據量過多的情況下,一種簡單的方式是升級Redis實例的資源配置,包括增加內存容量、磁盤容量、更好配置的CPU等,但這種情況下Redis使用RDB進行持久化的時候響應會變慢,Redis通過fork子進程來完成數據持久化,但fork在執行時會阻塞主線程,數據量越大,fork的阻塞時間就越長,從而導致Redis響應變慢。
Redis的切片集群可以解決這個問題,也就是啟動多個Redis實例來組成一個集群,再按照一定的規則把數據劃分為多份,每一份用一個實例來保存,這樣客戶端只需要訪問對應的實例就可以獲取數據。在這種情況下fork子進程一般不會給主線程帶來較長時間的阻塞,如下圖:
切片集群架構圖
將20GB的數據分為4分,每份包含5GB數據,客戶端只需要找到對應的實例就可以獲取數據,從而減少主線程阻塞的時間。
當數據量過多的時候,可以通過升級Redis實例的資源配置或者通過切片集群的方式。前者實現起來簡單粗暴,但這數據量增加的時候,需要的內存也在不斷增加,主線程fork子進程就有可能會阻塞,而且該方案受到硬件和成本的限制。相比之下第二種方案是一種擴展性更好的方案,如果想保存更多的數據,僅需要增加Redis實例的個數,不用擔心單個實例的硬件和成本限制。在面向百萬、千萬級別的用戶規模時,橫向擴展的 Redis 切片集群會是一個非常好的選擇。
選擇切片集群也是需要解決一些問題的:
- 數據切片后,在多個實例之間怎么分布?
- 客戶端怎么確定想要訪問的實例是哪一個?
Redis采用了Redis Cluster的方案來實現切片集群,具體的Redis Cluster采用了哈希槽(Hash Slot)來處理數據和實例之間的映射關系。在Redis Cluster中,一個切片集群共有16384個哈希槽(為什么Hash Slot的個數是16384),這些哈希槽類似于數據的分區,每個鍵值對都會根據自己的key被影射到一個哈希槽中,映射步驟如下:
- 根據鍵值對key,按照CRC16算法計算一個16bit的值。
- 用計算的值對16384取模,得到0~16383范圍內的模數,每個模數對應一個哈希槽。
這時候可以得到一個key對應的哈希槽了,哈希槽又是如何找到對應的實例的呢?
在部署Redis Cluster的時候,可以通過cluster create命令創建集群,此時Redis會自動把這些槽分布在集群實例上,例如一共有N個實例,那么每個實例包含的槽個數就為16384/N。當然可能存在Redis實例中內存大小配置不一的問題,內存大的實例具有更大的容量。這種情況下可以通過cluster addslots命令手動分配哈希槽。
redis-cli -h 33.33.33.3 –p 6379 cluster addslots 0,1redis-cli -h 33.33.33.4 –p 6379 cluster addslots 2,3redis-cli -h 33.33.33.5 –p 6379 cluster addslots 4
復制代碼
復制代碼
要注意的是,如果采用cluster addslots的方式手動分配哈希槽,需要將16384個槽全部分配完,否則Redis集群無法正常工作。現在通過哈希槽,切片集群就實現了數據到哈希槽、哈希槽到實例的對應關系,那么客戶端如何確定需要訪問的實例是哪一個呢?
(二)客戶端定位集群中的數據
客戶端請求的key可以通過CRC16算法計算得到,但客戶端還需要知道哈希槽分布在哪個實例上。在最開始客戶端和集群實例建立連接后,實例就會把哈希槽的分配信息發給客戶端,實例之間會把自己的哈希槽信息發給和它相連的實例,完成哈希槽的擴散。這樣客戶端訪問任何一個實例的時候,都能獲取所有的哈希槽信息。當客戶端收到哈希槽的信息后會把哈希槽對應的信息緩存在本地,當客戶端發送請求的時候,會先找到key對應的哈希槽,然后就可以給對應的實例發送請求了。
但是,哈希槽和實例的對應關系不是一成不變的,可能會存在新增或者刪除的情況,這時候就需要重新分配哈希槽;也可能為了負載均衡,Redis需要把所有的實例重新分布。
雖然實例之間可以互相傳遞消息以獲取最新的哈希槽分配信息,但是客戶端無法感知這個變化,就會導致客戶端訪問的實例可能不是自己所需要的了。
Redis Cluster提供了重定向的機制,當客戶端給實例發送數據讀寫操作的時候,如果這個實例上沒有找到對應的數據,此時這個實例就會給客戶端返回MOVED命令的相應結果,這個結果中包含了新實例的訪問地址,此時客戶端需要再給新實例發送操作命令以進行讀寫操作,MOVED命令如下:
GET hello:key(error) MOVED 33.33.33.33:6379
復制代碼
復制代碼
返回的信息代表客戶端請求的key所在的哈希槽為3333,實際是在33.33.33.33這個實例上,此時客戶端只需要向33.33.33.33這個實例發送請求就可以了。
此時也存在一個小問題,哈希槽中對應的數據過多,導致還沒有遷移到其他實例,此時客戶端就發起了請求,在這種情況下,客戶端就對實例發起了請求,如果數據還在對應的實例中,會給客戶端返回數據;如果請求的數據已經被轉移到其他實例上,客戶端就會收到實例返回的ASK命令,該命令表示:哈希槽中數據還在前一種、ASK命令把客戶端需要訪問的新實例返回了。此時客戶端需要給新實例發送ASKING命令以進行請求操作。
值得注意的是ASK信息和MOVED信息不一樣,ASK信息并不會更新客戶端本地的緩存的哈希槽分配信息,也就是說如果客戶端再次訪問該哈希槽還是會請求之前的實例,直到數據遷移完成.
原文鏈接:https://blog.csdn.net/weixin_48271370/article/details/127854771
相關推薦
- 2022-06-15 go語言定時器Timer及Ticker的功能使用示例詳解_Golang
- 2023-06-16 瞅一眼就能學會的GO并發編程使用教程_Golang
- 2022-08-01 Win?Server2016遠程桌面如何允許多用戶同時登錄_win服務器
- 2022-05-16 解析Sentry?Relay?二次開發調試_python
- 2022-07-18 使用d2l包和相關環境配置的一些血淚心得
- 2022-08-18 python編寫第一個交互程序步驟示例教程_python
- 2022-08-17 C語言超全面覆蓋操作符知識點_C 語言
- 2022-08-12 python封裝成exe的超詳細教程_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支