網站首頁 編程語言 正文

更多內容請參考官網: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
- 上一篇:沒有了
- 下一篇:沒有了
相關推薦
- 2022-05-20 SpringBoot整合Mybatis演示
- 2022-05-28 Python庫AutoTS一行代碼得到最強時序基線_python
- 2022-07-01 使用python實現簡單去水印功能_python
- 2021-11-06 C/C++?Qt?StringListModel?字符串列表映射組件詳解_C 語言
- 2022-09-03 python通過ElementTree操作XML_python
- 2022-07-10 初中級前端程序員必用且夠用的git命令同時推送到github/gitee及三種常用場景
- 2022-04-14 Python中的flask框架詳解_python
- 2022-04-17 <el-dropdown>按鈕點擊出來下拉菜單,點擊下拉菜單觸發事件
- 欄目分類
-
- 最近更新
-
- 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同步修改后的遠程分支