從零開始學Redis之逍遙天境

前言

文本已收錄至我的GitHub倉庫,歡迎Star:https://github.com/bin392328206/six-finger
種一棵樹最好的時間是十年前,其次是現在
我知道很多人不玩qq了,但是懷舊一下,歡迎加入六脈神劍Java菜鳥學習羣,羣聊號碼:549684836 鼓勵大家在技術的路上寫博客

絮叨

逍遙天境 以天道爲武力,一刀一劍有萬物與之呼應。
這是進階篇哦,如果要去看基礎的話建議看我下面的鏈接:
🔥從零開始學Redis之金剛凡境
🔥從零開始學Redis之自在地境
第一篇基礎的概率很多 估計大家看得想睡覺 第二篇的乾貨確實很多 值得深刻研究
這篇的乾貨也不少的

這篇主要寫redis的淘汰算法 持久化

Redis的淘汰策略

如果你的 Redis 只能存8G數據,你寫了11G,那麼 Redis 會怎麼淘汰那3G數據呢?
redis.conf 中的過期淘汰配置 看下源碼的配置

# MAXMEMORY POLICY: how Redis will select what to remove when maxmemory
# is reached. You can select among five behaviors:
#最大內存策略:當到達最大使用內存時,你可以在下面5種行爲中選擇,Redis如何選擇淘汰數據庫鍵

#當內存不足以容納新寫入數據時

# volatile-lru -> remove the key with an expire set using an LRU algorithm
# volatile-lru :在設置了過期時間的鍵空間中,移除最近最少使用的key。這種情況一般是把 redis 既當緩存,又做持久化存儲的時候才用。

# allkeys-lru -> remove any key according to the LRU algorithm
# allkeys-lru : 移除最近最少使用的key (推薦)

# volatile-random -> remove a random key with an expire set
# volatile-random : 在設置了過期時間的鍵空間中,隨機移除一個鍵,不推薦

# allkeys-random -> remove a random key, any key
# allkeys-random : 直接在鍵空間中隨機移除一個鍵,弄啥叻

# volatile-ttl -> remove the key with the nearest expire time (minor TTL)
# volatile-ttl : 在設置了過期時間的鍵空間中,有更早過期時間的key優先移除 不推薦

# noeviction -> don't expire at all, just return an error on write operations
# noeviction : 不做過鍵處理,只返回一個寫操作錯誤。 不推薦

# Note: with any of the above policies, Redis will return an error on write
#       operations, when there are no suitable keys for eviction.
# 上面所有的策略下,在沒有合適的淘汰刪除的鍵時,執行寫操作時,Redis 會返回一個錯誤。下面是寫入命令:
#       At the date of writing these commands are: set setnx setex append
#       incr decr rpush lpush rpushx lpushx linsert lset rpoplpush sadd
#       sinter sinterstore sunion sunionstore sdiff sdiffstore zadd zincrby
#       zunionstore zinterstore hset hsetnx hmset hincrby incrby decrby
#       getset mset msetnx exec sort

# 過期策略默認是:
# The default is:
# maxmemory-policy noeviction

  • noeviction:當內存不足以容納新寫入數據時,新寫入操作會報錯。
  • allkeys-lru:當內存不足以容納新寫入數據時,在鍵空間中,移除最近最少使用的key。
  • allkeys-random:當內存不足以容納新寫入數據時,在鍵空間中,隨機移除某個key。
  • volatile-lru:當內存不足以容納新寫入數據時,在設置了過期時間的鍵空間中,移除最近最少使用的key。
  • volatile-random:當內存不足以容納新寫入數據時,在設置了過期時間的鍵空間中,隨機移除某個key。
  • volatile-ttl:當內存不足以容納新寫入數據時,在設置了過期時間的鍵空間中,有更早過期時間的key優先移除。

其實我覺得用volatile-lru就好了 畢竟報錯是完全沒有必要的 還有就是設置一個報警裝置 如果不夠了 就搞主從 哈哈

Redis的持久化方式

Redis爲持久化提供了兩種方式:

  • RDB:在指定的時間間隔能對你的數據進行快照存儲。
  • AOF:記錄每次對服務器寫的操作,當服務器重啓的時候會重新執行這些命令來恢復原始的數據。

爲了使用持久化的功能,我們需要先知道該如何開啓持久化的功能。在redis.conf 中有下面的配置:

RDB的配置

# 時間策略
save 900 1
save 300 10
save 60 10000

# 文件名稱
dbfilename dump.rdb

# 文件保存路徑
dir /home/work/app/redis/data/

# 如果持久化出錯,主進程是否停止寫入
stop-writes-on-bgsave-error yes

# 是否壓縮
rdbcompression yes

# 導入時是否檢查
rdbchecksum yes

save 900 1 表示900s內如果有1條是寫入命令,就觸發產生一次快照,可以理解爲就進行一次備份
save 300 10 表示300s內有10條寫入,就產生快照

下面的類似,那麼爲什麼需要配置這麼多條規則呢?因爲Redis每個時段的讀寫請求肯定不是均衡的,爲了平衡性能與數據安全,我們可以自由定製什麼情況下觸發備份。所以這裏就是根據自身Redis寫入情況來進行合理配置。

stop-writes-on-bgsave-error yes
這個配置也是非常重要的一項配置,這是當備份進程出錯時,主進程就停止接受新的寫入操作,是爲了保護持久化的數據一致性問題。如果自己的業務有完善的監控系統,可以禁止此項配置, 否則請開啓。

關於壓縮的配置 rdbcompression yes ,建議沒有必要開啓,畢竟Redis本身就屬於CPU密集型服務器,再開啓壓縮會帶來更多的CPU消耗,相比硬盤成本,CPU更值錢。

當然如果你想要禁用RDB配置,也是非常容易的,只需要在save的最後一行寫上:save “”, 默認是開啓的。

RDB的原理

在Redis中RDB持久化的觸發分爲兩種:自己手動觸發與Redis定時觸發。
針對RDB方式的持久化,手動觸發可以使用:

- save:會阻塞當前Redis服務器,直到持久化完成,線上應該禁止使用。
- bgsave:該觸發方式會fork一個子進程,由子進程負責持久化過程,因此阻塞只會發生在fork子進程的時候。

而自動觸發的場景主要是有以下幾點:

- 根據我們的 save m n 配置規則自動觸發;
- 從節點全量複製時,主節點發送rdb文件給從節點完成複製操作,主節點會觸發 bgsave;
- 執行 shutdown時,如果沒有開啓aof,也會觸發。

由於 save 基本不會被使用到,我們重點看看 bgsave 這個命令是如何完成RDB的持久化的。

這裏注意的是 fork 操作會阻塞,導致Redis讀寫性能下降。我們可以控制單個Redis實例的最大內存,來儘可能降低Redis在fork時的事件消耗。以及上面提到的自動觸發的頻率減少fork次數,或者使用手動觸發,根據自己的機制來完成持久化。

保存已經會了,接下來我看看如何恢復數據-> 將備份文件複製到Redis的暗安裝目錄下,然後重新啓動服務。

AOF的配置

# 是否開啓aof
appendonly yes

# 文件名稱
appendfilename "appendonly.aof"

# 同步方式
appendfsync everysec

# aof重寫期間是否同步
no-appendfsync-on-rewrite no

# 重寫觸發配置
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

# 加載aof時如果有錯如何處理
aof-load-truncated yes

# 文件重寫策略
aof-rewrite-incremental-fsync yes

還是重點解釋一些關鍵的配置:

appendfsync everysec 它其實有三種模式:

  • always:把每個寫命令都立即同步到aof,很慢,但是很安全
  • everysec:每秒同步一次,是折中方案(默認也是這個)
  • no:redis不處理交給OS來處理,非常快,但是也最不安全

AOF的原理

AOF的整個流程大體來看可以分爲兩步,一步是命令的實時寫入(如果是 appendfsync everysec 配置,會有1s損耗),第二步是對aof文件的重寫。

對於增量追加到文件這一步主要的流程是:命令寫入=》追加到aof_buf =》同步到aof磁盤。那麼這裏爲什麼要先寫入buf在同步到磁盤呢?如果實時寫入磁盤會帶來非常高的磁盤IO,影響整體性能。

aof重寫是爲了減少aof文件的大小,可以手動或者自動觸發,關於自動觸發的規則請看上面配置部分。fork的操作也是發生在重寫這一步,也是這裏會對主進程產生阻塞。

手動觸發: bgrewriteaof,自動觸發 就是根據配置規則來觸發,當然自動觸發的整體時間還跟Redis的定時任務頻率有關係。

數據的備份、持久化做完了,我們如何從這些持久化文件中恢復數據呢?如果一臺服務器上有既有RDB文件,又有AOF文件,該加載誰呢?

啓動時會先檢查AOF文件是否存在,如果不存在就嘗試加載RDB。那麼爲什麼會優先加載AOF呢?因爲AOF保存的數據更完整,通過上面的分析我們知道AOF基本上最多損失1s的數據。

Redis持久化的性能優化

通過上面的分析,我們都知道RDB的快照、AOF的重寫都需要fork,這是一個重量級操作,會對Redis造成阻塞。因此爲了不影響Redis主進程響應,我們需要儘可能降低阻塞。

- 降低fork的頻率,比如可以手動來觸發RDB生成快照、與AOF重寫;
- 控制Redis最大使用內存,防止fork耗時過長;
- 使用更牛逼的硬件;
- 合理配置Linux的內存分配策略,避免因爲物理內存不足導致fork失敗。

一些線上經驗

- 如果Redis中的數據並不是特別敏感或者可以通過其它方式重寫生成數據,可以關閉持久化,如果丟失數據可以通過其它途徑補回;
- 自己制定策略定期檢查Redis的情況,然後可以手動觸發備份、重寫數據;
- 可以加入主從機器,利用一臺從機器進行備份處理,其它機器正常響應客戶端的命令;

結尾

redis 今天的內存淘汰策略和持久化就講這麼多,本來我想多寫點,但是一篇文章怕大家看得累 就寫短點吧
哈哈 後面還有 lua腳本 主從 哨兵 等我們下集再見

因爲博主也是一個開發萌新 我也是一邊學一邊寫 我有個目標就是一週 二到三篇 希望能堅持個一年吧 希望各位大佬多提意見,讓我多學習,一起進步。

日常求贊

好了各位,以上就是這篇文章的全部內容了,能看到這裏的人呀,都是人才

創作不易,各位的支持和認可,就是我創作的最大動力,我們下篇文章見

六脈神劍 | 文 【原創】如果本篇博客有任何錯誤,請批評指教,不勝感激 !

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章