myesn

myEsn2E9

hi
github

Redis 一覽無餘

簡略總結#

  • 認識 Redis
    • 記憶體資料庫
    • 常用於快取、消息隊列、分佈式鎖
    • 原子性操作
  • Redis 值的資料結構(五種常見)
    • String 字串:快取物件、常規計數、分佈式鎖、共享 session 資訊等
    • List 列表(鏈表):消息隊列等
    • Hash 哈希(無序散列表):快取物件、購物車等
    • Set 集合(字串的無序集合):聚合計算(並集、交集、差集)場景,比如點讚、共同關注、抽獎活動等
    • Zset 有序集合:排序場景,比如排行榜、電話和姓名排序等
    • …(還有 4 種,先不寫了)
  • Redis 執行緒模型
    • 單執行緒是指
      • [接收客戶端請求> 解析 > 資料讀寫 > 發送資料給客戶端] 由主執行緒完成。
      • redis 程式並不是單執行緒
    • 6.0 前後
      • 前 - 單執行緒:可維護高,簡單,無鎖問題
      • 後 - 多執行緒:採用多個 I/O 執行緒處理網路請求(因為網路 I/O 性能瓶頸)
      • 總結:執行命令還是單執行緒,引入多執行緒為了提供網路 I/O 處理性能
  • Redis 持久化
    • AOF 日誌:執行命令後,將命令寫入 AOF 檔案,重啟時加載該檔案
      • 策略:
        • Always:執行完命令後同步寫入
        • Everysec:先將命令寫入核心緩衝區,然後每秒將緩衝區的內容寫入磁碟
        • NO:由作業系統控制何時將緩衝區的內容寫進磁碟
      • 過大後:觸發 AOF 重寫機制
      • 缺點:檔案過大,載入時間長
    • RDB 快照:將某一時刻的記憶體資料(頻率可控),以二進位的方式寫入磁碟
      • 方式:
        • save 命令:通過主執行緒生成,會阻塞執行緒
        • bgsave 命令:通過創建子進程生成,不會阻塞執行緒
      • 缺點:資料丟失風險高
    • 混合:4.0 新增,解決 AOF 恢復慢,RDB 資料丟失風險高,集合兩者優點
  • Redis 集群
    • 方式
      • 主從複製:主同步到從(首次全量,後續增量),主寫從讀
      • 哨兵模式:在主從複製的基礎上,增加哨兵監控主、從、哨兵的健康狀態,自動故障轉移
      • 切片集群:將資料分佈到不同的伺服器,降低單點依賴,提高讀寫性能
    • 集群腦裂:網路分區(不同網路下)導致雙主
      • 解決:
        • min-slaves-to-write x,限制至少 x 個從連接到主,低於時主禁寫
        • min-slaves-max-lag x,限制主從資料同步的延遲小於 x 秒,超過時主禁寫
  • Redis 過期刪除與記憶體淘汰
    • 過期刪除:對比過期字典,未過期返回資料,已過期刪除
    • 刪除策略
      • 惰性刪除:訪問 key 時檢測是否過期,是則刪除 key 返回 null
      • 定期刪除:定時隨機取一定數量的 key 檢查,刪除其中過期的
        • 流程:抽取 key → 檢查是否過期,並刪除 → 過期數量超過 25% 時,重複之前步驟 → 小於 25% ,等待下一輪檢查
    • 持久化時過期鍵處理
      • AOF:
        • 對過期鍵添加刪除指令到 AOF 檔案
        • 載入時過期鍵不會寫入 AOF
      • RDB:
        • 生成 RDB 時忽略過期鍵
        • 載入時主過期不載入,從全部載入
    • 主從過期鍵處理:從依賴主(不掃描過期鍵),主檢查刪除過期鍵後同步到從
    • 記憶體滿載:達到閾值觸發記憶體淘汰機制,配置 maxmemory
    • 記憶體淘汰機制策略:共種,歸類為 [不進行淘汰] 和 [進行淘汰] 兩類
      • 不進行淘汰:超過閾值,直接返回錯誤
      • 進行淘汰:分為 [在設定了過期時間的資料中] 和 [所有資料] 內進行淘汰兩類,最好的是設定了過期時間且使用率最低的鍵
  • Redis 快取設計
    • 雪崩:為了資料一致性,對快取的資料設定過期時間,過期後從資料庫請求並重新更新快取,當大量鍵過期,請求直接到 DB 導致宕機。或 Redis 宕機。
      • 解決:
        • 過期:
          • 打散過期時間
          • 互斥鎖:同一時間僅一個業務執行緒更新快取
          • 雙 key(主設過期,備永久)
        • 宕機:
          • 服務熔斷
          • 請求限流
          • 高可用
    • 擊穿熱點資料過期,請求直接到 DB(雪崩的子集情況)導致宕機
      • 解決:
        • 互斥鎖:同一時間僅一個業務執行緒更新快取
        • 不設定過期時間
    • 穿透資料不在快取中,也不在 DB 中,一般是業務誤操作和惡意攻擊兩種
      • 解決:
        • 限制非法請求
        • 快取預設值
        • 使用布隆過濾器判斷資料是否存在,避免查 DB
    • 動態快取熱點資料:通過資料最新訪問時間排序,留下 top 資料
    • 常見快取更新策略
      • Cache Aside 旁路快取(實際開發時使用,最常用,適合讀多寫少):應用程式直接與 [資料庫、快取] 互動,負責維護快取
        • 寫策略:先更新 DB,再刪除 Cache(不能改變順序,否則導致資料不一致,刪除是懶加載思想)
        • 讀策略
          • 有快取,直接返回資料
          • 沒快取,讀 DB,寫入 Cache,返回資料
      • Read/Write Through 讀穿 / 寫穿
      • Write Back 寫回:有資料丟失風險
    • 保證 Cache 和 DB 資料一致性更新資料庫 + 更新快取(使用分佈式鎖,加上較短的過期時間)
  • Redis 實戰
    • 延遲執行隊列:使用 ZSet(有序集合),其中 Score 屬性存儲延遲執行的時間,再利用 zrangebysocre 查詢並對比時間找到待處理的
    • Redis 大 key:指 key 的 value 很大
      • 條件
        • String 類型的值大於 10 KB
        • Hash、List、Set、ZSet 類型的元素超過 5k
      • 影響
        • 客戶端超時阻塞:redis 單執行緒執行命令,操作大 key 耗時,阻塞執行緒
        • 引發網路堵塞:資料 * 訪問量 = 產生大流量
        • 阻塞工作執行緒:del 大 key,阻塞工作執行緒
        • 記憶體分佈不均:集群模型在 slot 分片均勻時,出現資料和查詢傾斜情況,部分有大 key 的節點佔用記憶體多,QPS 較大
      • 排查
        1. redis-cli --bigkeys
          • 注意:
            • 在從節點執行,因為會阻塞執行緒
            • 無從時在低峰時間執行,可使用 -i 控制掃描間隔,降低性能影響
        2. SCAN :先用 SCAN 掃描,再用 TYPE 獲取 key 的類型
          • String 類型:使用 STRLEN 獲取長度
          • 集合類型:
            • 平均大小 * 數量
            • MEMORY USAGE 查詢鍵佔用空間(Redis 4.0+)
        3. https://github.com/sripathikrishnan/redis-rdb-tools:解析 RDB 檔案
      • 刪除:直接刪除會釋放大量記憶體,同時會造成空閒記憶體塊鏈表操作時間增加,從而 Redis 主執行緒阻塞,致使各種請求超時,最終 Redis 連接耗盡,產生各種異常
        • 方法:
          • 分批次
            • 大 Hash:使用 hscan 每次獲取 100 個字段,再用 hdel one by one 刪除
            • 大 Set:使用 sscan 每次掃描 100 個元素,再用 srem one by one 刪除
            • 大 ZSet:使用 zremrangebyrank 每次刪除 top 100 個元素
          • 非同步(Redis 4.0+):用 unlink 代替 del
            • 方式:
              • 主動調用 unlink 命令
              • 配置參數,滿足條件時非同步刪除
    • Redis 管道(Pipeline)是客戶端而非伺服器提供的一種批處理技術,一次處理多個 Redis 命令,解決多個命令執行時的網路等待
    • Redis 事務不支持回滾:不支持事務運行時錯誤的事務回滾,只有 DISCARD 放棄事務執行
      • 不支持原因:
        • 作者認為生產環境很少出錯,沒必要開發
        • 事務回滾較複雜與 Redis 簡單高效設計不符
    • 分佈式鎖:在分佈式環境下並發控制的一種機制,用於控制資源在同一時刻只能被一個應用使用
      • 原理SET 命令的 NX 參數可以實現 [key 不存在才插入]

        • key 不存在:顯示插入成功,表示加鎖成功
        • key 存在:顯示插入失敗,表示加鎖失敗
      • 加鎖條件

        • 加鎖是對鎖變數進行 [讀取、檢查和設定] 三個操作,需要原子操完成,所以使用 SET +NX
        • 鎖變數需要設定過期時間,使用 EX/PX 選項,單位為毫秒
        • 鎖變數的值使用客戶端的唯一標識區分來源
        # 滿足三條件的命令:
        SET lock_key unique_value NX PX 10000
        
        - lock_key: key
        - unique_value: 客戶端唯一標識
        - NX: lock_key 不存在時才進行設定
        - PX 10000: 設定 lock_key 過期時間為 10
        
      • 解鎖:有兩個操作,需要 Lua 腳本保證原子性,即先比較值是否相等,再刪除鍵

        // 釋放鎖時,先比較 unique_value 是否相等,避免鎖的誤釋放
        if redis.call("get",KEYS[1]) == ARGV[1] then
            return redis.call("del",KEYS[1])
        else
            return 0
        end
        
      • 優點:

        • 性能高
        • 實現方便
        • 避免單點故障(Redis 集群部署)
      • 缺點:

        • 超時時間不好設定:過長影響性能,過短失去鎖保護
        • Redis 主從複製模式中資料是非同步複製的,可能導致分佈式鎖的不可靠性。
      • 集群下的可靠性:官方設計了一個分佈式鎖演算法 Redlock(紅鎖)。基於多個 Redis 節點的分佈式鎖,官方推薦至少 5 個孤立的主節點

        • 原理:讓客戶端和多個獨立的 Redis 節點依次請求申請加鎖和半數以上的節點加鎖成功,就認為客戶端加鎖成功
        • 過程(加鎖成功 = 超半數成功獲取鎖 & 總耗時 < 鎖有效時間)
          1. 客戶端獲取當前時間(t1)
          2. 客戶端按順序依次向 N 個節點執行加鎖
          3. 客戶端從超過半數(大於等於 N/2+1)的節點上成功獲取到了鎖,就再次獲取當前時間(t2),然後計算耗時(t2-t1),t2-t1 < 鎖的過期時間,認為加鎖成功
載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。