分布式系列十二: Redis高級主題


持久化

Redis 支持持久化, 其持久化數據有兩種方式. 兩種可以同時使用. 如果同時使用, Reids 在重啟時將使用 AOF 方式來還原數據.

RDB

按照一定策略定時同步內存的數據到磁盤.文件名 dump.rdb

  • snapshot: 快照復制. Redis在指定情況下觸發快照: (1) 按配置的規則;(2) save 或 bgsave 命令執行;(3) flushall 命令; (4)執行復制

    1. 配置的規則: save seconds exchange 當在 seconds 指定的時間內, key 的數量更改大於 exchange 時發生快照.

    2. save 或 bgsave 命令: 執行快照同步操作, 注意save這個操作會暫時阻塞客戶端請求. bgsave則不會阻塞

    3. flushall: 清除內存所有數據, 只要規則不為空, redis就會執行快照

    4. 執行復制:

  • 快照原理

    fork 復制一份當前進程的副本, 這個進程是子進程, 負責同步持久化到磁盤. 而父進程負責處理客戶端請求.

  • 快照的優缺點:

    1. 缺點: 可能會丟失數據, 在下一次快照前宕機
    2. 優點: 最大化Redis的性能, 父子進程職責分離

AOF

保存命令到磁盤, 也就是持久化日志.

  • 配置: appendonly yes 啟動aof. 默認的文件名是 appendonly.aof.

  • 配置 auto-aof-rewrite-percentage 100 當 aof 文件與上一次文件的大小相比, 超過配置的百分比就進行重寫

  • 配置 auto-aof-rewrite-min-size 64m 限制允許重寫最小 aof 文件大小, 即小於64m時不重寫

  • aof 重寫原理: aof 重寫是安全的. 相當於同時將命令追加到現有的aof文件, 同時寫入新的 aof 臨時文件, 臨時文件最終將覆蓋原 aof 文件.

  • 同步磁盤數據: aof機制會將命令記錄到aof文件, 但實際是同步到操作系統的緩存區, 最終由操作系統同步到磁盤. 可以通過下面配置修改策略
    appendsync always 每次執行寫入就同步, 安全但影響性能
    appendsync everysec 每一秒執行
    appendsync no 不執行同步, 由操作系統去執行, 效率高但不安全

  • aof 文件損壞后的修復, 使用redis-check-aof-fix

集群

master/slave 復制

主從方式, 從是只讀的, slave也可以有自己的slave.

  • slave節點上配置 slaveof masterip masterport

  • 配置 slave-serve-stale-data no 可以用來保證數據同步后再做其他操作

  • 命令info replication可以查看信息.

  • 實現原理:

    1. slave 連接到 master 后, 會向 master 發送 SYNC 命令.
    2. master 收到命令后, 會做兩件事(1) 執行bgsave;(2)master 將收到的修改命令存入緩沖區, 再將命令傳輸給slave
  • 復制方式:

    1. 基於rdb文件復制
    2. 無硬盤復制 配置rpli-diskless-sync yes
    3. 增量復制 PSYNC master run id. offset
  • 命令replconf listening-port 6379可以用來查看復制過程

  • 缺點: 無法做master選舉

sentinale 哨兵模式

  1. 監控
  2. master選舉
  • 配置文件為sentinel.conf

  • 配置節點: sentinel monitor mymaster 192,168,11,111 6379 2 最后的2為投票數

  • 是高可用方案, 但不是高性能方案

集群

  • 原理

    Reids有slot槽的概念: redis中有16384個. 根據key的 CRC16 算法, 取得的結果與槽數取模.落入的槽的索引是固定的. 然后根據節點數將槽的范圍確定到每個節點上.

    當節點新增和刪除時, 節點的槽范圍發生變化, 數據遷移需要人工干預.

  • 三方方案

    1. redis shardding : jedis支持
    2. codis : 代理, 分片和數據遷移自動化
    3. twemproxy :

緩存穿透問題

  • 數據庫中不存在的對象查詢后也緩存.
if(objJson!=null){
    redisService.expire("key",timeout:3*60);
} else {
    redisService.expire("key",timeout:5); //5秒內不查詢數據庫
}
  • synchronized 方法, 不理想, 排隊影響性能.
  • 同步塊, 需要雙重判定, 否則阻塞的線程均會查詢數據庫, 代碼如下
String value = redisService.get("key");
if(value==null){
    synchronized(lock){
        value = redisService.get("key"); //多線程再次查詢,防止數據庫多次查詢
        if(value==null){
            value = dao.get();
            redisService.set("key",value);
            if(objJson!=null){
                redisService.expire("key",timeout:3*60);
            } else {
                redisService.expire("key",timeout:5); //5秒內不查詢數據庫
            }
        }
    }
}
  • 使用ReentrantLocktryLock(),else中線程等待一段時間, 這樣不阻塞進程

  • 使用分布式鎖

if(redisService.setNx("key")==true){
    //查詢數據庫
}
  • 不設超時時間或設置一個較長的超時時間, 然后判斷當前時間是否超過緩存時間, 結合分布式鎖, 超過則刷新緩存. 此解決方法可能會發生少量數據不一致的情況.

采用何種策略需要結合實際需求, 是保證可用, 還是保證一致性? 對於一致性要求不高的場景, 可能最后一種方案可以徹底解決擊穿問題. 對於一致性要求較高的場景, 使用同步/鎖的方式會更好.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM