使用過Redis,我竟然還不知道Rdb

使用過Redis,那就先說說使用過那些場景吧

字符串緩存

//舉例
$redis->set();
$redis->get();
$redis->hset();
$redis->hget();

隊列

//舉例
$redis->rpush();
$redis->lpop();
$redis->lrange();

發佈訂閱

//舉例
$redis->publish();
$redis->subscribe();

計數器

//舉例
$redis->set();
$redis->incr();

排行榜

//舉例
$redis->zadd();
$redis->zrevrange();
$redis->zrange();

集合間操作

//舉例
$redis->sadd();
$redis->spop();
$redis->sinter();
$redis->sunion();
$redis->sdiff();

悲觀鎖

解釋:悲觀鎖(Pessimistic Lock), 顧名思義,就是很悲觀。

每次去拿數據的時候都認爲別人會修改,所以每次在拿數據的時候都會上鎖。

場景:如果項目中使用了緩存且對緩存設置了超時時間。

當併發量比較大的時候,如果沒有鎖機制,那麼緩存過期的瞬間,

大量併發請求會穿透緩存直接查詢數據庫,造成雪崩效應。

/**
 * 獲取鎖
 * @param  String  $key    鎖標識
 * @param  Int     $expire 鎖過期時間
 * @return Boolean
 */
public function lock($key = '', $expire = 5) {
    $is_lock = $this->_redis->setnx($key, time()+$expire);
    //不能獲取鎖
    if(!$is_lock){
        //判斷鎖是否過期
        $lock_time = $this->_redis->get($key);
        //鎖已過期,刪除鎖,重新獲取
        if (time() > $lock_time) {
            unlock($key);
            $is_lock = $this->_redis->setnx($key, time() + $expire);
        }
    }

    return $is_lock? true : false;
}

/**
 * 釋放鎖
 * @param  String  $key 鎖標識
 * @return Boolean
 */
public function unlock($key = ''){
    return $this->_redis->del($key);
}

// 定義鎖標識
$key = 'test_lock';

// 獲取鎖
$is_lock = lock($key, 10);
if ($is_lock) {
    echo 'get lock success<br>';
    echo 'do sth..<br>';
    sleep(5);
    echo 'success<br>';
    unlock($key);
} else { //獲取鎖失敗
    echo 'request too frequently<br>';
}

樂觀鎖

解釋:樂觀鎖(Optimistic Lock), 顧名思義,就是很樂觀。

每次去拿數據的時候都認爲別人不會修改,所以不會上鎖。

watch命令會監視給定的key,當exec時候如果監視的key從調用watch後發生過變化,則整個事務會失敗。

也可以調用watch多次監視多個key。這樣就可以對指定的key加樂觀鎖了。

注意watch的key是對整個連接有效的,事務也一樣。

如果連接斷開,監視和事務都會被自動清除。

當然了exec,discard,unwatch命令都會清除連接中的所有監視。

$strKey = 'test_age';

$redis->set($strKey,10);

$age = $redis->get($strKey);

echo "---- Current Age:{$age} ---- <br/><br/>";

$redis->watch($strKey);

// 開啓事務
$redis->multi();

//在這個時候新開了一個新會話執行
$redis->set($strKey,30);  //新會話

echo "---- Current Age:{$age} ---- <br/><br/>"; //30

$redis->set($strKey,20);

$redis->exec();

$age = $redis->get($strKey);

echo "---- Current Age:{$age} ---- <br/><br/>"; //30

//當exec時候如果監視的key從調用watch後發生過變化,則整個事務會失敗

上面的一些場景,咱們大部分都使用過,卻還沒有提及到Rdb文件。

“對吧,使用過Redis,卻不知道Rdb文件,你中槍了嗎?”

Rdb文件是什麼,它是幹什麼的

Redis 作爲互聯網產品開發中不可缺少的常備武器,它性能高、數據結構豐富、簡單易用,但同時也是因爲太容易用了,不管什麼數據、不管這數據有多大、不管數據有多少,通通塞進去,最後導致的問題就是 Redis 內存使用持續上升,但是又不知道里面的數據是不是有用,是否可以拆分和清理,最可怕的是服務器發生宕機後,Redis 數據庫裏的所有數據將會全部丟失。

比如當內存上升,性能慢時,我們進行性能調優的時候,我們想知道:

  • 哪些Key佔用了大量的內存?
  • 想知道每個Key的佔用空間?
  • 想知道佔用空間大的Key都存了啥?
  • 想知道佔用空間大的Key的重要性,當性能慢的時候是否可以馬上刪除?
  • 更想知道這些Key是哪個業務方,哪個開發創建的?這樣就可以找他溝通了。

嘗試解決問題的思路

一、先通過 keys * 命令,拿到所有的 key,然後根據 key 再獲取所有的內容。

  • 優點:可以不使用 Redis 機器的硬盤,直接網絡傳輸。
  • 缺點:如果 key 數據特別多,keys 命令可能會直接導致 Redis 卡住,從而影響業務使用 或 對 Redis 請求太多次,資源消耗多,遍歷數據太慢。

二、開啓 aof,通過 aof 文件獲取所有的數據。

  • 優點:無需影響 Redis 服務,完全離線操作,足夠安全。
  • 缺點:有一些 Redis 實例寫入頻繁,不適合開啓 aof,普適性不強;aof 文件有可能特別大,傳輸、解析起來太慢,效率低。

三、使用 bgsave,獲取 rdb 文件,解析後獲取數據。

  • 優點:機制成熟,可靠性好;文件相對小,傳輸、解析效率高。
  • 缺點:bgsave 雖然會 fork 子進程,但還是有可能導致主進程卡住一段時間,對業務有產生影響的風險。

綜合評估後,決定採用低峯期在從節點做 bgsave 獲取 rdb 文件,相對安全可靠,也可以覆蓋所有業務的 Redis 集羣。

也就是說每個實例每天在低峯期自動生成一個 .rdb 文件,即使報表數據有一天的延遲也是可以接受的。

“哦,原來.rdb文件是磁盤的緩存文件,那麼如何開啓持久化呢?”

下面簡單的介紹下,Redis 的持久化。

Redis 支持兩種方式的持久化,一種是RDB方式,一種是AOF方式。

RDB 是 Redis 用來進行持久化的一種方式,是把當前內存中的數據集,快照寫入磁盤。

RDB - 自動

RDB(Redis DataBase)方式是通過快照完成的,當符合一定條件時Redis會自動將內存中的所有數據進行快照,並且存儲到硬盤上,RDB是Redis的默認持久化方式。

vim /usr/local/redis/conf/redis.conf

save 900 1    #15分鐘內有至少1個鍵被更改
save 300 10   #5分鐘內至少有10個鍵被更改
save 60 1000  #1分鐘內至少有10000個鍵被更改

#以上條件都是或的關係,當滿足其一就會進行快照。

dbfilename "dump.rdb"       #持久化文件名稱
dir "/data/dbs/redis/6381"  #持久化數據文件存放的路徑

#配置文件修改後,需要重啓redis服務。

還可以通過命令行的方式進行配置:

CONFIG GET save    #查看redis持久化配置

CONFIG SET save "100 20" #修改redis持久化配置

#使用命令行的方式配置,即時生效,服務器重啓後需要重新配置。

RDB - 手動

  • save

該命令會阻塞當前Redis服務器,執行save命令期間,Redis不能處理其他命令,直到RDB過程完成爲止。

顯然該命令對於內存比較大的實例會造成長時間阻塞,這是致命的缺陷。

  • bgsave

執行該命令時,Redis會在後臺異步進行快照操作,快照同時還可以響應客戶端請求。

具體操作是Redis進程執行fork操作創建子進程,RDB持久化過程由子進程負責,完成後自動結束。阻塞只發生在fork階段。

AOF

AOF(APPEND ONLY MODE)是通過保存對redis服務端的寫命令(如set、sadd、rpush)來記錄數據庫狀態的,即保存你對redis數據庫的寫操作。

配置日誌文件如下:

vim /usr/local/redis/conf/redis.conf
dir "/data/dbs/redis/6381"           #AOF文件存放目錄
appendonly yes                       #開啓AOF持久化,默認關閉
appendfilename "appendonly.aof"      #AOF文件名稱(默認)
appendfsync no                       #AOF持久化策略
auto-aof-rewrite-percentage 100      #觸發AOF文件重寫的條件(默認)
auto-aof-rewrite-min-size 64mb       #觸發AOF文件重寫的條件(默認)

#上面的每個參數,可以找資料瞭解下,不做多解釋了。

RDB 與 AOF 的優缺點,見上面的即可。

至此,我們瞭解了 Redis 持久化的一些配置,裏面的細節建議查詢相關資料進行研究。

接下來繼續,通過上一步我們拿到了 rdb 文件,就相當於拿到了Redis實例的數據。

  1. 解析 rdb 文件,獲取key和value的值。
  2. 根據相應的數據結構及內容,估算內存消耗。
  3. 統計並生成報表。

分析工具

小結

  1. 講解了工作中常用的 redis 使用場景。
  2. 講解了 redis 持久化的兩個方式(RDB、AOF)。
  3. 推薦了兩個分析rdb的工具。

通過對 redis 的使用 到 瞭解到服務器上如何對redis數據做持久化快照,再到如何利用工具進行分析rdb文件,最後通過分析後的數據,可以反過來對 redis 的使用提出一些建議。

其他知識點也是這樣,我們不能只停留在方法的簡單調用,就覺得理解了這門技術!

聯想

其實上面分析出來的數據,是不可能定位到這個key是哪個業務方的,哪個開發創建的,是否重要等等,那我們應該怎麼做呢?

  1. 制定開發團隊的Redis Key的使用規範,通過key的命名可以得到:

    • 屬於什麼業務(加域名錶示)
    • 屬於什麼數據類型(加數據類型標示)
    • 是否設置過期時間
    • ...
  2. 統一平臺進行Redis Key的申請,只有申請了才能進行使用:

    • 填寫申請人
    • 填寫申請時間
    • 填寫申請業務方
    • 填寫數據類型
    • 填寫Key的重要性
    • 填寫Key是否存在過期時間
    • 根據填寫項生成規範的key名稱
    • ...(等等需要標記的)
  3. 上面我們已經能分析出某個redis實例rdb文件的內容,通過分析出來的內容 與 統一平臺申請的數據,進行整合,分析key的合格率、內存使用量、不同數據類型的分佈、內存佔用量Top 100的值 等等。
  4. 我們可以通過運維瞭解到,每個服務器與實例之間的配置關係,就可以瞭解到某臺服務器(N個實例)上的 key的合格率、內存使用量、不同數據類型的分佈、內存佔用量Top 100的值等等。

這樣,在後臺系統中就可以看到哪臺服務器,哪個實例的使用情況,解決了Redis濫用並無法進行監控的問題。

推薦閱讀

clipboard.png

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