掌握這21條Redis核心知識,沒有18k可以考慮換工作了

先來了解

掌握這21條Redis核心知識,沒有18k可以考慮換工作了

1) 什麼是 Redis

  • Redis(Remote Dictionary Server)是一個使用C語言 編寫的,開源的(BSD許可)高性能非關係型(NoSQL) 的鍵值對數據庫
  • Redis可以存儲鍵和五種不同類型的值之間的映射。
  • Redis 支持很多特性,例如將內存中的數據持久化到硬盤中,使用複製來擴展讀性能,使用分片來擴展寫性能。所以讀寫速度非常快,因此Redis被廣泛應用於緩存方向,每秒可以處理超過10萬次讀寫操作,是已知性能最快的key-value 數據庫。另外 Redis 也經常用來做分佈式鎖,而且 Redis 支持事務持久化LUA腳本LRU驅動事件多種集群方案等。

2)Redis為什麼那麼快

  • 完全基於內存,絕大部分請求是純粹的內存操作
  • 數據結構簡單,對數據操作也簡單,Redis中的數據結構是專門為各種場景設計的
  • 採用單線程,避免了不必要的上下文切換和競爭條件,也不存在多進程或者多線程導致的切換而消耗CPU,不用去考慮各種鎖的問題,不存在加鎖釋放鎖操作,沒有因為可能出現死鎖而導致的性能消耗
  • 使用多路 I/O 複用模型,非阻塞 IO

3)Redis 的優缺點

優點:

  • 讀寫速度快,因為數據存在內存中,類似於HashMap
  • 支持豐富的數據類型,支持 String,List,Hash,Set,SortSet(Zset)
  • 支持事務(一致性和隔離性),利用好RDB和AOF也能實現持久性
  • 支持主從複製,主機會自動將數據同步到從機,可以進行讀寫分離

缺點:

  • 緩存和數據庫雙寫一致性問題
  • 緩存雪崩、穿透、擊穿問題
  • Redis 較難支持在線擴容,在集群容量達到上限時擴容會變得很複雜
  • 主機宕機前會有部分數據未能及時同步到從機,切換IP後還會引入數據不一致問題,降低了系統的可用性
  • 緩存的併發競爭問題

4)Redis與Memcache的區別

  • 數據類型 Memcached僅支持字符串類型 Redis 支持五種不同的數據類型,可以更靈活地解決問題
  • 數據持久化 Memcached 不支持持久化 Redis 支持兩種持久化策略:RDB快照 和 AOF 日誌
  • 分佈式 Memcached 不支持分佈式,只能通過在客戶端使用一致性哈希來實現分佈式存儲,這種方式在存儲和查詢時都需要先在客戶端計算一次數據所在的節點 Redis Cluster 支持分佈式
  • 內存管理機制 Redis 中,並不是所有數據都一直存儲在內存中,可以將一些很久沒用的 value 交換到磁盤 Memcached 的數據一直會在內存中,它將內存分割成特定長度的塊來存儲數據,以完全解決內存碎片的問題,但是這種方式會使得內存的利用率不高,例如塊的大小為 128 bytes,只存儲 100 bytes 的數據,那麼剩下的 28 bytes 就浪費了

5)Redis有哪些數據類型

  • String(字符串) 簡介: 二進制安全 可以存儲的值: 字符串,整數或者浮點數,還有jpg圖片或者序列化對象 操作: 對整個字符串或者字符串的其中一部分執行操作,對整數和浮點數執行自增或者自減操作 應用場景: 做簡單的鍵值對緩存 實際使用:
<code>  > set test cbuc
ok
    ----------------------------
  > get test
"cbuc"
    ----------------------------
  > del test
(integer) 1
    ----------------------------
  >get test
(nil)/<code>
  • List(列表) 簡介: 鏈表(雙向鏈表) 可以存儲的值: 列表 操作: 從兩端壓入或者彈出元素,對單個或者多個元素進行修改,只保留一個範圍內的元素 應用場景: 最新消息排行;消息隊列 實際使用:
<code>  > rpush test c1
(integer) 1
    ----------------------------
  > rpush test c2
(integer) 2
    ----------------------------
  > rpush test c2
(integer) 3
    ----------------------------
  > lrange test 0 -1
1) "c1"
2) "c2"
3) "c3"
    ----------------------------
  > lindex test 1
"c2"
    ----------------------------
  > lpop test
"c1"
    ----------------------------
  > lrange test 0 -1
"c2"
"c2"  /<code>
  • Hash(字典) 簡介: 鍵值對集合,即編程語言中的map類型 可以存儲的值: 適合存儲對象,並且可以像數據庫中的update一樣,只修改某一項的屬性值 操作: 添加、獲取、移除單個鍵值對,獲取所有鍵值對,檢查某個鍵是否存在 應用場景: 存儲、讀取、修改用戶屬性 實際使用:
<code>  > hset test name cbuc
(integer) 1
    ----------------------------
  > hset test age 23
(integer) 1
    ----------------------------
  > hgetall test
1)"name"
2)"cbuc"
3)"age"
4)"23"
    ----------------------------
  > hdel test age
(integer) 1
    ----------------------------
  > hget test name 
"cbuc"
    ----------------------------
  > hgetall test
1)"name"
2)"cbuc"     /<code>
  • Set(集合) 簡介: hash表實現,元素不重複 可以存儲的值: 無序集合 操作: 添加、獲取、移除單個元素,檢查一個元素是否已經存在於集合中,計算交集、並集、差集從集合裡面隨機獲取元素 應用場景: 共同好友;利用唯一性,統計訪問網站的所有IP 實際使用:
<code>  > sadd test c1
(integer) 1
  > sadd test c2
(integer) 1
  > sadd test c1
(integer) 0
    ----------------------------
  >smembers test
1)"c1"
2)"c2"
    ----------------------------
  > sismember test c3
(integer) 0
  > sismember test c1
(integer) 1
    ----------------------------
  > srem test c1
(integer) 1
    ----------------------------
  > smembers test
1)"c2"        /<code>
  • ZSet(有序集合) 簡介: 將 set 中的元素增加一個權重參數score,元素按score有序排列 可以存儲的值: 有序集合 操作: 添加、獲取、刪除元素,根據分值範圍或者成員來獲取元素,計算一個鍵的排名
    應用場景: 排行榜;帶權重的消息隊列 實際使用:
<code>  > zadd test 92 math
(integer) 1
  > zadd test 88 english
(integer) 1
  > zadd test 92 score
(integer) 1
    ----------------------------
  > zrange test 0 -1 withscores
1)"english"
2)"88"
3)"math"
4)"92"
    ----------------------------
  > zrangebyscore test 80 90 withscores
1)"english"
2)"88"
    ----------------------------
  > zrem test english
(integer) 1
    ----------------------------
  > zrange test 0 -1 withscores
3)"math"
4)"92"   /<code>

高級用法:

  • BitMap
    位圖是支持按 bit 位來存儲信息,可以用來實現 布隆過濾器(BloomFilter)
  • HyperLogLog
    供不精確的去重計數功能,比較適合用來做大規模數據的去重統計,例如統計 UV
  • Geospatial
    可以用來保存地理位置,並作位置距離計算或者根據半徑計算位置等。可以用來實現附近的人,或者計算最優地圖路徑

6)什麼是Redis持久化

持久化就是把內存中的數據寫到磁盤中去,防止服務宕機了內存數據丟失。

7)Redis的持久化機制

Redis提供兩種持久化機制:RDB快照(默認)和AOF(機制)

RDB

RDB(Redis DataBase)是Redis中默認的持久化方式。按照一定的時間將內存的數據以快照的形式保存到磁盤中,會產生dump.rdb數據文件,可以通過配置文件中的save參數來定義快照的週期。

掌握這21條Redis核心知識,沒有18k可以考慮換工作了

原理: fork和cow。fork 是指 redis間隔一段時間會 fork 一個子進程,子線程將數據寫到磁盤上一個臨時RDB文件中,當子進程寫完臨時文件後,將原來的RDB替換掉,這樣的好處是可以 cow(copy-on-wirte)
優點:

  • 方便持久化,只有一個文件 dump.rdb
  • 容災性好,一個文件可以保存到安全的磁盤中
  • 性能最大化,fork 子進程來完成寫操作,讓主進程繼續處理命令,所以是IO最大化。使用單獨的進程來進行持久化,主進程不會進行任何IO操作,保證 redis 的高性能

缺點:

  • 數據安全性低,RDB是間隔一段時間來進行持久化,如果持久化之間 redis 發生故障,會發生數據丟失,所以這種方式更適合數據要求不嚴謹的時候用
  • 保存時間長,如果數據量很大,保存快照的時間會很長

AOF

AOF(Append-Only-File),是將 Redis 執行的每次寫命令記錄到單獨的日誌文件中,當重啟 Redis 會重新將持久化的日誌中文件恢復數據

掌握這21條Redis核心知識,沒有18k可以考慮換工作了

原理: 將寫命令添加到 AOF 文件(Append Only File)的末尾。使用AOF持久化需要設置同步選項,從而確保寫命令同步到磁盤文件上的時機。這是因為對文件進行寫入並不會馬上將內容同步到磁盤上,而是先存儲到緩衝區,然後由操作系統決定什麼時候同步到磁盤。


同步選項:

掌握這21條Redis核心知識,沒有18k可以考慮換工作了

選項 同步頻率 no 讓操作系統決定何時同步 always 每個寫命令都同步 everysec 每秒同步一次

  • no: 並不能給服務器性能帶來多大的提升,而且也會增加系統奔潰時數據丟失的數量
  • always: 嚴重減低服務器性能
  • everysec: 這個選項比較合適,可以保證系統奔潰時只會丟失一秒左右的數據,並且 Redis 每秒執行一次同步對服務器性能幾乎沒有任何影響

隨著服務器寫請求的增多,AOF文件會越來越大。Redis提供了一種將AOF重寫的特性auto-aof-rewrite,能夠去除AOF文件中的冗餘寫命令

優點:

  • 數據安全,AOF 持久化可以配置 appendfsync 屬性中的always,每進行一次寫命令操作就記錄到 AOF 文件中一次、
  • 一致性,通過 append 模式寫文件,即使中途服務器宕機,可以通過 redis-check-aof 工具解決數據一致性問題

缺點:

  • AOF 文件比RDB文件大,而且恢復速度慢
  • 數據集大的時候比 RDB 啟動效率低

兩者比較

  • AOF 文件比 RDB 更新頻率高,優先使用 AOF 還原數據
  • AOF 比 RDB 更安全也更強大
  • RDB 性能比 AOF 好
  • 如果兩個都配了優先加載 AOF

8)如何選擇合適的持久化方式

一般來說兩者都會配置。如果單獨用 RDB 的話你會丟失很多數據,單獨用 AOF,你數據恢復沒有 RDB 來的快,如果系統出現問題的時候我們可以先用 RDB 恢復,然後用 AOF 補全數據。冷熱備份一起用,才能保證高健壯性的系統。

9)Redis的過期鍵刪除策略

  • 定時刪除
    每個設置過期時間的 key 都需要創建一個定時器,到過期時間就會立即清除。該策略可以立即清除過期的數據,對內存很友好;但是會佔用大量的CPU資源來處理過期的數據,從而影響緩存的響應時間和吞吐量
  • 惰性刪除
    只有當訪問一個 key 時,才會判斷該 key 是否已過期,是則刪除。該策略可以最大化節省CPU資源,卻對內存非常不友好。極端情況下可能出現大量的過期 key 沒有再次被訪問,從而不會被清除,佔用大量內存
  • 定期刪除
    每隔一定時間,會掃描一定數量的 expires 字典中的 key,並清除其中已過期的 key。該策略是前兩者的一個折中方法。通過調整定時掃描的時間間隔和每次掃描的限定耗時,可以在不同情況下使得CPU和內存資源達到最優的平衡效果。

Redis 一般同時使用 惰性過期 和 定期過期 兩種過期策略

10)Redis 內存淘汰策略

設置過期時間的鍵空間選擇性移除

  • volatile-lru:
    嘗試回收最少使用的鍵使得新添加的數據有空間存放。
  • volatile-random:
    回收隨機的鍵使得新添加的數據有空間存放
  • volatile-ttl:
    優先回收存活時間較短的鍵使得新添加的數據有空間存放

全局的鍵空間選擇性移除

  • allkeys-lru:
    嘗試回收最少使用的鍵使得新添加的數據有空間存放。
  • allkeys-random:
    回收隨機的鍵使得新添加的數據有空間存放
  • noeviction:
    當內存達到限制並且客戶端嘗試執行,會返回錯誤

11)Redis 事務

Redis 事務的本質是通過 MULTIEXECWATCHDISCARD四個原語實現的。事務支持一次執行多個命令,一個事務中所有命令都會被序列化。在事務執行過程,會按照順序串行化執行隊列中的命令,其他客戶端提交的命令請求不會插入到事務執行命令序列中。總結:Redis 事務就是一次性、順序性、排他性的執行一個隊列中的一系列命令。

  • Redis 不支持回滾,Redis 在事務失敗時不進行回滾,而是繼續執行餘下的命令,所以 Redis 的內部可以保持簡單且快速。
  • 如果在一個事務中的命令出現錯誤,那麼所有的命令都不會執行
  • 如果在一個事務中出現運行錯誤,那麼正確的命令會被執行
    四個原語
  • WATCH: 是一個樂觀鎖,可以為 Redis 事務提供 check-and-set(CAS)行為,可以監控一個或多個鍵。一旦其中有一個鍵被修改(或刪除),之後的事務就不會執行,監控一直持續到EXEC命令
  • MULTI: 用於開啟一個事務,它總是返回OK。MULTI執行之後,客戶端可以繼續向服務器發送任意多條命令,這些命令不會立即被執行,而是被放到一個隊列中,當 EXEC命令被調用時,所有隊列中的命令才會被執行
  • EXEC: 執行所有事務塊內的命令,返回事務塊內所有命令的返回值,按命令執行的先後順序排列,當操作被打斷時,返回控制 nil
  • DISCARD: 調用 DISCARD ,客戶端可以清空事務隊列,並放棄執行事務,並且客戶端會從事務狀態中退出

12)Redis設置過期時間和永久有效

EXPIRE 和 PERSIST 命令

13)緩存雪崩

緩存雪崩是指緩存同一時間大面積的失效,所以,後面的請求都會落到數據庫上,造成數據庫短時間內承受大量請求而崩掉解決方法:

  • 緩存數據的過期時間設置隨機,防止同一時間大量數據過期現象發生
  • 一般併發量不是特別多的時候,使用最多的解決方案是加鎖排隊
  • 搭建集群,如果一臺 Redis 掛掉之後,還有其他的可以繼續工作

14)緩存擊穿

緩存擊穿是指緩存中沒有但數據庫中有的數據(一般是緩存時間到期),這時由於併發用戶特別多,同時讀緩存沒讀到數據,又同時去數據庫去取數據,引起數據庫壓力瞬間增大解決方法:

  • 設置熱點數據永遠不過期
  • 可以使用互斥鎖更新,保證同一個進程中針對同一個數據不會併發請求到 DB,減小 DB 壓力
  • 使用隨機退避方式,失效時隨機 sleep 一個很短的時間,再次查詢,如果失敗再執行更新

15)緩存穿透

緩存穿透是指緩存和數據庫中都沒有的數據,導致所有的請求都落到數據庫上,造成數據庫短時間內承受大量請求而崩掉解決方法:

  • 對於不存在的數據,在緩存中保存一個數據進行標記,並設置上過期時間,防止相同的數據請求再次訪問 DB。
  • 使用 BloomFilter 過濾器,布隆過濾器的特點是存在性檢測,如果布隆過濾器中不存在,那麼數據一定不存在;如果布隆過濾器中存在,實際數據也有可能會不存在。

16)Redis主從架構

單機的 Redis,能夠承載的 QPS 大概在上萬到幾萬不等,對於緩存來說,一般都是用來支撐讀高併發的。如果一臺機器讀寫合一的那會很容易發生問題。因此會採用主從架構,讓 master 去處理寫操作,然後把數據同步到 slave 上,slave 負責讀操作。這樣就會分發掉大量的請求,而且在擴容的時候還可以輕鬆實現水平擴容。

掌握這21條Redis核心知識,沒有18k可以考慮換工作了

當啟動一臺 slave 的時候,它會發送一個 psync 命令到 master ,如果是第一次同步,主節點會做一次

bgsave,並同時將後續修改操作記錄到內存buffer,待完成後將RDB文件全量同步到複製節點,複製節點接收完成後將RDB鏡像加載到內存然後寫入本地磁盤。處理完成後,再通知主節點將期間修改的操作記錄同步到複製節點進行重放就完成了同步過程。後續的增量數據通過AOF日誌同步即可,類似於數據庫的binlog

17)Redis實現分佈式鎖

簡單來說就是先拿setnx來爭搶鎖,搶到之後,再用expire給鎖加一個過期時間防止鎖忘記了釋放SETNX 是【SET if Not eXists】(如果不存在,則 SET)的簡寫。當且僅當 key 不存在,將 key 的值設為 value。 若給定的 key 已經存在,則 SETNX 不做任何動作。返回值:設置成功,返回 1 。設置失敗,返回 0 。

18)Redis的同步機制

Redis可以使用主從同步,從從同步。第一次同步時,主節點會做一次bgsave,並同時將後續修改操作記錄到內存

buffer,待完成後將RDB文件全量同步到複製節點,複製節點接收完成後將RDB鏡像加載到內存然後寫入本地磁盤。處理完成後,再通知主節點將期間修改的操作記錄同步到複製節點進行重放就完成了同步過程。後續的增量數據通過AOF日誌同步即可,類似於數據庫的binlog

19)Redis集群原理

Redis Sentinel(哨兵)著眼於高可用,在master 宕機時會自動將slave提升為master,繼續提供服務。Redis Cluster(集群)著眼於擴展性,在單個redis內存不足時,使用Cluster進行分片存儲。選主策略:

  • slave 的 priority 設置的越低,優先級越高
  • 同等情況下,slave 複製的數據越多優先級越高
  • 相同的條件下,runid 越小越容易被選中

20)Redis 哨兵模式

掌握這21條Redis核心知識,沒有18k可以考慮換工作了

哨兵必須用三個實例去保證自己的健壯性,哨兵 + 主從 並不能保證數據不丟失 ,但是可以保證集群的高可用。
工作原理:

  • 每個 Sentinel 節點以每秒一次的頻率向它所知的主服務器、從服務器和其他 Sentinel 節點發送一個 PING 命令
  • 如果 一個實例舉例最後一次有效回覆 PING 命令的時間超過
    down-after-milliseconds 所指定的值,那麼這個實例就會被標記為主觀下線
  • 如果一個主服務器被標記為主觀下線,那麼正在監視這個服務器的所有 Sentinel 節點會以每秒一次的頻率確認主服務器的確進入了主觀下線狀態
  • 如果有足夠數量的 Sentinel (至少要達到配置文件中指定的數量)在指定的時間範圍內同意這一判斷,那麼這個主服務器就會被標記為客觀下線
  • 當主服務器被標記為客觀下線後,Sentinel 節點會向下線主服務器的所有從服務器發送 INFO 命令的頻率從 10 秒一次改為每秒一次
  • Sentinel 節點會協商客觀下線主服務器的狀態,如果處於 SDOWN 狀態,則投票自動選出新的主節點,將剩下從節點指向新的主節點進行數據複製。
  • 當沒有足夠數量的 Sentinel 節點泳衣主服務器下線是,主服務器的客觀下線狀態就會被移除。或者當主服務器重新向 Sentinel 的 PING 命令返回有效回覆時,主服務器的主觀下線狀態就會被移除

21)腦裂問題及解決

何為腦裂:

Redis 的集群腦裂是指因為網絡問題,導致 redis master 節點跟 redis slave 節點和 sentinel 集群處於不用的網絡分區,此時因為 sentinel 集群無法感知到 master 的存在,所以將 slave 節點提升為 master 節點。此時存在兩個不同的 master 節點,就像是一個大腦分裂成了兩個。這時如果客戶端還在基於原來的 master 節點繼續寫入數據,那麼新的 master 節點將無法同步這些數據,當網絡問題解決之後,sentinel集群就會將原先的 master 節點降為 slave 節點,此時再從新的 master 中同步數據,將會造成大量的數據丟失

掌握這21條Redis核心知識,沒有18k可以考慮換工作了

解決:

  • 通常採用隔離(Fencing)機制
  • 共享存儲Fencing:確保只有一個 Master 往共享存儲中寫數據
  • 客戶端Fencing:確保只有一個 Master 可以響應客戶端的請求
  • Slave Fencing:確保只有一個 Master 可以向 Slave 下發命令
  • 配置文件中修改參數
<code>min-replicas-to-write 3        # 表示連接到 master 的最少slave數量
min-replicas-max-lag 10        # 表示 slave 連接到 master 的最大延遲時間/<code>

按照上面配置,要求至少3個slave節點,且數據複製和同步的延遲不能超過10秒,否則的話 master 就會拒絕寫請求,配置了這兩個參數之後,如果發生集群腦裂,原先的 master 節點接收到客戶端的寫入請求或拒絕,就可以減少數據同步之後的數據丟失。

掌握這21條Redis核心知識,沒有18k可以考慮換工作了

來源:掘金

作者:蔡不菜丶


分享到:


相關文章: