日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

分布式緩存之Redis(持久化、主從、哨兵、分片集群)

作者:crazy_xieyi 更新時間: 2023-07-10 編程語言

更多內容請參考官網:https://redis.io/

Redis持久化

Redis有兩種持久化方案:RDB持久化和AOF持久化。

RDB持久化

RDB全稱Redis Database Backup file(Redis數據備份文件),也被叫做Redis數據快照。簡單來說就是把內存中的所有數據都記錄到磁盤中。當Redis實例故障重啟后,從磁盤讀取快照文件,恢復數據。快照文件稱為RDB文件,默認是保存在當前運行目錄。

RDB持久化在四種情況下會執行:執行save命令、執行bgsave命令、Redis停機時、觸發RDB條件時。

save命令會導致主進程執行RDB,這個過程中其它所有命令都會被阻塞,只有在數據遷移時可能用到。

bgsave命令執行后會開啟獨立進程完成RDB,主進程可以持續處理用戶請求,不受影響。

Redis停機時會執行一次save命令,實現RDB持久化。

Redis內部有觸發RDB的機制,可以在redis.conf文件中找到,格式如下:

# 900秒內,如果至少有1個key被修改,則執行bgsave , 如果是save "" 則表示禁用RDB
save 900 1  
save 300 10  
save 60 10000 

RDB的其它配置也可以在redis.conf文件中設置:

# 是否壓縮 ,建議不開啟,壓縮也會消耗cpu,磁盤比較便宜
rdbcompression yes

# RDB文件名稱
dbfilename dump.rdb  

# 文件保存的路徑目錄
dir ./ 

RDB原理

bgsave開始時會fork主進程得到子進程,然后得到的子進程共享主進程的內存數據。完成fork后讀取內存數據并寫入 RDB 文件,用新RDB文件替換舊的RDB文件。fork采用的是copy-on-write技術:當主進程執行讀操作時,訪問共享內存;當主進程執行寫操作時,則會拷貝一份數據,執行寫操作。

RDB的缺點:

RDB執行間隔時間長,兩次RDB之間寫入數據有丟失的風險。

fork子進程、壓縮、寫出RDB文件都比較耗時。

AOF持久化

AOF全稱為Append Only File(追加文件)。Redis處理的每一個寫命令都會記錄在AOF文件,可以看做是命令日志文件。AOF默認是關閉的,需要修改redis.conf配置文件來開啟AOF:

# 是否開啟AOF功能,默認是no
appendonly yes
# AOF文件的名稱
appendfilename "appendonly.aof"

AOF的命令記錄的頻率也可以通過redis.conf文件來配:

# 表示每執行一次寫命令,立即記錄到AOF文件
appendfsync always 
# 寫命令執行完先放入AOF緩沖區,然后表示每隔1秒將緩沖區數據寫到AOF文件,是默認方案
appendfsync everysec 
# 寫命令執行完先放入AOF緩沖區,由操作系統決定何時將緩沖區內容寫回磁盤
appendfsync no

因為是記錄命令,AOF文件會比RDB文件大的多。而且AOF會記錄對同一個key的多次寫操作,但只有最后一次寫操作才有意義。通過執行bgrewriteaof命令,可以讓AOF文件執行重寫功能,用最少的命令達到相同效果。

Redis也會在觸發閾值時自動去重寫AOF文件,閾值也可以在redis.conf中配置:

# AOF文件比上次文件 增長超過多少百分比則觸發重寫
auto-aof-rewrite-percentage 100
# AOF文件體積最小多大以上才觸發重寫 
auto-aof-rewrite-min-size 64mb 

RDB和AOF各有自己的優缺點,如果對數據安全性要求較高,在實際開發中往往會結合兩者來使用。

RDB

AOF

持久化方式

定時對整個內存做快照

記錄每一次執行的命令

數據完整性

不完整,在兩次備份之間的時間段,數據可能會丟失

相對而言是完整的,取決于刷盤的策略

文件大小

會有壓縮,文件體積小

會記錄每一次的命令,文件體積大

宕機恢復速度

很快

數據恢復優先級

低,數據完整性不如AOF

系統資源占用

高,大量CPU和內存消耗

低,主要是磁盤IO資源,但AOF重寫時會占用大量CPU和內存資源。

使用場景

可以接受數分鐘的數據丟失,追求更快的啟動速度

對數據安全性要求較高

Redis主從

單節點Redis的并發能力是有上限的,要進一步提高Redis的并發能力,就需要搭建主從集群,實現讀寫分離。

開啟主從關系,修改配置文件

在redis.conf中添加一行配置:```slaveof <masterip> <masterport>```

主從數據同步原理:全量同步、增量同步

主從第一次建立連接時,會執行全量同步,將master節點的所有數據都拷貝給slave節點。完整流程:

1.slave節點請求增量同步

2.master節點判斷replid,發現不一致,拒絕增量同步

3.master將完整內存數據生成RDB,發送RDB到slave

4.slave清空本地數據,加載master的RDB

5.master將RDB期間的命令記錄在repl_baklog,并持續將log中的命令發送給slave

6.slave執行接收到的命令,保持與master之間的同步

master如何得知salve是第一次來連接呢?

Replication Id:簡稱replid,是數據集的標記,id一致則說明是同一數據集。每一個master都有唯一的replid,slave則會繼承master節點的replid

offset:偏移量,隨著記錄在repl_baklog中的數據增多而逐漸增大。slave完成同步時也會記錄當前同步的offset。如果slave的offset小于master的offset,說明slave數據落后于master,需要更新。

因此slave做數據同步,必須向master聲明自己的replication id 和offset,master才可以判斷到底需要同步哪些數據。

master判斷發現slave發送來的replid與自己的不一致,說明這是一個全新的slave,就知道要做全量同步了。master會將自己的replid和offset都發送給這個slave,slave保存這些信息。以后slave的replid就與master一致了。master判斷一個節點是否是第一次同步的依據,就是看replid是否一致

全量同步需要先做RDB,然后將RDB文件通過網絡傳輸個slave,成本太高了。因此除了第一次做全量同步,其它大多數時候slave與master都是做增量同步

repl_backlog原理(master知道slave與自己的數據差異)

這個文件是一個固定大小的數組,只不過數組是環形,也就是說角標到達數組末尾后,會再次從0開始讀寫,這樣數組頭部的數據就會被覆蓋。repl_baklog中會記錄Redis處理過的命令日志及offset,包括master當前的offset,和slave已經拷貝到的offset。slave與master的offset之間的差異,就是salve需要增量拷貝的數據了。

repl_baklog大小有上限,寫滿后會覆蓋最早的數據。如果slave斷開時間過久,導致尚未備份的數據被覆蓋,則無法基于log做增量同步,只能再次全量同步

主從同步可以保證主從數據的一致性,可以從以下幾個方面來優化Redis主從就集群:

1.在master中配置repl-diskless-sync yes啟用無磁盤復制,避免全量同步時的磁盤IO。

2.Redis單節點上的內存占用不要太大,減少RDB導致的過多磁盤IO

3.適當提高repl_baklog的大小,發現slave宕機時盡快實現故障恢復,盡可能避免全量同步

4.限制一個master上的slave節點數量,如果實在是太多slave,則可以采用主-從-從鏈式結構,減少master壓力

小結:

全量同步:master將完整內存數據生成RDB,發送RDB到slave。后續命令則記錄在repl_baklog,逐個發送給slave。

增量同步:slave提交自己的offset到master,master獲取repl_baklog中從offset之后的命令給slave

執行全量同步的時機:

slave節點第一次連接master節點時

slave節點斷開時間太久,repl_baklog中的offset已經被覆蓋時

Redis哨兵

Redis提供了哨兵(Sentinel)機制,其作用如下:

監控:Sentinel 會不斷檢查您的master和slave是否按預期工作

自動故障恢復:如果master故障,Sentinel會將一個slave提升為master,當故障實例恢復后也以新的master為主。

通知:Sentinel充當Redis客戶端的服務發現來源,當集群發生故障轉移時,會將最新信息推送給Redis的客戶端。

集群監控原理

Sentinel基于心跳機制監測服務狀態,每隔1秒向集群的每個實例發送ping命令:如果某sentinel節點發現某實例未在規定時間響應,則認為該實例主觀下線。如果超過指定數量(quorum)的sentinel都認為該實例主觀下線,則該實例客觀下線。quorum值最好超過Sentinel實例數量的一半。

集群故障恢復原理

一旦發現master故障,sentinel需要在salve中選擇一個作為新的master,選擇依據如下:

1.首先會判斷slave節點與master節點斷開時間長短,如果超過指定值(down-after-milliseconds * 10【主從庫斷連的最大連接超時時間】)則會排除該slave節點

2.然后判斷slave節點的slave-priority值,越小優先級越高【一般都為1】,如果是0則永不參與選舉

3.如果slave-prority一樣,則判斷slave節點的offset值,越大說明數據越新,優先級越高

4.最后是判斷slave節點的運行id大小,越小優先級越高。

當選出一個新的master后,實現切換流程:

1.sentinel給備選的slave節點發送slaveof no one命令,讓該節點成為master

2.sentinel給所有其它slave發送(slaveof ip+端口)命令,讓這些slave成為新master的從節點,開始從新的master上同步數據。

3.最后,sentinel將故障節點標記為slave(修改故障節點配置,添加slaveof 新master 命令),當故障節點恢復后會自動成為新的master的slave節點。

Redis分片集群

主從和哨兵可以解決高可用、高并發讀的問題。但是對于海量數據存儲問題和高并發寫的問題,只有使用分片集群可以解決。

分片集群特征:集群中有多個master,每個master保存不同數據;每個master都可以有多個slave節點;master之間通過ping監測彼此健康狀態;客戶端請求可以訪問集群任意節點,最終都會被轉發到正確節點。

散列插槽

Redis會把每一個master節點映射到0~16383共16384個插槽(hash slot)上,數據key不是與節點綁定,而是與插槽綁定。redis會根據key的有效部分計算插槽值,分兩種情況:

1.key中包含"{}",且“{}”中至少包含1個字符,“{}”中的部分是有效部分【可以根據{}里面的內容將key分類】

2.key中不包含“{}”,整個key都是有效部分

例如:key是num,那么就根據num計算,如果key是{xy}num,則根據xy計算。計算方式是利用CRC16算法得到一個hash值,然后對16384取余,得到的結果就是slot值。

小結:

Redis如何判斷某個key應該在哪個實例?

1.將16384個插槽分配到不同的實例

2.根據key的有效部分計算哈希值,對16384取余

3.余數作為插槽,尋找插槽所在實例即可

如何將同一類數據固定的保存在同一個Redis實例?

這一類數據使用相同的有效部分,例如key都以{typeId}為前綴。

集群伸縮

添加新節點到redis

執行命令:

redis-cli --cluster add-node  新節點地址:端口  舊節點地址:端口

默認是加入了一個master節點。

轉移插槽:

redis-cli --cluster reshard 節點地址:端口

其實對于分片集群來說,所有數據都是跟著插槽走的。

故障轉移

當集群中有一個master宕機,首先是該實例與其它實例失去連接,然后是疑似宕機狀態,最后是確定下線,自動提升一個slave為新的master,當改故障master再次啟動,就會變為一個slave節點了。

PS: 多級緩存

傳統的緩存策略一般是請求到達Tomcat后,先查詢Redis,如果未命中則查詢數據庫,但是存在下面的問題:

1.請求要經過Tomcat處理,Tomcat的性能成為整個系統的瓶頸

2.Redis緩存失效時,會對數據庫產生沖擊

多級緩存就是充分利用請求處理的每個環節,分別添加緩存,減輕Tomcat壓力,提升服務性能:

1.瀏覽器訪問靜態資源時,優先讀取瀏覽器本地緩存

2.訪問非靜態資源(ajax查詢數據)時,訪問服務端

3.請求到達Nginx后,優先讀取Nginx本地緩存

4.如果Nginx本地緩存未命中,則去直接查詢Redis(不經過Tomcat)

5.如果Redis查詢未命中,則查詢Tomcat

6.請求進入Tomcat后,優先查詢JVM進程緩存

7.如果JVM進程緩存未命中,則查詢數據庫

在多級緩存架構中,Nginx內部需要編寫本地緩存查詢、Redis查詢、Tomcat查詢的業務邏輯,因此這樣的nginx服務不再是一個反向代理服務器,而是一個編寫業務的Web服務器了

如果tomcat是集群模式,那么要對tomcat集群做負載均衡,是因為要讓每一個路徑請求進來都訪問同一個tomcat服務,那么JVM緩存就能一定能生效。

關于Redis緩存預熱

Redis緩存會面臨冷啟動問題:

冷啟動:服務剛剛啟動時,Redis中并沒有緩存,如果所有商品數據都在第一次查詢時添加緩存,可能會給數據庫帶來較大壓力。

緩存預熱:在實際開發中,我們可以利用大數據統計用戶訪問的熱點數據,在項目啟動時將這些熱點數據提前查詢并保存到Redis中。

原文鏈接:https://blog.csdn.net/crazy_xieyi/article/details/129202803

  • 上一篇:沒有了
  • 下一篇:沒有了
欄目分類
最近更新