一、 redis的簡介與安裝
引用:https://www.cnblogs.com/ysocean/tag/Redis%E8%AF%A6%E8%A7%A3/
二、 redis的配置文件介紹
引用:https://www.cnblogs.com/ysocean/tag/Redis%E8%AF%A6%E8%A7%A3/
三、redis的五大數據類型詳細用法
引用:https://www.cnblogs.com/ysocean/tag/Redis%E8%AF%A6%E8%A7%A3/
四、redis的底層數據結構
引用:https://www.cnblogs.com/ysocean/tag/Redis%E8%AF%A6%E8%A7%A3/
五、 redis的五大數據類型實現原理
引用:https://www.cnblogs.com/ysocean/tag/Redis%E8%AF%A6%E8%A7%A3/
六、 持久化
RDB持久化是把當前進程數據生成快照保存到硬盤的過程,觸發RDB持
久化過程分為手動觸發和自動觸發。
配置引用: https://www.cnblogs.com/ysocean/tag/Redis%E8%AF%A6%E8%A7%A3/
RDB的優缺點
優點:
- RDB是一個緊湊壓縮的二進制文件,代表Redis在某個時間點上的數據快照。非常適用於備份,全量復制等場景。比如每6小時執行bgsave備份,並把RDB文件拷貝到遠程機器或者文件系統中(如hdfs),用於災難恢復。
- Redis加載RDB恢復數據遠遠快於AOF的方式。
缺點:
- RDB方式數據沒辦法做到實時持久化/秒級持久化。因為bgsave每次運
行都要執行fork操作創建子進程,屬於重量級操作,頻繁執行成本過高。
- RDB文件使用特定二進制格式保存,Redis版本演進過程中有多個格式的RDB版本,存在老版本Redis服務無法兼容新版RDB格式的問題。
針對RDB不適合實時持久化的問題,Redis提供了AOF持久化方式來解決。
AOF持久化
AOF(append only file)持久化:以獨立日志的方式記錄每次寫命令,重啟時再重新執行AOF文件中的命令達到恢復數據的目的。
AOF的主要作用是解決了數據持久化的實時性,目前已經是Redis持久化的主流方式
配置引用: https://www.cnblogs.com/ysocean/tag/Redis%E8%AF%A6%E8%A7%A3/
AOF的工作流程如下圖:

1)所有的寫入命令會追加到aof_buf(緩沖區)中。
2)AOF緩沖區根據對應的策略向硬盤做同步操作。
3)隨着AOF文件越來越大,需要定期對AOF文件進行重寫,達到壓縮的目的。
4)當Redis服務器重啟時,可以加載AOF文件進行數據恢復。
更詳細的工作原理可以參考書籍【Redis開發與運維(付磊)】
或者參考這篇文章:
https://redisbook.readthedocs...
溫馨提示
場景:AOF文件可能存在結尾不完整的情況,比如機器突然掉電導致AOF尾部文件命令寫入不全。
解決方法:
- 對於錯誤格式的AOF文件,先進行備份,然后采用redis-check-aof --fix命令進行修復,修復后使用diff-u對比數據的差異,找出丟失的數據,有些可以人工修改補全。
- Redis為我們提供了aof-load-truncated配置來兼容這種情況,默認開啟。加載AOF時,當遇到此問題時會忽略並繼續啟動,同時打印如下警告日志:
# !!! Warning: short read while loading the AOF file !!! # !!! Truncating the AOF at offset 397856725 !!! # AOF loaded anyway because aof-load-truncated is enabled
持久化的優化
Redis持久化功能一直是影響Redis性能的高發地。主要有以下方面
1. fork操作
起因:對於高流量的Redis實例OPS可達5萬以上,如果fork操作耗時在秒級別將拖慢Redis幾萬條命令執行,對線上應用延遲影響非常明顯。正常情況下fork耗時應該是每GB消耗20毫秒左右。可以在info stats統計中查latest_fork_usec指標獲取最近一次fork操作耗時,單位微秒。
優化:
1)優先使用物理機或者高效支持fork操作的虛擬化技術,避免使用Xen。
2)控制Redis實例最大可用內存,fork耗時跟內存量成正比,線上建議每個Redis實例內存控制在10GB以內。
3)合理配置Linux內存分配策略,避免物理內存不足導致fork失敗。
4)降低fork操作的頻率,如適度放寬AOF自動觸發時機,避免不必要的全量復制等。
2. CPU
CPU開銷分析。子進程負責把進程內的數據分批寫入文件,這個過程屬於CPU密集操作,通常子進程對單核CPU利用率接近90%。
CPU消耗優化。Redis是CPU密集型服務,不要做綁定單核CPU操作。由於子進程非常消耗CPU,會和父進程產生單核資源競爭。
不要和其他CPU密集型服務部署在一起,造成CPU過度競爭。如果部署多個Redis實例,盡量保證同一時刻只有一個子進程執行重寫工作。
3. 內存
內存消耗優化:
1)同CPU優化一樣,如果部署多個Redis實例,盡量保證同一時刻只有一個子進程在工作。
2)避免在大量寫入時做子進程重寫操作,這樣將導致父進程維護大量頁副本,造成內存消耗。
4. 硬盤
優化方法如下:
a)不要和其他高硬盤負載的服務部署在一起。如:存儲服務、消息隊列服務等。
b)AOF重寫時會消耗大量硬盤IO,可以開啟配置no-appendfsync-on-rewrite,默認關閉。表示在AOF重寫期間不做fsync操作。
c)當開啟AOF功能的Redis用於高流量寫入場景時,如果使用普通機械磁盤,寫入吞吐一般在100MB/s左右,這時Redis實例的瓶頸主要在AOF同步硬盤上。
d)對於單機配置多個Redis實例的情況,可以配置不同實例分盤存儲AOF文件,分攤硬盤寫入壓力。
注:配置no-appendfsync-on-rewrite=yes時,在極端情況下可能丟失整個AOF重寫期間的數據,需要根據數據安全性決定是否配置。
5.AOF追加阻塞
當開啟AOF持久化時,常用的同步硬盤的策略是everysec,用於平衡性能和數據安全性。對於這種方式,Redis使用另一條線程每秒執行fsync同步硬盤。當系統硬盤資源繁忙時,會造成Redis主線程阻塞,

阻塞流程分析:
1)主線程負責寫入AOF緩沖區。
2)AOF線程負責每秒執行一次同步磁盤操作,並記錄最近一次同步時間。
3)主線程負責對比上次AOF同步時間:如果距上次同步成功時間在2秒內,主線程直接返回。如果距上次同步成功時間超過2秒,主線程將會阻塞,直到同步操作完成。
優化AOF追加阻塞問題主要是優化系統硬盤負載,優化方法參考第4點
七、事務
為了保證多條命令組合的原子性,Redis提供了簡單的事務功能以及集成Lua腳本來解決這個問題。簡單介紹Redis中事務的使用方法以及它的局限性。
127.0.0.1:6379> multi OK 127.0.0.1:6379> sadd user:a:follow user:b QUEUED 127.0.0.1:6379> zadd user:b:fans 1 user:a QUEUED 127.0.0.1:6379> exec 1) (integer) 1 2) (error) WRONGTYPE Operation against a key holding the wrong kind of value 127.0.0.1:6379> sismember user:a:follow user:b (integer) 1
Redis提供了簡單的事務功能,**將一組需要一起執行的命令放到multi和
exec兩個命令之間**。
multi命令代表事務開始。
exec命令代表事務結束。
它們之間的命令是原子順序執行的。
它不支持事務中的回滾特性。
Lua腳本
基本語法教程可參考下面這個網址:
https://www.runoob.com/lua/lu...
在Redis中執行Lua腳本有兩種方法:eval和evalsha。
八、發布訂閱
Redis提供了基於“發布/訂閱”模式的消息機制,此種模式下,消息發布
者和訂閱者不進行直接通信,發布者客戶端向指定的頻道(channel)發布消息,訂閱該頻道的每個客戶端都可以收到該消息。

- 發布消息
publish channel:sports "Tim won the championship"
- 訂閱消息
subscribe channel:sports
有關訂閱命令有兩點需要注意:
- 客戶端在執行訂閱命令之后進入了訂閱狀態,只能接收subscribe、
psubscribe、unsubscribe、punsubscribe的四個命令。
- 新開啟的訂閱客戶端,無法收到該頻道之前的消息,因為Redis不會對
發布的消息進行持久化。
Redis發布訂閱與成熟MQ的比較
(1)MQ支持多種消息協議,包括AMQP,MQTT,Stomp等,並且支持JMS規范,但Redis沒有提供對這些協議的支持;
(2)MQ提供持久化功能,但Redis無法對消息持久化存儲,一旦消息被發送,如果沒有訂閱者接收,那么消息就會丟失;
(3)MQ提供了消息傳輸保障,當客戶端連接超時或事務回滾等情況發生時,消息會被重新發送給客戶端,Redis沒有提供消息傳輸保障。
總之,MQ所提供的功能遠比Redis發布訂閱要復雜,畢竟Redis不是專門做發布訂閱的,但是如果系統中已經有了Redis,並且需要基本的發布訂閱功能,就沒有必要再安裝MQ了,因為可能MQ提供的功能大部分都用不到,而且你可以容忍redis發布訂閱的缺點的話,可以考慮用它。
九、主從復制及哨兵模式
配置引用:https://www.cnblogs.com/ysocean/tag/Redis%E8%AF%A6%E8%A7%A3/
主節點Master 只有一個,一旦主節點掛掉之后,從節點沒法擔起主節點的任務,那么整個系統也無法運行。如果主節點掛掉之后,從節點能夠自動變成主節點,那么問題就解決了,於是哨兵模式誕生了。
哨兵模式就是不時地監控redis是否按照預期良好地運行(至少是保證主節點是存在的),若一台主機出現問題時,哨兵會自動將該主機下的某一個從機設置為新的主機,並讓其他從機和新主機建立主從關系。
十、redis雪崩、擊穿、穿透
https://www.toutiao.com/i6755313319684342276/?tt_from=weixin&utm_campaign=client_share&wxshare_count=1&from=singlemessage×tamp=1572913492&app=news_article&utm_source=weixin&utm_medium=toutiao_android&req_id=2019110508245201000804313323AE21C8&group_id=6755313319684342276
1、redis雪崩效應
由於redis設置失效時間,當所有key在同一時間失效,並發直接打入DB,導致DB崩潰。
舉個簡單的例子:如果所有首頁的Key失效時間都是12小時,中午12點刷新的,我零點有個秒殺活動大量用戶涌入,假設當時每秒 6000 個請求,本來緩存在可以扛住每秒 5000 個請求,但是緩存當時所有的Key都失效了。此時 1 秒 6000 個請求全部落數據庫,數據庫必然扛不住,它會報一下警,真實情況可能DBA都沒反應過來就直接掛了。此時,如果沒用什么特別的方案來處理這個故障,DBA 很着急,重啟數據庫,但是數據庫立馬又被新的流量給打死了。這就是我理解的緩存雪崩。
我刻意看了下我做過的項目感覺再吊的都不允許這么大的QPS直接打DB去,不過沒慢SQL加上分庫,大表分表可能還還算能頂,但是跟用了Redis的差距還是很大。
解決:
處理緩存雪崩簡單,在批量往Redis存數據的時候,把每個Key的失效時間都加個隨機值就好了,這樣可以保證數據不會在同一時間大面積失效,我相信,Redis這點流量還是頂得住的。
如果Redis是集群部署,將熱點數據均勻分布在不同的Redis庫中也能避免全部失效的問題,不過本渣我在生產環境中操作集群的時候,單個服務都是對應的單個Redis分片,是為了方便數據的管理,但是也同樣有了可能會失效這樣的弊端,失效時間隨機是個好策略。
或者設置熱點數據永遠不過期,有更新操作就更新緩存就好了(比如運維更新了首頁商品,那你刷下緩存就完事了,不要設置過期時間),電商首頁的數據也可以用這個操作,保險。
2、緩存穿透
緩存穿透是指緩存和數據庫中都沒有的數據,而用戶不斷發起請求,我們數據庫的 id 都是1開始自增上去的,如發起為id值為 -1 的數據或 id 為特別大不存在的數據。這時的用戶很可能是攻擊者,攻擊會導致數據庫壓力過大,嚴重會擊垮數據庫。
解決:
接口層增加校驗,比如用戶鑒權校驗,參數做校驗,不合法的參數直接代碼Return
3、緩存擊穿
這個跟緩存雪崩有點像,但是又有一點不一樣,緩存雪崩是因為大面積的緩存失效,打崩了DB,而緩存擊穿不同的是緩存擊穿是指一個Key非常熱點,在不停的扛着大並發,大並發集中對這一個點進行訪問,當這個Key在失效的瞬間,持續的大並發就穿破緩存,直接請求數據庫,就像在一個完好無損的桶上鑿開了一個洞。
解決:
從緩存取不到的數據,在數據庫中也沒有取到,這時也可以將對應Key的Value對寫為null、位置錯誤、稍后重試這樣的值具體取啥問產品,或者看具體的場景,緩存有效時間可以設置短點,如30秒(設置太長會導致正常情況也沒法使用)。
這樣可以防止攻擊用戶反復用同一個id暴力攻擊,但是我們要知道正常用戶是不會在單秒內發起這么多次請求的,那網關層Nginx本渣我也記得有配置項,可以讓運維大大對單個IP每秒訪問次數超出閾值的IP都拉黑。
總結:
- 事前:Redis 高可用,主從+哨兵,Redis cluster,避免全盤崩潰。
- 事中:本地 ehcache 緩存 + Hystrix 限流+降級,避免MySQL 被打死。
- 事后:Redis 持久化 RDB+AOF,一旦重啟,自動從磁盤上加載數據,快速恢復緩存數據。
