使用過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), 顧名思義,就是很悲觀。git

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

場景:若是項目中使用了緩存且對緩存設置了超時時間。redis

當併發量比較大的時候,若是沒有鎖機制,那麼緩存過時的瞬間,數據庫

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

/**
 * 獲取鎖
 * @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), 顧名思義,就是很樂觀。segmentfault

每次去拿數據的時候都認爲別人不會修改,因此不會上鎖。緩存

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是哪一個業務方,哪一個開發建立的?這樣就能夠找他溝通了。

嘗試解決問題的思路

1、先經過 keys * 命令,拿到全部的 key,而後根據 key 再獲取全部的內容。

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

2、開啓 aof,經過 aof 文件獲取全部的數據。

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

3、使用 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

相關文章
相關標籤/搜索