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

學(xué)無(wú)先后,達(dá)者為師

網(wǎng)站首頁(yè) 編程語(yǔ)言 正文

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

作者:crazy_xieyi 更新時(shí)間: 2023-07-10 編程語(yǔ)言

更多內(nèi)容請(qǐng)參考官網(wǎng):https://redis.io/

Redis持久化

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

RDB持久化

RDB全稱Redis Database Backup file(Redis數(shù)據(jù)備份文件),也被叫做Redis數(shù)據(jù)快照。簡(jiǎn)單來(lái)說(shuō)就是把內(nèi)存中的所有數(shù)據(jù)都記錄到磁盤(pán)中。當(dāng)Redis實(shí)例故障重啟后,從磁盤(pán)讀取快照文件,恢復(fù)數(shù)據(jù)??煺瘴募Q為RDB文件,默認(rèn)是保存在當(dāng)前運(yùn)行目錄。

RDB持久化在四種情況下會(huì)執(zhí)行:執(zhí)行save命令、執(zhí)行bgsave命令、Redis停機(jī)時(shí)、觸發(fā)RDB條件時(shí)。

save命令會(huì)導(dǎo)致主進(jìn)程執(zhí)行RDB,這個(gè)過(guò)程中其它所有命令都會(huì)被阻塞,只有在數(shù)據(jù)遷移時(shí)可能用到。

bgsave命令執(zhí)行后會(huì)開(kāi)啟獨(dú)立進(jìn)程完成RDB,主進(jìn)程可以持續(xù)處理用戶請(qǐng)求,不受影響。

Redis停機(jī)時(shí)會(huì)執(zhí)行一次save命令,實(shí)現(xiàn)RDB持久化。

Redis內(nèi)部有觸發(fā)RDB的機(jī)制,可以在redis.conf文件中找到,格式如下:

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

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

# 是否壓縮 ,建議不開(kāi)啟,壓縮也會(huì)消耗cpu,磁盤(pán)比較便宜
rdbcompression yes

# RDB文件名稱
dbfilename dump.rdb  

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

RDB原理

bgsave開(kāi)始時(shí)會(huì)fork主進(jìn)程得到子進(jìn)程,然后得到的子進(jìn)程共享主進(jìn)程的內(nèi)存數(shù)據(jù)。完成fork后讀取內(nèi)存數(shù)據(jù)并寫(xiě)入 RDB 文件,用新RDB文件替換舊的RDB文件。fork采用的是copy-on-write技術(shù):當(dāng)主進(jìn)程執(zhí)行讀操作時(shí),訪問(wèn)共享內(nèi)存;當(dāng)主進(jìn)程執(zhí)行寫(xiě)操作時(shí),則會(huì)拷貝一份數(shù)據(jù),執(zhí)行寫(xiě)操作。

RDB的缺點(diǎn):

RDB執(zhí)行間隔時(shí)間長(zhǎng),兩次RDB之間寫(xiě)入數(shù)據(jù)有丟失的風(fēng)險(xiǎn)。

fork子進(jìn)程、壓縮、寫(xiě)出RDB文件都比較耗時(shí)。

AOF持久化

AOF全稱為Append Only File(追加文件)。Redis處理的每一個(gè)寫(xiě)命令都會(huì)記錄在AOF文件,可以看做是命令日志文件。AOF默認(rèn)是關(guān)閉的,需要修改redis.conf配置文件來(lái)開(kāi)啟AOF:

# 是否開(kāi)啟AOF功能,默認(rèn)是no
appendonly yes
# AOF文件的名稱
appendfilename "appendonly.aof"

AOF的命令記錄的頻率也可以通過(guò)redis.conf文件來(lái)配:

# 表示每執(zhí)行一次寫(xiě)命令,立即記錄到AOF文件
appendfsync always 
# 寫(xiě)命令執(zhí)行完先放入AOF緩沖區(qū),然后表示每隔1秒將緩沖區(qū)數(shù)據(jù)寫(xiě)到AOF文件,是默認(rèn)方案
appendfsync everysec 
# 寫(xiě)命令執(zhí)行完先放入AOF緩沖區(qū),由操作系統(tǒng)決定何時(shí)將緩沖區(qū)內(nèi)容寫(xiě)回磁盤(pán)
appendfsync no

因?yàn)槭怯涗浢?,AOF文件會(huì)比RDB文件大的多。而且AOF會(huì)記錄對(duì)同一個(gè)key的多次寫(xiě)操作,但只有最后一次寫(xiě)操作才有意義。通過(guò)執(zhí)行bgrewriteaof命令,可以讓AOF文件執(zhí)行重寫(xiě)功能,用最少的命令達(dá)到相同效果。

Redis也會(huì)在觸發(fā)閾值時(shí)自動(dòng)去重寫(xiě)AOF文件,閾值也可以在redis.conf中配置:

# AOF文件比上次文件 增長(zhǎng)超過(guò)多少百分比則觸發(fā)重寫(xiě)
auto-aof-rewrite-percentage 100
# AOF文件體積最小多大以上才觸發(fā)重寫(xiě) 
auto-aof-rewrite-min-size 64mb 

RDB和AOF各有自己的優(yōu)缺點(diǎn),如果對(duì)數(shù)據(jù)安全性要求較高,在實(shí)際開(kāi)發(fā)中往往會(huì)結(jié)合兩者來(lái)使用。

RDB

AOF

持久化方式

定時(shí)對(duì)整個(gè)內(nèi)存做快照

記錄每一次執(zhí)行的命令

數(shù)據(jù)完整性

不完整,在兩次備份之間的時(shí)間段,數(shù)據(jù)可能會(huì)丟失

相對(duì)而言是完整的,取決于刷盤(pán)的策略

文件大小

會(huì)有壓縮,文件體積小

會(huì)記錄每一次的命令,文件體積大

宕機(jī)恢復(fù)速度

很快

數(shù)據(jù)恢復(fù)優(yōu)先級(jí)

低,數(shù)據(jù)完整性不如AOF

系統(tǒng)資源占用

高,大量CPU和內(nèi)存消耗

低,主要是磁盤(pán)IO資源,但AOF重寫(xiě)時(shí)會(huì)占用大量CPU和內(nèi)存資源。

使用場(chǎng)景

可以接受數(shù)分鐘的數(shù)據(jù)丟失,追求更快的啟動(dòng)速度

對(duì)數(shù)據(jù)安全性要求較高

Redis主從

單節(jié)點(diǎn)Redis的并發(fā)能力是有上限的,要進(jìn)一步提高Redis的并發(fā)能力,就需要搭建主從集群,實(shí)現(xiàn)讀寫(xiě)分離。

開(kāi)啟主從關(guān)系,修改配置文件

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

主從數(shù)據(jù)同步原理:全量同步、增量同步

主從第一次建立連接時(shí),會(huì)執(zhí)行全量同步,將master節(jié)點(diǎn)的所有數(shù)據(jù)都拷貝給slave節(jié)點(diǎn)。完整流程:

1.slave節(jié)點(diǎn)請(qǐng)求增量同步

2.master節(jié)點(diǎn)判斷replid,發(fā)現(xiàn)不一致,拒絕增量同步

3.master將完整內(nèi)存數(shù)據(jù)生成RDB,發(fā)送RDB到slave

4.slave清空本地?cái)?shù)據(jù),加載master的RDB

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

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

master如何得知salve是第一次來(lái)連接呢?

Replication Id:簡(jiǎn)稱replid,是數(shù)據(jù)集的標(biāo)記,id一致則說(shuō)明是同一數(shù)據(jù)集。每一個(gè)master都有唯一的replid,slave則會(huì)繼承master節(jié)點(diǎn)的replid

offset:偏移量,隨著記錄在repl_baklog中的數(shù)據(jù)增多而逐漸增大。slave完成同步時(shí)也會(huì)記錄當(dāng)前同步的offset。如果slave的offset小于master的offset,說(shuō)明slave數(shù)據(jù)落后于master,需要更新。

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

master判斷發(fā)現(xiàn)slave發(fā)送來(lái)的replid與自己的不一致,說(shuō)明這是一個(gè)全新的slave,就知道要做全量同步了。master會(huì)將自己的replid和offset都發(fā)送給這個(gè)slave,slave保存這些信息。以后slave的replid就與master一致了。master判斷一個(gè)節(jié)點(diǎn)是否是第一次同步的依據(jù),就是看replid是否一致。

全量同步需要先做RDB,然后將RDB文件通過(guò)網(wǎng)絡(luò)傳輸個(gè)slave,成本太高了。因此除了第一次做全量同步,其它大多數(shù)時(shí)候slave與master都是做增量同步。

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

這個(gè)文件是一個(gè)固定大小的數(shù)組,只不過(guò)數(shù)組是環(huán)形,也就是說(shuō)角標(biāo)到達(dá)數(shù)組末尾后,會(huì)再次從0開(kāi)始讀寫(xiě),這樣數(shù)組頭部的數(shù)據(jù)就會(huì)被覆蓋。repl_baklog中會(huì)記錄Redis處理過(guò)的命令日志及offset,包括master當(dāng)前的offset,和slave已經(jīng)拷貝到的offset。slave與master的offset之間的差異,就是salve需要增量拷貝的數(shù)據(jù)了。

repl_baklog大小有上限,寫(xiě)滿后會(huì)覆蓋最早的數(shù)據(jù)。如果slave斷開(kāi)時(shí)間過(guò)久,導(dǎo)致尚未備份的數(shù)據(jù)被覆蓋,則無(wú)法基于log做增量同步,只能再次全量同步

主從同步可以保證主從數(shù)據(jù)的一致性,可以從以下幾個(gè)方面來(lái)優(yōu)化Redis主從就集群:

1.在master中配置repl-diskless-sync yes啟用無(wú)磁盤(pán)復(fù)制,避免全量同步時(shí)的磁盤(pán)IO。

2.Redis單節(jié)點(diǎn)上的內(nèi)存占用不要太大,減少RDB導(dǎo)致的過(guò)多磁盤(pán)IO

3.適當(dāng)提高repl_baklog的大小,發(fā)現(xiàn)slave宕機(jī)時(shí)盡快實(shí)現(xiàn)故障恢復(fù),盡可能避免全量同步

4.限制一個(gè)master上的slave節(jié)點(diǎn)數(shù)量,如果實(shí)在是太多slave,則可以采用主-從-從鏈?zhǔn)浇Y(jié)構(gòu),減少master壓力

小結(jié):

全量同步:master將完整內(nèi)存數(shù)據(jù)生成RDB,發(fā)送RDB到slave。后續(xù)命令則記錄在repl_baklog,逐個(gè)發(fā)送給slave。

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

執(zhí)行全量同步的時(shí)機(jī):

slave節(jié)點(diǎn)第一次連接master節(jié)點(diǎn)時(shí)

slave節(jié)點(diǎn)斷開(kāi)時(shí)間太久,repl_baklog中的offset已經(jīng)被覆蓋時(shí)

Redis哨兵

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

監(jiān)控:Sentinel 會(huì)不斷檢查您的master和slave是否按預(yù)期工作

自動(dòng)故障恢復(fù):如果master故障,Sentinel會(huì)將一個(gè)slave提升為master,當(dāng)故障實(shí)例恢復(fù)后也以新的master為主。

通知:Sentinel充當(dāng)Redis客戶端的服務(wù)發(fā)現(xiàn)來(lái)源,當(dāng)集群發(fā)生故障轉(zhuǎn)移時(shí),會(huì)將最新信息推送給Redis的客戶端。

集群監(jiān)控原理

Sentinel基于心跳機(jī)制監(jiān)測(cè)服務(wù)狀態(tài),每隔1秒向集群的每個(gè)實(shí)例發(fā)送ping命令:如果某sentinel節(jié)點(diǎn)發(fā)現(xiàn)某實(shí)例未在規(guī)定時(shí)間響應(yīng),則認(rèn)為該實(shí)例主觀下線。如果超過(guò)指定數(shù)量(quorum)的sentinel都認(rèn)為該實(shí)例主觀下線,則該實(shí)例客觀下線。quorum值最好超過(guò)Sentinel實(shí)例數(shù)量的一半。

集群故障恢復(fù)原理

一旦發(fā)現(xiàn)master故障,sentinel需要在salve中選擇一個(gè)作為新的master,選擇依據(jù)如下:

1.首先會(huì)判斷slave節(jié)點(diǎn)與master節(jié)點(diǎn)斷開(kāi)時(shí)間長(zhǎng)短,如果超過(guò)指定值(down-after-milliseconds * 10【主從庫(kù)斷連的最大連接超時(shí)時(shí)間】)則會(huì)排除該slave節(jié)點(diǎn)

2.然后判斷slave節(jié)點(diǎn)的slave-priority值,越小優(yōu)先級(jí)越高【一般都為1】,如果是0則永不參與選舉

3.如果slave-prority一樣,則判斷slave節(jié)點(diǎn)的offset值,越大說(shuō)明數(shù)據(jù)越新,優(yōu)先級(jí)越高

4.最后是判斷slave節(jié)點(diǎn)的運(yùn)行id大小,越小優(yōu)先級(jí)越高。

當(dāng)選出一個(gè)新的master后,實(shí)現(xiàn)切換流程:

1.sentinel給備選的slave節(jié)點(diǎn)發(fā)送slaveof no one命令,讓該節(jié)點(diǎn)成為master

2.sentinel給所有其它slave發(fā)送(slaveof ip+端口)命令,讓這些slave成為新master的從節(jié)點(diǎn),開(kāi)始從新的master上同步數(shù)據(jù)。

3.最后,sentinel將故障節(jié)點(diǎn)標(biāo)記為slave(修改故障節(jié)點(diǎn)配置,添加slaveof 新master 命令),當(dāng)故障節(jié)點(diǎn)恢復(fù)后會(huì)自動(dòng)成為新的master的slave節(jié)點(diǎn)。

Redis分片集群

主從和哨兵可以解決高可用、高并發(fā)讀的問(wèn)題。但是對(duì)于海量數(shù)據(jù)存儲(chǔ)問(wèn)題和高并發(fā)寫(xiě)的問(wèn)題,只有使用分片集群可以解決。

分片集群特征:集群中有多個(gè)master,每個(gè)master保存不同數(shù)據(jù);每個(gè)master都可以有多個(gè)slave節(jié)點(diǎn);master之間通過(guò)ping監(jiān)測(cè)彼此健康狀態(tài);客戶端請(qǐng)求可以訪問(wèn)集群任意節(jié)點(diǎn),最終都會(huì)被轉(zhuǎn)發(fā)到正確節(jié)點(diǎn)。

散列插槽

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

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

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

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

小結(jié):

Redis如何判斷某個(gè)key應(yīng)該在哪個(gè)實(shí)例?

1.將16384個(gè)插槽分配到不同的實(shí)例

2.根據(jù)key的有效部分計(jì)算哈希值,對(duì)16384取余

3.余數(shù)作為插槽,尋找插槽所在實(shí)例即可

如何將同一類數(shù)據(jù)固定的保存在同一個(gè)Redis實(shí)例?

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

集群伸縮

添加新節(jié)點(diǎn)到redis

執(zhí)行命令:

redis-cli --cluster add-node  新節(jié)點(diǎn)地址:端口  舊節(jié)點(diǎn)地址:端口

默認(rèn)是加入了一個(gè)master節(jié)點(diǎn)。

轉(zhuǎn)移插槽:

redis-cli --cluster reshard 節(jié)點(diǎn)地址:端口

其實(shí)對(duì)于分片集群來(lái)說(shuō),所有數(shù)據(jù)都是跟著插槽走的。

故障轉(zhuǎn)移

當(dāng)集群中有一個(gè)master宕機(jī),首先是該實(shí)例與其它實(shí)例失去連接,然后是疑似宕機(jī)狀態(tài),最后是確定下線,自動(dòng)提升一個(gè)slave為新的master,當(dāng)改故障master再次啟動(dòng),就會(huì)變?yōu)橐粋€(gè)slave節(jié)點(diǎn)了。

PS: 多級(jí)緩存

傳統(tǒng)的緩存策略一般是請(qǐng)求到達(dá)Tomcat后,先查詢Redis,如果未命中則查詢數(shù)據(jù)庫(kù),但是存在下面的問(wèn)題:

1.請(qǐng)求要經(jīng)過(guò)Tomcat處理,Tomcat的性能成為整個(gè)系統(tǒng)的瓶頸

2.Redis緩存失效時(shí),會(huì)對(duì)數(shù)據(jù)庫(kù)產(chǎn)生沖擊

多級(jí)緩存就是充分利用請(qǐng)求處理的每個(gè)環(huán)節(jié),分別添加緩存,減輕Tomcat壓力,提升服務(wù)性能:

1.瀏覽器訪問(wèn)靜態(tài)資源時(shí),優(yōu)先讀取瀏覽器本地緩存

2.訪問(wèn)非靜態(tài)資源(ajax查詢數(shù)據(jù))時(shí),訪問(wèn)服務(wù)端

3.請(qǐng)求到達(dá)Nginx后,優(yōu)先讀取Nginx本地緩存

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

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

6.請(qǐng)求進(jìn)入Tomcat后,優(yōu)先查詢JVM進(jìn)程緩存

7.如果JVM進(jìn)程緩存未命中,則查詢數(shù)據(jù)庫(kù)

在多級(jí)緩存架構(gòu)中,Nginx內(nèi)部需要編寫(xiě)本地緩存查詢、Redis查詢、Tomcat查詢的業(yè)務(wù)邏輯,因此這樣的nginx服務(wù)不再是一個(gè)反向代理服務(wù)器,而是一個(gè)編寫(xiě)業(yè)務(wù)的Web服務(wù)器了。

如果tomcat是集群模式,那么要對(duì)tomcat集群做負(fù)載均衡,是因?yàn)橐屆恳粋€(gè)路徑請(qǐng)求進(jìn)來(lái)都訪問(wèn)同一個(gè)tomcat服務(wù),那么JVM緩存就能一定能生效。

關(guān)于Redis緩存預(yù)熱

Redis緩存會(huì)面臨冷啟動(dòng)問(wèn)題:

冷啟動(dòng):服務(wù)剛剛啟動(dòng)時(shí),Redis中并沒(méi)有緩存,如果所有商品數(shù)據(jù)都在第一次查詢時(shí)添加緩存,可能會(huì)給數(shù)據(jù)庫(kù)帶來(lái)較大壓力。

緩存預(yù)熱:在實(shí)際開(kāi)發(fā)中,我們可以利用大數(shù)據(jù)統(tǒng)計(jì)用戶訪問(wèn)的熱點(diǎn)數(shù)據(jù),在項(xiàng)目啟動(dòng)時(shí)將這些熱點(diǎn)數(shù)據(jù)提前查詢并保存到Redis中。

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

  • 上一篇:沒(méi)有了
  • 下一篇:沒(méi)有了
欄目分類
最近更新