Redis必備常識理論

Redis 數據類型

Redis支持五種數據類型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。

1、redis.windows.conf 中配置

a、配置密碼

修改 redis.windows.conf 下

Redis必備常識理論

注意:不要帶入其他空格之類的,也可修改 端口 port 6379。修改完後需要生效:

Redis必備常識理論

b、配置RDB快照存放:

Redis必備常識理論

c、AOF設置

Redis必備常識理論

d、設置最大內存

maxmemory 100mb

maxmemory-policy allkeys-lru

maxmemory-samples 5

例如, 要設置 100MB 的內存限制, 可以在 redis.conf 文件中這樣配置: maxmemory 100mb

maxmemory 設置為 0, 則表示不進行內存限制。32位系統有一個隱性的限制條件: 最多 3GB 內存。

LRU(Least Recent Used)是Redis唯一支持的回收算法. 在緩存塊已滿,而需要緩存新的數據塊的時需要從緩存中找到一個“沒有價值”的塊用新的數據塊去替換它。

近似LRU算法

Redis 使用的並不是完全LRU算法。自動驅逐的 key , 並不一定是最滿足LRU特徵的那個. 而是通過近似LRU算法, 抽取少量的 key 樣本, 然後刪除其中訪問時間最古老的那個key。驅逐算法, 從 Redis 3.0 開始得到了巨大的優化, 使用 pool(池子) 來作為候選. 這大大提升了算法效率, 也更接近於真實的LRU算法。

在 Redis 的 LRU 算法中, 可以通過設置樣本(sample)的數量來調優算法精度。 通過以下指令配置: maxmemory-samples 5

為什麼不使用完全LRU實現? 原因是為了節省內存。但 Redis 的行為和LRU基本上是等價的. 下面是 Redis LRU 與完全LRU算法的一個行為對比圖。

Redis必備常識理論

測試過程中, 依次從第一個 key 開始訪問, 所以最前面的 key 才是最佳的驅逐對象。

從圖中可以看到三種類型的點, 構成了三個不同的條帶。

  • 淺灰色部分表示被驅逐的對象。
  • 灰色部分表示 “未被驅逐” 的對象。
  • 綠色部分表示後面加入的對象。

在純粹的LRU算法實現中, 前半部分舊的key被釋放了。而 Redis 的 LRU 算法只是將時間較長的 key 較大概率地(probabilistically)釋放了。

如你所見, Redis 3.0 中, 5樣本的效果比 Redis 2.8 要好很多。 當然, Redis 2.8 也不錯,最後訪問的key基本上都還留在內存中. 在 Redis 3.0 中使用 10 樣本時, 已經非常接近純粹的LRU算法了。

注意,LRU只是用來預測將來可能會繼續訪問某個key的一個概率模型. 此外,如果數據訪問的情況符合冪律分佈(power law), 那麼對於大部分的請求來說, LRU都會表現良好。

在模擬中, 我們發現, 如果使用冪律方式訪問, 純粹的LRU和Redis的結果差別非常, 甚至看不出來。

當然也可以將樣本數量提高到10, 以額外消耗一些CPU為代價, 使得結果更接近於真實的LRU, 並通過 cache miss 統計信息來判斷差異。

設置樣本大小很容易, 使用命令 CONFIG SET maxmemory-samples 即可。

驅逐策略

達到最大內存限制時(maxmemory), Redis 根據 maxmemory-policy 配置的策略, 來決定具體的行為。

當前版本,Redis 3.0 支持的策略包括:

  • noeviction: 不刪除策略, 達到最大內存限制時, 如果需要更多內存, 直接返回錯誤信息。 大多數寫命令都會導致佔用更多的內存(有極少數會例外, 如 DEL )。
  • allkeys-lru: 所有key通用; 優先刪除最近最少使用(less recently used ,LRU) 的 key。
  • volatile-lru: 只限於設置了 expire 的部分; 優先刪除最近最少使用(less recently used ,LRU) 的 key。
  • allkeys-random: 所有key通用; 隨機刪除一部分 key。
  • volatile-random: 只限於設置了 expire 的部分; 隨機刪除一部分 key。
  • volatile-ttl: 只限於設置了 expire 的部分; 優先刪除剩餘時間(time to live,TTL) 短的key。

如果沒有設置 expire 的key, 不滿足先決條件(prerequisites); 那麼 volatile-lru, volatile-randomvolatile-ttl 策略的行為, 和 noeviction(不刪除) 基本上一致。

您需要根據系統的特徵, 來選擇合適的驅逐策略。 當然, 在運行過程中也可以通過命令動態設置驅逐策略, 並通過 INFO 命令監控緩存的 miss 和 hit, 來進行調優。

一般來說:

  • 如果分為熱數據與冷數據, 推薦使用 allkeys-lru 策略。 也就是, 其中一部分key經常被讀寫. 如果不確定具體的業務特徵, 那麼 allkeys-lru 是一個很好的選擇。
  • 如果需要循環讀寫所有的key, 或者各個key的訪問頻率差不多, 可以使用
    allkeys-random 策略, 即讀寫所有元素的概率差不多。
  • 假如要讓 Redis 根據 TTL 來篩選需要刪除的key, 請使用 volatile-ttl 策略。

volatile-lruvolatile-random 策略主要應用場景是: 既有緩存,又有持久key的實例中。 一般來說, 像這類場景, 應該使用兩個單獨的 Redis 實例。

值得一提的是, 設置 expire 會消耗額外的內存, 所以使用 allkeys-lru 策略, 可以更高效地利用內存, 因為這樣就可以不再設置過期時間了。

驅逐的內部實現

驅逐過程可以這樣理解:

  • 客戶端執行一個命令, 導致 Redis 中的數據增加,佔用更多內存。
  • Redis 檢查內存使用量, 如果超出 maxmemory 限制, 根據策略清除部分 key。
  • 繼續執行下一條命令, 以此類推。

在這個過程中, 內存使用量會不斷地達到 limit 值, 然後超過, 然後刪除部分 key, 使用量又下降到 limit 值之下。

如果某個命令導致大量內存佔用(比如通過新key保存一個很大的set), 在一段時間內, 可能內存的使用量會明顯超過 maxmemory 限制。

該段源自:https://blog.csdn.net/ligupeng7929/article/details/79603060

2、Redis持久化存儲

Redis提供了兩種方式:Redis Database 簡稱(RDB) 以及 Append-only file 簡稱(AOF)

a、RDB

定義 : RDB是在某個時間點將數據寫入一個臨時文件,持久化結束後,用這個臨時文件替換上次持久化的文件,達到數據恢復。

問題一: 什麼時間點寫? 通過配置redis在 n 秒內如果超過 m 個key被修改就執行一次RDB操作:保存一次Redis的所有數據(

如果數據量大的話,而且寫操作比較多,必然會引起大量的磁盤io操作,可能會嚴

重影響性能。,稱為快照(snapshots)。snapshot觸發的時機,是有“間隔時間”和“變更次數”共同決定,同時符合2個條件才會觸發snapshot,否則“變更次數”會被繼續累加到下一個“間隔時間”上。

snapshot過程中並不阻塞客戶端請求。snapshot 首先將數據寫入臨時文件,當成功結束後,將臨時文件重名為dump.rdb。

Redis必備常識理論

設置觸發執行快照時間

問題二:如何恢復數據? 自動的持久化數據存儲到dump.rdb後。實際只要重啟redis服務即可完成(啟動redis的server時會從dump.rdb中先同步數據)

客戶端使用命令進行持久化save存儲:

./redis-cli -h ip -p port save

./redis-cli -h ip -p port bgsave

問題三:save與bgsave區別?

  • save 保存是阻塞主進程,客戶端無法連接redis,等SAVE完成後,主進程才開始工作,客戶端可以連接。
  • bgsave 不阻塞相當於異步保存。是fork一個save的子進程,在執行save過程中,不影響主進程,客戶端可以正常鏈接redis,等子進程fork執行save完成後,通知主進程,子進程關閉。很明顯BGSAVE方式比較適合線上的維護操作,兩種方式的使用一定要了解清楚在謹慎選擇。

優點:使用單獨子進程來進行持久化,主進程不會進行任何IO操作,保證了redis的高性能

缺點:RDB是間隔一段時間進行持久化,如果持久化之間redis發生故障,會發生數據丟失。所以這種方式更適合數據要求不嚴謹的時候

b、AOF

Redis必備常識理論

定義: 將“操作 + 數據”以格式化指令的方式追加到操作日誌文件的尾部,在append操作返回後(已經寫入到文件或者即將寫入),才進行實際的數據變更,“日誌文件”保存了歷史所有的操作過程;當server需要數據恢復時,可以直接replay此日誌文件,即可還原所有的操作過程。AOF相對可靠,它和mysql中bin.log、apache.log、zookeeper中txn-log簡直異曲同工。AOF文件內容是字符串,非常容易閱讀和解析。

我們可以簡單的認為AOF就是日誌文件,此文件只會記錄“變更操作”(例如:set/del等),如果server中持續的大量變更操作,將會導致AOF文件非常的龐大,意味著server失效後,數據恢復的過程將會很長;事實上,一條數據經過多次變更,將會產生多條AOF記錄,其實只要保存當前的狀態,歷史的操作記錄是可以拋棄的;因為AOF持久化模式還伴生了“AOF rewrite”(重寫即“壓縮”AOF文件的過程也即是對日誌中命令進行合併重寫)。AOF的特性決定了它相對比較安全,如果你期望數據更少的丟失,那麼可以採用AOF模式。如果AOF文件正在被寫入時突然server失效,有可能導致文件的最後一次記錄是不完整,你可以通過手工或者程序的方式去檢測並修正不完整的記錄,以便通過aof文件恢復能夠正常;同時需要提醒,如果你的redis持久化手段中有aof,那麼在server故障失效後再次啟動前,需要檢測aof文件的完整性。

AOF是文件操作,對於變更操作比較密集的server,那麼必將造成磁盤IO的負荷加重;此外linux對文件操作採取了“延遲寫入”手段,即並非每次write操作都會觸發實際磁盤操作,而是進入了buffer中,當buffer數據達到閥值時觸發實際寫入(也有其他時機),這是linux對文件系統的優化,但是這卻有可能帶來隱患,如果buffer沒有刷新到磁盤,此時物理機器失效(比如斷電),那麼有可能導致最後一條或者多條aof記錄的丟失。通過上述配置文件,可以得知 redis 提供了3種 aof 記錄同步選項:

  • 1.always:每一條aof記錄都立即同步到文件,這是最安全的方式,也以為更多的磁盤操作和阻塞延遲,是IO開支較大。
  • 2.everysec:每秒同步一次,性能和安全都比較中庸的方式,也是redis推薦的方式。如果遇到物理服務器故障,有可能導致最近一秒內aof記錄丟失(可能為部分丟失)。
  • 3.no:redis並不直接調用文件同步,而是交給操作系統來處理,操作系統可以根據buffer填充情況/通道空閒時間等擇機觸發同步;這是一種普通的文件操作方式。性能較好,在物理服務器故障時,數據丟失量會因OS配置有關。

AOF文件會不斷增大,它的大小直接影響“故障恢復”的時間,而且AOF文件中歷史操作是可以丟棄的。AOF rewrite操作就是“壓縮”AOF文件的過程,當然redis並沒有採用“基於原aof文件”來重寫的方式,而是採取了類似snapshot的方式:基於copy-on-write,全量遍歷內存中數據,然後逐個序列到aof文件中。因此AOF rewrite能夠正確反應當前內存數據的狀態,這正是我們所需要的;rewrite過程中,對於新的變更操作將仍然被寫入到原AOF文件中,同時這些新的變更操作也會被redis收集起來(buffer,copy-on-write方式下,最極端的可能是所有的key都在此期間被修改,將會耗費2倍內存),當內存數據被全部寫入到新的aof文件之後,收集的新的變更操作也將會一併追加到新的aof文件中,此後將會重命名新的aof文件為appendonly.aof,此後所有的操作都將被寫入新的aof文件。如果在rewrite過程中,出現故障,將不會影響原AOF文件的正常工作,只有當rewrite完成之後才會切換文件,因為rewrite過程是比較可靠的。AOF rewrite過程並不阻塞客戶端請求。系統會開啟一個子進程來完成。 觸發rewrite的時機可以通過配置文件來聲明,同時redis中可以通過bgrewriteaof指令人工干預。

redis-cli -h ip -p port bgrewriteaof

因為rewrite操作/aof記錄同步/snapshot都消耗磁盤IO,redis採取了“schedule”策略:無論是“人工干預”還是系統觸發,snapshot和rewrite需要逐個被執行。

總結:AOF和RDB各有優缺點,這是有它們各自的特點所決定:

一 、 AOF更加安全,可以將數據更加及時的同步到文件中,但是AOF需要較多的磁盤IO開支,AOF文件尺寸較大,文件內容恢復數度相對較慢。

二 、Snapshot,安全性較差,它是“正常時期”數據備份以及master-slave數據同步的最佳手段,文件尺寸較小,恢復數度較快。

可以通過配置文件來指定它們中的一種,或者同時使用它們(不建議同時使用),或者全部禁用,在架構良好的環境中,master 通常使用AOF,slave使用snapshot,主要原因是master需要首先確保數據完整性,它作為數據備份的第一選擇;slave提供只讀服務(目前slave只能提供讀取服務),它的主要目的就是快速響應客戶端read請求;但是如果你的redis運行在網絡穩定性差/物理環境糟糕情況下,建議你master和slave均採取AOF,這個在master和slave角色切換時,可以減少“人工數據備份”/“人工引導數據恢復”的時間成本;如果你的環境一切非常良好,且服務需要接收密集性的write操作,那麼建議master採取snapshot,而slave採用AOF。同時使用時,服務啟動時,優先加載AOF文件恢復數據。

本文純屬個人學習總結,摘錄官網及網友文章。


分享到:


相關文章: