目錄
一.Redis 持久化
1.持久化概述
2.持久化分類
3.RDB和AOF持久化
1.RDB持久化
2.RDB觸發條件
(1)手動觸發
?(2)自動觸發
(3) 執行流程?
(4)啟動時加載?
3.AOF持久化
(1)開啟AOF
(2)執行流程?
(3)啟動時加載
4.RDB和AOF的優缺點和區別(重點!)
1.RDB
2.AOF
3.區別?
二.Redis 性能管理?
1.查看Redis內存使用
2.跟蹤內存碎片率
3.解決碎片率大的問題?
4.內存使用率
?5.內回收key
6.Redis性能優化(重點!!)
三.Redis 的三大緩存問題?
1.緩存雪崩?
(1)緩存雪崩解決方案?
2.緩存穿透?
(1) 緩存穿透解決方案
3.緩存擊穿?
(1)緩存擊穿解決方案?
一.Redis 持久化
1.持久化概述
Redis 是運行在內存中,內存中的數據斷電丟失,為了能夠重用Redis數據,或者防止系統故障、需要定期將Redis中的數據以某種形式(數據或命令)從內存保存到硬盤,當下次Redis重啟時,利用持久化文件實現數據恢復,即持久化。
2.持久化分類
- RDB 方式:創建快照的方式獲取某一時刻Redis中所有數據的副本定時保存在磁盤上
- AOF方式:將執行的寫命令寫到文件的末尾,以日志的方式記錄數據的變化?
3.RDB和AOF持久化
1.RDB持久化
RDB持久化是指在指定的時間間隔內將內存中當前進程中的數據生成快照保存到硬盤(因此也稱作快照持久化),用二進制壓縮存儲,保存的文件后綴是rdb;當Redis重新啟動時,可以讀取快照文件恢復數據。
2.RDB觸發條件
(1)手動觸發
?save命令和bgsave命令都可以生成RDB文件。
save命令會阻塞Redis服務器進程,直到RDB文件創建完畢為止,在Redis服務器阻塞期間,服務? 器不能處理任何命令請求。
bgsave命令會創建一個子進程,由子進程來負責創建RDB文件,父進程(即Redis主進程)則繼續處理請求。
bgsave命令執行過程中,只有fork子進程時會阻塞服務器,而對于save命令,整個過程都會阻塞服務器,因此save已基本被廢棄,線上環境要杜絕save的使用。
?(2)自動觸發
在自動觸發RDB持久化時,Redis也會選擇bgsave而不是save來進行持久化。
save m n
自動觸發最常見的情況是在配置文件中通過save m n,指定當m秒內發生n次變化時,會觸發bgsave進行快照。
vim /usr/local/redis/conf/redis.conf
--433行--RDB默認保存策略
# save 3600 1 300 100 60 10000
#表示以下三個save條件滿足任意一個時,都會引起bgsave的調用
save 3600 1 :當時間到3600秒時,如果redis數據發生了至少1次變化,則執行bgsave
save 300 10 :當時間到300秒時,如果redis數據發生了至少10次變化,則執行bgsave
save 60 10000 :當時間到60秒時,如果redis數據發生了至少10000次變化,則執行bgsave--454行--是否開啟RDB文件壓縮
rdbcompression yes
--481行--指定RDB文件名
dbfilename dump.rdb
--504行--指定RDB文件和AOF文件所在目錄
dir /usr/local/redis/data
注意其他自動觸發機制 :
- 在主從復制場景下,如果從節點執行全量復制操作,則主節點會執行bgsave命令,并將rdb文件發送給從節點。
- 執行shutdown命令時,自動執行rdb持久化。
(3) 執行流程
- Redis父進程首先判斷:當前是否在執行save,或bgsave/bgrewriteaof的子進程,如果在執行則bgsave命令直接返回。 bgsave/bgrewriteaof的子進程不能同時執行,主要是基于性能方面的考慮:兩個并發的子進程同時執行大量的磁盤寫操作,可能引起嚴重的性能問題。
- 父進程執行fork操作創建子進程,這個過程中父進程是阻塞的,Redis不能執行來自客戶端的任何命令
- 父進程fork后,bgsave命令返回”Background saving started”信息并不再阻塞父進程,并可以響應其他命令
- 子進程創建RDB文件,根據父進程內存快照生成臨時快照文件,完成后對原有文件進行原子替換
- 子進程發送信號給父進程表示完成,父進程更新統計信息
?
(4)啟動時加載?
RDB文件的載入工作是在服務器啟動時自動執行的,并沒有專門的命令。但是由于AOF的優先級更高,因此當AOF開啟時,Redis會優先載入 AOF文件來恢復數據;只有當AOF關閉時,才會在Redis服務器啟動時檢測RDB文件,并自動載入。服務器載入RDB文件期間處于阻塞狀態,直到載入完成為止。
Redis載入RDB文件時,會對RDB文件進行校驗,如果文件損壞,則日志中會打印錯誤,Redis啟動失敗。
3.AOF持久化
RDB持久化是將進程數據寫入文件,而AOF持久化,則是將Redis執行的每次寫、刪除命令記錄到單獨的日志文件中,查詢操作不會記錄; 當Redis重啟時再次執行AOF文件中的命令來恢復數據。
與RDB相比,AOF的實時性更好,因此已成為主流的持久化方案。
(1)開啟AOF
Redis服務器默認開啟RDB,關閉AOF;要開啟AOF,需要在配置文件中配置:
vim /usr/local/redis/conf/redis.conf
--1380行--修改,開啟AOF
appendonly yes
--1407行--指定AOF文件名稱
appendfilename "appendonly.aof"
--1505行--是否忽略最后一條可能存在問題的指令
aof-load-truncated yessystemctl restart redis-server.service
(2)執行流程
由于需要記錄Redis的每條寫命令,因此AOF不需要觸發,下面介紹AOF的執行流程。
AOF的執行流程包括:
●命令追加(append):將Redis的寫命令追加到緩沖區aof_buf;
●文件寫入(write)和文件同步(sync):根據不同的同步策略默認為everysec(每秒進行一次同步)將 aof_buf中的內容同步到硬盤;
vim /usr/local/redis/conf/redis.conf
--1439--
●appendfsync always: 命令寫入aof_buf后立即調用系統fsync操作同步到AOF文件,
fsync完成后線程返回。這種情況下,每次有寫命令都要同步到AOF文件,硬盤IO成為性能瓶頸,
Redis只能支持大約幾百TPS寫入,嚴重降低了Redis的性能;即便是使用固態硬盤(SSD),
每秒大約也只能處理幾萬個命令,而且會大大降低SSD的壽命。●appendfsync no: 命令寫入aof_buf后調用系統write操作,不對AOF文件做fsync同步;
同步由操作系統負責,通常同步周期為30秒。這種情況下,文件同步的時間不可控,
且緩沖區中堆積的數據會很多,數據安全性無法保證。●appendfsync everysec: 命令寫入aof_buf后調用系統write操作,write完成后線程返回;
fsync同步文件操作由專門的線程每秒調用一次。everysec是前述兩種策略的折中,
是性能和數據安全性的平衡,因此是Redis的默認配置,也是我們推薦的配置。
●文件重寫(rewrite):減少aof文件的占用空間和加快恢復速度,可以配合crontab定時執行bgrewriteaof命令觸發。
注意:文件重寫能夠壓縮AOF文件原因:過期的數據不再寫入文件、無效的命令不再寫入文件、多條命令可以合并為一個,通過上述內容可以看出,由于重寫后AOF執行的命令減少了,文件重寫既可以減少文件占用的空間,也可以加快恢復速度
(3)啟動時加載
當AOF開啟時,Redis啟動時會優先載入AOF文件來恢復數據;只有當AOF關閉時,才會載入RDB文件恢復數據。
當AOF開啟,但AOF文件不存在時,即使RDB文件存在也不會加載。
Redis載入AOF文件時,會對AOF文件進行校驗,如果文件損壞,則日志中會打印錯誤,Redis啟動失敗。但如果是AOF文件結尾不完整(機器突然宕機等容易導致文件尾部不完整),且aof-load-truncated參數開啟,則日志中會輸出警告,Redis忽略掉AOF文件的尾部,啟動成功。aof-load-truncated參數默認是開啟的。
4.RDB和AOF的優缺點和區別(重點!)
1.RDB
優點:RDB持久化保存的文件占用空間較小,網絡傳輸較快,恢復速度比AOF更快,性能影響比AOF更小
?缺點:實時性不如AOF,兼容性較差,持久化期間在fork子進程時會阻塞redis主進程,影響客戶端命令的響應
2.AOF
優點:實時性比RDB更好,支持秒級持久化,兼容性較好
缺點:持久化文件占用空間較大,恢復速度較慢,性能影響更大,AOF文件重寫期間在fork子進程時會阻塞redis主進程,且磁盤IO壓力更大
3.區別?
從 工作方式、實時性、占用空間、恢復速度、兼容性、磁盤IO性能影響描述:
答案:
RDB是定時的將redis在內存的數據進行快照并壓縮保存到硬盤中,
而AOF是實時的以追加的方式將redis寫操作命令記錄到aof文件中,
AOF的實時性比RDB更好,所以AOF保存數據更安全、兼容性也比RDB更好;
因為RDB是快照壓縮保存在硬盤中的,所以占用空間會比AOF小,
網絡傳輸速度和恢復速度都比AOF更快,因為RDB持久化期間在fork子進程時會阻塞redis主進程,
而AOF在重寫期間在fork子進程會阻塞主進程,所以RDB的IO性能比AOF更小一些。
二.Redis 性能管理?
1.查看Redis內存使用
----- 內存碎片率 -----
mem_fragmentation_ratio:內存碎片率。
mem_fragmentation_ratio = used_memory_rss / used_memoryused_memory_rss:是Redis向操作系統申請的內存。
used_memory:是Redis中的數據占用的內存。
used_memory_peak:redis內存使用的峰值。
2.跟蹤內存碎片率
●內存碎片率在1到1.5之間是正常的,這個值表示內存碎片率比較低,也說明 Redis 沒有發生內存交換。
●內存碎片率超過1.5,說明Redis消耗了實際需要物理內存的150%,其中50%是內存碎片率。
●內存碎片率低于1的,說明Redis內存分配超出了物理內存,操作系統正在進行內存交換。需要增加可用物理內存或減少 Redis內存占用。
3.解決碎片率大的問題?
#解決碎片率大的問題:
如果你的Redis版本是4.0以下的,需要在 redis-cli 工具上輸入 shutdown save 命令,
讓 Redis 數據庫執行保存操作并關閉 Redis 服務,再重啟服務器。
Redis服務器重啟后,Redis會將沒用的內存歸還給操作系統,碎片率會降下來。Redis4.0版本開始,可以在不重啟的情況下,線上整理內存碎片。
config set activedefrag yes #自動碎片清理,內存就會自動清理了。
memory purge #手動碎片清理
4.內存使用率
redis實例的內存使用率超過可用最大內存,操作系統將開始進行內存與swap空間交換。
查看Redis內存是否發生Swap
redis-cli info | grep process_id #查看redis進程號
process_id: 5332 #ps aux | grep redis#ss -lntp |grep rediscat /proc/5332/smaps | egrep '^(Swap|Size)'#發生內存 swap 的解決方法:
●設置key的過期時間
●增加 Redis 集群的實例個數,來分攤每個實例服務的數據量,進而減少每個實例所需的內存量
5.內回收key
----- 內回收key -----
內存數據淘汰策略,保證合理分配redis有限的內存資源。當達到設置的最大閥值時,需選擇一種key的回收策略,默認情況下回收策略是禁止刪除。
配置文件中修改 maxmemory-policy 屬性值:
vim /usr/local/redis/conf/redis.conf
--1149--
maxmemory-policy noenviction
●allkeys-lru:不管 key 是否設置了過期,淘汰最近最少訪問的 key
●volatile-lru:只淘汰最近最少訪問、并設置了過期時間的 key
●allkeys-random:不管 key 是否設置了過期,隨機淘汰 key
●volatile-random:只隨機淘汰設置了過期時間的 key
●volatile-ttl:不管 key 是否設置了過期,淘汰即將過期的 key
●no-eviction:不淘汰任何 key,實例內存達到 maxmeory 后,再寫入新數據直接返回錯誤
●allkeys-lfu:不管 key 是否設置了過期,淘汰訪問頻率最低的 key(4.0+版本支持)
●volatile-lfu:只淘汰訪問頻率最低、并設置了過期時間 key(4.0+版本支持)
6.Redis性能優化(重點!!)
1)設置內存上限(maxmemory),并設置內存數據淘汰策略(maxmemory-policy),采用lru算 法淘汰最近最少使用的key
2)給key設置合理的過期時間,盡量避免大量key集中過期
3)合理規劃鍵值的長度,避免存儲大鍵bigkey導致操作延遲(string類型的建議大小在20KB以內。hash、list、set和zset建議控制好閾值,推薦控制元素數量在5000以內)
4)開啟自動內存碎片清理(activedefrag yes)
5)開啟AOF持久化保證數據安全(實時性好),設置AOF文件同步策略appendfsync everysec(秒級同步);開啟混合持久化 aof-use-rdb-preamble yes?
6)開啟lazy free機制(lazyfree-lazy-eviction、lazyfree-lazy-expire、lazyfree-lazy-server-del yes),將刪除過期key的操作放到后臺線程執行,以減少刪除對redis主進程的阻塞
7)盡量使用物理機而非虛擬機部署redis服務,使用高速固態硬盤作為AOF日志的寫入盤
8)使用分布式架構(主從復制、哨兵、集群)實現讀寫分離、分散bigkey來提升讀寫速度,并實現高可用
9)禁用內存大頁 echo never > ?/sys/kernel/mm/transparent_hugepage/enabled ,因為開啟內存大頁會導致fork子進程變慢,大幅增加重寫期間父進程內存消耗,還會拖慢寫操作的執行時間
三.Redis 的三大緩存問題?
前言:正常情況下,大部分的訪問請求應該是先被redis緩存命中響應,在redis那里得不到響應的小部分訪問才會去請求MySQL數據庫獲取數據,這樣MySQL數據庫的負載壓力會非常小,能夠正常穩定工作。
注意:緩存雪崩/穿透/擊穿問題的根本原因是在于redis緩存命中率下降,大量請求會直接發送給MySQL數據庫,導致數據庫負載壓力過大而可能崩潰。
1.緩存雪崩
定義:緩存雪崩是指在短時間內,有大量緩存同時過期,導致大量的請求直接查詢數據庫,從而對數據庫造成了巨大的壓力,嚴重情況下可能會導致數據庫宕機的情況叫做緩存雪崩。
(1)緩存雪崩解決方案?
- 使用隨機數設置緩存key的過期時間,避免緩存集中過期
- 設置二級緩存,除了redis本身的緩存,再設置一層緩存,當redis失效之后,先去查詢二級緩存
- 在應用代碼中使用互斥鎖實現加鎖排隊,緩沖大量請求,防止大量的請求同時操作數據庫(思路:當緩存未查詢到時,對要請求的key進行加鎖,只允許一個線程去數據庫中查,其他線程等候排隊)
2.緩存穿透
定義:大量請求訪問redis和數據庫都不存在數據,因為數據庫查詢無數據,出于容錯考慮,不會將結果保存到緩存中,因此每次請求都會去查詢數據庫,導致最后大量的請求還是直接查詢數據庫,這種情況就叫做緩存穿透。
(1) 緩存穿透解決方案
- 使用布隆過濾器過濾掉一定不存在的無效請求,從而避免了無效請求給數據庫帶來的查詢壓力
- 對空值數據也進行緩存
3.緩存擊穿
定義:?redis中的熱點緩存過期,導致緩存失效,此時又有大量請求訪問這個熱點數據,導致大量的請求直接查詢數據庫,此時這些請求會給數據庫造成巨大的壓力,這種情況就叫做緩存擊穿。
(1)緩存擊穿解決方案?
- 對熱點緩存不設置過期時間,保證緩存的穩定性
- 預先對熱點數據進行緩存預熱
- 在應用代碼中使用互斥鎖實現加鎖排隊,緩沖大量請求,防止大量的請求同時操作數據庫