1. 程式人生 > 程式設計 >?從零開始學Redis之逍遙天境

?從零開始學Redis之逍遙天境

前言

文字已收錄至我的GitHub倉庫,歡迎Star:github.com/bin39232820…
種一棵樹最好的時間是十年前,其次是現在
我知道很多人不玩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指令碼 主從 哨兵 等我們下集再見

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

日常求贊

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

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

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