1. 程式人生 > 其它 >Redis基礎知識掃盲

Redis基礎知識掃盲

redis基礎知識掃盲

1. redis有哪些資料結構?其底層又是如何實現的?

基礎資料結構:

  • String

    • 字串物件
    • 底層實現
      • int : 整數值實現
      • 短字串:embstr編碼,sds實現
      • 長字串:raw編碼,sds實現
  • List

    • 列表物件
    • 底層實現
      • ziplist 壓縮列表

        • 圖例
      • linkedlist 雙端列表

        • 圖例
      • 滿足特定條件的物件才使用ziplist實現,否則使用linkedlist實現

  • Hash

    • 雜湊物件
    • 底層實現
      • ziplist 壓縮列表
        • 圖例
      • hashtable 雜湊表,其底層採用字典實現
        • 圖例
      • 滿足特定條件的物件才使用ziplist實現,否則使用hashtable實現
  • Set

    • 集合物件
    • 底層實現
      • 整數集合 intset實現
        • 圖例
      • 非整數集合 hashtable實現,底層同樣是dict
        • 圖例
      • 滿足特定條件的物件使用intset實現,否則使用hashtable實現
  • SortedSet

    • 有序集合物件
    • 底層實現
      • ziplist
        • 樣例
      • skiplist編碼,底層包含一個skiplist和dict
        • 樣例

大致總結一下:

高階資料結構:

  • HyperLogLog

    • 作用: 以極小的記憶體佔用提供稍微不精準的去重基數統計。
    • 在redis中,只需要12kb就可以統計2^64個數據,
    • 計數存在一定的誤差,誤差率整體較低。標準誤差為 0.81%
  • Geo

    • 用於計算地理位置資訊相關的一些功能(比如附近的人),其底層依然採用sortedSet實現
    • redis使用業界通用的地理位置距離排序演算法GeoHash演算法
    • GeoHash演算法將二維經緯度資料對映到一維整數,這樣所有的元素都將掛載到一條線上距離相近的二維點對映到一維也會相近,然後再用有序set排序,就可實現附近的人功能
  • Pub/Sub

    • 釋出與訂閱
    • 在redis中,你可以對某一個key值進行訊息釋出和訂閱,當一個key值進行了訊息釋出之後,所有訂閱它的客戶端都會收到相應的訊息。

Redis Moudle:

  • RedisBloom:分散式環境下的布隆過濾器

    • 布隆過濾器
      • 作用:用於檢索一個元素是否在一個合集中,它的優點是空間效率高,查詢時間少,缺點是有一定的誤識別率和無法刪除
      • 原理:當一個元素被加入合集時,通過K個雜湊函式將元素對映成一個位數組中的K個點,將他們置為1,檢索時,只需要看這些點是不是1就知道它是否在集合中,如果這些點,有任何一個為0,則被檢元素一定不在,如果都是1,則被檢元素很有可能存在。
      • 應用:
        • 主要用於防止快取擊穿,避免每次請求都不走快取直接打到資料庫。
        • 布隆過濾器可以明確某個資料在資料庫是否存在,所以可以過濾掉無效的查詢到資料庫,減小資料庫的壓力。
  • RedisSearch:全文檢索元件,適合資料量適中,記憶體和儲存有限的快取。

2. redis的分散式鎖是怎麼回事?

  • 先用setnx來爭搶鎖,搶到之後,再用expire給鎖加一個過期時間防止鎖忘了釋放。
  • 並且set有非常複雜的引數,可以將setnx和expire合成一條指令來使用,不用擔心setnx之後expire之前,程序意外crash或者重啟維護了

setnx: 如果不存在,則set

3. 假如redis裡有一億個key,10w個key是固定字首,如何將他們全部找出?

keys指令可以掃出指定模式的key列表

4. 如果redis正在給線上服務提供服務,使用keys指令會有什麼問題?

  • reids是單執行緒的,keys指令會導致執行緒阻塞一段時間,線上服務會停頓,直到keys指令執行完畢,服務才能恢復
  • 這個時候可以採用scan指令,scan指令可以無阻塞的提取出指定模式的key列表,但有一定概率重複(scan是增量式的迭代命令),在客戶端做一次去重就ok了,但比單keys命令耗時長。

5. 如何使用redis實現非同步佇列?

  • 方式1:生產者消費者模式
    • 使用list結構做佇列,rpush生產訊息,lpop消費訊息,當lpop沒有訊息時,適當的sleep一會再重試,避免過高qps,或者直接使用blpop指令,在沒有訊息的時候,他會阻塞住,直到訊息到來。
  • 方式2:釋出訂閱模式
    • 使用pub/sub主題訂閱者模式,可以實現1:N的訊息佇列,即生產一次,消費多次,缺點就是在消費者下線的時候,生產的訊息會丟失,此場景,建議MQ。

6. 如何使用redis實現延時佇列?

  • 使用sortedset,用時間戳作為score,訊息內容作為key,使用zadd命令生產訊息,使用zrangebyscore來消費最早的一條訊息。
  • 之所以可以用redis實現延時佇列,
    • 最主要的原因就是redis支援高效能的socre排序。
    • 同時redis的持久化支援bgsave特性,保證了訊息的消費和儲存問題。
    • bgsave的原理是fork和cow。
      • fork是指redis通過建立子程序來進行bgsave操作。
      • cow是指copy on write ,子程序建立後,父程序通過共享資料段,父程序繼續提供讀寫服務,寫髒的頁面資料會逐漸和子程序分離開來。

7.redis持久化是怎麼做的?各自有什麼優缺點?突然掉電怎麼辦?

  • RDB做映象全量持久化,AOF做增量持久化

  • 因為RDB耗時長,不夠實時,在停機的時候回導致大量丟失資料,所以需要AOF配合使用,在redis重啟例項時,會使用RDB持久化檔案重新構建記憶體,再使用AOF重放近期的操作指令來實現完整恢復重啟之前的狀態。

  • 可以將RDB理解為一整個表的全量資料,AOF理解為每次操作的日誌,伺服器重啟的時候先將表的資料全部搞進去,但可能不完整,再回放一下日誌,資料就完整了。

  • RDB

    • 優點
      • 它會生成多個數據檔案,每個資料檔案都代表了某一時刻redis裡面的資料,這種方式,適合做冷備份,比如你想要多少分鐘前的redis資料。
      • RDB對redis效能的影響也非常小,因為在同步資料時它只是fork了一個子程序去做持久化,而且在恢復資料的時候速度比AOF更快。
    • 缺點
      • RDB都是快照檔案,都是預設五分鐘或者更久才生成一次,這意味著兩次同步時間之間的這五分鐘的資料都會全部丟掉。而AOF最多丟失一秒資料
      • 在生成RDB快照檔案時,如果檔案很大,客戶端可能會暫停幾毫秒或者幾秒,這不能滿足高效能要求場景,比如秒殺活動。
  • AOF

    • 優點
      • AOF通過一個後臺執行緒進行sync操作,最多丟失一秒的資料
      • AOF的日誌通過append-only的方式去寫,追加的方式寫資料,會少很多磁碟定址的開銷,寫入效能很不錯,檔案也不容易破損
      • AOF的日誌是以一種非常可讀的方式進行記錄的,這種特性適合做災難性資料誤刪除的緊急恢復操作。
    • 缺點
      • AOF資料檔案體積比RDB大
      • AOF開啟後,redis支援寫的QPS會比RDB支援寫的要低,因為AOF每次都要去非同步重新整理一下日誌fsync
  • 可以採用RDB做冷備份,AOF做熱備份

  • 掉電會有可能導致資料丟失,這個取決於AOF日誌的sync屬性,不要求效能時,在每條寫指令時都sync磁碟,就不會丟失資料,但高效能要求下要求每次寫指令都sync是不現實的,一般使用定時sync,比如1s一次,這個時候就最多丟失1s的資料。

8. RDB持久化的原理是什麼?

fork和cow。

  • fork是指redis通過建立子程序來進行rdb操作。
  • cow是指copy on write ,子程序建立後,父程序通過共享資料段,父程序繼續提供讀寫服務,寫髒的頁面資料會逐漸和子程序分離開來。

9.pipeline是什麼?有什麼好處?

  • pipeline又叫做管道,是個佇列。
  • pipeline可以一次性發送多條命令,服務端依次處理完後,通過一條響應一次性將結果返回
  • pipeline通過減少客戶端與redis的通訊次數來實現降低往返延時時間,總結其好處就是可以將多次IO往返時間縮減為一次。
  • 同時pipeline具有事務隔離特性。

10. redis同步機制瞭解嗎?

  • redis可以使用主從同步,從從同步
  • 第一次同步時,主節點做一次bgsave,並將後續操作記錄到記憶體buf,待完成後將RDB檔案全量同步到複製節點,複製節點接收完成後將RDB映象載入到記憶體,載入完成後,再通知主節點將期間修改的操作記錄同步到複製節點進行重放就完成了同步過程,後續的增量資料通過AOF日誌同步即可。

11.redis快取雪崩,擊穿,穿透的各自含義?後果?如何避免?

  • 快取雪崩

    • 含義:大面積的快取失效,大量的請求直接打到了db。
    • 後果:大數量級的請求直接打到db,後果幾乎是災難性的,比如說打掛的是一個使用者服務的資料庫,那麼依賴這個庫的所有介面都會報錯,如果沒有做熔斷等策略,基本上就是瞬間掛一片的節奏。
    • 避免方法:
      • 往redis中批量存資料時,把每個key的失效時間都加一個隨機值,保證資料不會在同一時間大量失效。
      • 如果redis是叢集部署,將熱點資料均勻分佈在不同redis庫中也可。
      • 或者直接設定熱點資料永遠不過期。
  • 快取穿透

    • 含義:指快取和db中都沒有此資料,但使用者不斷髮起請求。
    • 後果:這種請求類似攻擊,會造成資料庫壓力過大,嚴重可能會擊垮資料庫。
    • 避免方法:
      • 首先要追究產生快取穿透的原因,比如請求使用者ID為負數的請求,沒有為負數的ID,服務端沒有做任何限制,導致直接打到了db,我們要做的就是防備不合法請求打到db,比如在介面層增加校驗,比如使用者鑑權,引數做校驗,不合法引數直接return等。
      • 我們開發時,都要有一顆不信任的心,不信任介面呼叫者對傳的任何引數。
      • 對單秒內發起很多次請求的惡意使用者,可以讓運維對單個IP訪問次數超過閾值的IP進行拉黑。
      • 布隆過濾器,判斷一個元素是否在合集中
  • 快取擊穿

    • 含義:一個key非常熱點,在不停的扛著大併發,在這個key失效瞬間,持續的大併發就擊破快取直接打到DB,就像是在完好的桶上開了一個洞。
    • 後果:後果類似快取雪崩
    • 避免:
      • 熱點資料設定成永不過期或長一點
      • 加互斥鎖,併發的多個請求中,只有一個請求執行緒可以拿到鎖去資料庫執行查詢操作,執行完後,將查詢的值設定到redis,

12. redis為什麼這麼快呢?

redis是採用基於記憶體的單程序單執行緒模型的KV資料庫,C語言編寫,官方提供的資料是可以達到10w+的QPS

  • 完全基於記憶體,絕大部分請求都是記憶體操作,速度非常快
  • 資料結構簡單,對資料操作也簡單,因為redis中的資料結構都是經過精心設計的
  • 採用單執行緒,避免不必要的上下文切換和競爭,也不存在多程序或多執行緒的切換而消耗的CPU,不用去考慮各種鎖的問題。
  • 使用多路IO複用模型
  • redis客戶端使用RESP協議與redis伺服器進行通訊。

13. redis是單執行緒的,現在機器都是多核的,會不會浪費?

不會,但是我們可以在單機開多個redis例項

14. redis單機會有瓶頸,這個問題如何解決?

採用叢集部署的方式,也就是redis cluster

  • redis cluster是主從同步讀寫分離,rediscluster 支撐N個 reids master node,每個master node都可以掛載多個slave node.
  • 讀寫分離的架構,對於每個master,寫就寫到master,讀就從master對應的slave去讀
  • 每個master都有自己的slave節點,如果master掛掉,會自動將master的某個slave切換成master
  • 整個redis可以進行橫向擴容,如果需要支援更大資料量的快取,就橫向擴容多個master節點。

15. redis和memcached的區別?

分別從資料操作,記憶體管理機制,效能,叢集管理四個方向進行分析

  • 資料操作
    • memcached僅支援簡單kv儲存,不支援其他資料型別
    • redis支援更多的資料結構,有更加豐富的資料操作
  • 記憶體管理機制
    • memcached所有資料都是一直儲存在記憶體中,不支援持久化,採用預設的slab allocation機制管理記憶體,其主要思想就是按照預先規定的大小,將分配的記憶體切割成特定長度的塊以儲存相應長度的key-value資料,以完全解決記憶體碎片問題
    • redis支援RDB和AOF持久化
    • 當實體記憶體用完時,reids可以將一些很久沒有用的value寫到磁碟,這種特性可以保證reids可以儲存超過機器實體記憶體大小的資料。
  • 效能
    • redis只使用單核,memcached可以使用多核
    • 所以平均每個核上redis在儲存小資料時比memcached效能高,而在100k以上的大資料時,memcached效能較高
  • 叢集管理
    • memcached本身不支援分散式,因此只能在客戶端通過一致性hash這樣的分散式演算法來實現memcached的分散式儲存
    • redis偏向於在伺服器端構建分散式儲存

參考

心之所向,素履以往