redis集羣

轉自:https://blog.csdn.net/Tmeng521/article/details/91039391

具體實現地址本篇文件是基於網絡上知識的整合

redis 是一個基於內存的高性能 key-value數據庫

支持豐富的數據類型(String,List , Set ,Sorted Set,Hash  )

redis中的單個value的存儲限制是1G,比 Memcached的1MB要強大太多

哎呀,還是以問答的方式來寫這篇文章吧!

1.redis有什麼優缺點

redis是內存數據庫,所以當數據量達到一定程度的時候,單機版的必然是其瓶頸所在,這個時候我們就需要引入主從複製方案,用了主從複製之後我們就會發現,主庫值負責讀寫,從庫負責讀,數據量達到千萬級的時候寫的庫還是扛不住,所以就更加深入的使用了集羣。

2.redis的線程模型

redis內部使用的是文件事件處理器方式(file event handler)它是一個單線程的,所以redis也是單線程模型的關於這個文件事件處理器方式可參照下圖

此圖形象的標出了redis存儲原理

  • 客戶端 socket01 向 redis 的 server socket 請求建立連接,此時 server socket 會產生一個 AE_READABLE 事件,IO 多路複用程序監聽到 server socket 產生的事件後,將該事件壓入隊列中。文件事件分派器從隊列中獲取該事件,交給連接應答處理器。連接應答處理器會創建一個能與客戶端通信的 socket01,並將該 socket01 的 AE_READABLE 事件與命令請求處理器關聯。
  • 假設此時客戶端發送了一個 set key value 請求,此時 redis 中的 socket01 會產生 AE_READABLE 事件,IO 多路複用程序將事件壓入隊列,此時事件分派器從隊列中獲取到該事件,由於前面 socket01 的 AE_READABLE 事件已經與命令請求處理器關聯,因此事件分派器將事件交給命令請求處理器來處理。命令請求處理器讀取 socket01 的 key value 並在自己內存中完成 key value 的設置。操作完成後,它會將 socket01 的 AE_WRITABLE 事件與令回覆處理器關聯。

  • 如果此時客戶端準備好接收返回結果了,那麼 redis 中的 socket01 會產生一個 AE_WRITABLE 事件,同樣壓入隊列中,事件分派器找到相關聯的命令回覆處理器,由命令回覆處理器對 socket01 輸入本次操作的一個結果,比如 ok,之後解除 socket01 的 AE_WRITABLE 事件與命令回覆處理器的關聯。

很簡單,多讀幾篇,就可理解。

3.爲什麼redis單線程效率也能那麼高

3.1.純內存操作,數據什麼的都存在服務器內存中(使用的時候要注意設置服務器可分不配給redis的內存大小,並且根據業務使用持久化機制)

3.2.非阻塞的IO多路複用機制

3.3.單線程避免了多線程情況下的上下文切換問題(內部使用了隊列技術,避免了傳統DB控制串行的開銷)

4.redis有幾種持久化方式

 4.1RDB

rdb是全量持久化,是在配置文件中指定持久化的間隔時間,然後將內存中的數據集快照寫入磁盤,實際操作是fork一個子進程然後將數據集寫入一個臨時磁盤,字後覆蓋掉以前的數據集文件。

優點,可以靈活的設置備份頻率和週期因爲是自己設置的,並且因爲備份的一個數據集文件,所以當redis宕機的時候很容易就可以備份,內部使用了一個子進程所以在持久化的時候可以保證redis的高性能。恢復數據比AOF要快

缺點 :因爲rdb是以時間爲單位存儲的,比如每5分鐘寫一次,那麼在第4分鐘59秒的時候redis服務器宕機了那麼在這4分多鐘裏面的數據就會丟失。嚴重還是影響蠻大的。

 4.2AOF

aof可以帶來更高的數據安全性,aof中有3中同步策略,(1.每秒同步 2.沒執行一個修改命令就同步3.不同步)

每秒同步是異步執行了,效率高但如果redis宕機了那麼那一秒的數據就丟了

每修改同步。redis中每次有寫的操作,都會同步到磁盤,效率比上面的每秒同步要低一些,但是極度安全

持久化的時候採用的是append的方式,由此可見恢復策略做的比較好,不會出現持久化文件錯亂問題,並且這個寫入磁盤的效率是非常之高,沒有磁盤尋址操作(kafka的消息存儲也是這個乾的,追加寫的形式)

如果日誌過大,Redis可以自動啓用 rewrite 機制。即使出現後臺重寫操作,也不會影響客戶端的讀寫。因爲在 rewrite log 的時候,會對其中的指令進行壓縮,創建出一份需要恢復數據的最小日誌出來。

缺點

同數據量下aof文件比rdb文件要大的多,因爲它記錄的是所有的寫指令,並且恢復速度也慢一點

總結:使用的時候可以同時開啓兩種持久化方式,利用aof來保證數據不丟失,在aof無法使用的時候,在用reb的備份文件做替補恢復,在兩種模式都開啓的情況下,默認採取aof來進行數據恢復

AOF設計實現

RDB設計實現

5.redis有幾種數據過期策略

5.1被動刪除:當讀/寫 一個過期的key時,會觸發惰性刪除策略,直接刪除這個key

5.2主動刪除由於惰性策略無法保證冷數據已經被刪除,所以redis會定期主動刪除一些已過期的key,或者當內存達到爲redis服務器設置的最大內存的時候,會主動的刪除一些數據(觸發數據淘汰策略)

寫的不錯的關於過期策越的文章

6.什麼是redis的數據淘汰策略

  1. volatile-lru
  2. volatile-ttl
  3. volatile-random
  4. allkeys-lru
  5. allkeys-random
  6. no-enviction

形象生動的說明了幾種策略的用法

7. MySQL 裏有 2000w 數據,Redis 中只存 20w 的數據,如何保證 Redis 中的數據都是熱點數據?

設置過期策略爲volatile-lru 或者allkeys-lru 這樣就會刪除不常用的,留下來的就是熱點數據了。

8.redis回收進程工作原理

1.在寫入redis之前查看是已經達到最大內存了,如果達到了就走數據淘汰策略,然後在寫入

9.redis如何解決緩存雪崩,緩存穿透,緩存擊穿

緩存雪崩呢就表示 在某個時間段設置了過期時間的key都一起失效了,那麼db肯定扛不住那麼大的併發量,可能會崩潰,所以我們在設置一些熱點key的時候,要儘量設置不同的過期時間,以避免在高併發的情況下緩存雪崩問題

緩存穿透呢 從字面上理解就是因爲每次做查詢請求的時候無法從緩存中查詢,從而直接將請請求落入DB,剛好db中也沒這條數據,那麼返回的就是null,就不會放入緩存中,周而復始知道db炸裂。 這種方案簡單粗暴的解決方式就是當db中查詢爲null的時候自己給個設置過期時間 的默認值,從而解決掉這種查詢直接到達db的頻率

緩存擊穿,某個熱點key突然過期了,那麼必然會導致,大量的請求入db那麼db就會扛不住壓力,涼涼。解決方案設置鎖,如果是分佈式系統就設置分佈式鎖。

10.redis如何實現分佈式鎖呢

代碼地址

實際上要理解的原理就是 設置key的過期時間,然後有請求到來的時候,去redis寫入這個key,如果這個key已經被寫入redis說明此鎖已經被佔用了,那麼就循環就如等待,上一個佔用鎖的人,在處理完邏輯後會釋放掉鎖,那麼下一個人就可以獲取這個鎖瞭然後執行自己的邏輯,總結來就是分佈式系統下的強制串行操作。

11.redis使用場景

1數據緩存(不做過多介紹)

2.手機驗證碼多長時間過期(可通過設置key的過期時間實現)

3.積分排行(設置key的過期時間,然後定時做統計)

4.計算器(單線程計數,不考慮併發情況下的數據不一致問題)

5.限流(通過設置某個ip的在1分鐘內訪問次數,來達到限流效果)

6.消息隊列

7.分佈式鎖

8.熱門列表(根據訪問次數來進行統計)

9.限制登錄次數(如果密碼錯了就計算1次,設置一個過期時間,連錯5次就鎖定此賬號)

10.唯一登錄,在系統登錄成功後記錄這個賬號信息,如果此賬號在其他地方又登錄,就清除某個token信息

11.token信息保存,剛好對應sprong-session中的核心處理

12.後續關於

主從複製的原理和實現

哨兵機制的原理和實現

redis事務的原理和實現

發佈訂閱機制的原理和實現

rdb和aof和實現

以及幾個使用場景的實現

https://github.com/LxyTe/redis

13記錄一點關於redis和db的數據一致性問題。

這個問題讀者應該在面試的時候都會被問題,其實這個已經涉及到了兩個數據庫了,已經算作分佈式事務的領域了。下面來說下解決方案。

方案一 沒有使用MQ的系統(併發寫量小的系統 )

先更新數據庫,數據庫更新完成之後,更新緩存(直接將結果給緩存不在查詢db)。(直接更新,不是刪除),缺點,數據庫如若成功,redis更新失敗,數據就不一致了。

方案二 使用了MQ的系統

先更新數據庫,數據庫更新成功返回狀態,然後把更新redis的操作使用MQ異步發出,然後使用MQ的消費者機制來保證一定會消費,從而避免由redis更新失敗帶來 數據不一致。(直接將結果給緩存不在查詢db)

方案三(併發量特別大的情況(這裏的併發只的是併發寫。),如果一個key的修改頻率大於查詢,那麼就要考慮這個key是否 適合緩存)

這個時候使用方案二會出現一個弊端,那就是在你使用MQ消費的時候是肯定存在延遲的,這個時候如果db的值已經改變那麼就會造成數據不一致,那麼這個時候第二步的做法就可以修改爲 消息到達mq只有,從db中查詢一次,然後將結果重新放在redis中

方案四 沒有使用MQ,系統併發量寫太大,但是併發讀不是很大,因爲刪緩存,併發讀又太大那麼容易造成緩存穿透)

那麼可以直接使用先更新數據庫,然後刪除緩存(等緩存使用的時候,從db中查詢,按需加載)

方案五 併發寫很大,併發讀也很大(秒殺系統(下單,那麼就要減庫存,下單前要判斷是否還與庫存))

此種解決方案的核心點是限流,通過各種限流將併發量減小,如果達到db能承受的範圍,在達到db能承受的範圍之後,將請求下放的數據庫層,然後先減去庫存,然後修改成功,在修改redis的數值(實際上的做法是先在redis層做限流,然後減去redis的庫存,然後再到db去修改。那麼這個時候就不用管redis的庫存了。)

總結:redis和db的數據一致性在不同的情景下有不同的做法,上面的五種場景第1種是用的最多的,如果對數據一致性比較重視,那麼可以用第二種,第三種的使用場景適用於少量寫,大量讀,情況下,數據的相對一致性。

   分佈式系統下的數據一致性其實是可以有一點不一致的(據說12306那種級別的網站,也是在每天晚上的時候,做一次數據同步,將db中的數據,重新刷到緩存中,爲什麼要重新呢,這裏就不多解釋了吧,肯定是db和緩存數據不一致呀),因爲分佈式系統訪問的時候肯定會出現網絡延遲,有網絡延遲,肯定會出現數據不一致,以前有個同學和我說過, 如果你的系統連一點點數據一致性偏差都不能承受,那你還玩什麼分佈式系統呢。

14.如何解決rediskey傾斜問題

什麼是熱點key傾斜?就是在redis集羣中某個節點一直承受這大量的查詢操作,壓力非常大,而其他節點壓力都較小。這個時候需要解決這個壓力太大的問題

 解決思路有兩種

    1.在將一些特別熱點的key直接放在客戶端進行存儲,設置過期時間,過期後從後臺查詢。

  2.上面的方法可以解決熱點key的傾斜問題,但是如果存儲在前端的數據在同一個時間都過期了呢,那麼還是有大量的請求到達redis的某一個節點,這個時候我們可以將一個熱點key 複製出多分子key,每個子key的value值一樣,查詢的時候使用hash取模算法,將壓力分配到不同的節點

 

               

 

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