使用過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實例的數據。
- 解析 rdb 文件,獲取key和value的值。
- 根據相應的數據結構及內容,估算內存消耗。
- 統計並生成報表。
分析工具
- 雪球 rdr:https://github.com/xueqiu/rdr
- redis-rdb-tools:https://github.com/sripathikr...
小結
- 講解了工作中常用的 redis 使用場景。
- 講解了 redis 持久化的兩個方式(RDB、AOF)。
- 推薦了兩個分析rdb的工具。
通過對 redis 的使用 到 瞭解到服務器上如何對redis數據做持久化快照,再到如何利用工具進行分析rdb文件,最後通過分析後的數據,可以反過來對 redis 的使用提出一些建議。
其他知識點也是這樣,我們不能只停留在方法的簡單調用,就覺得理解了這門技術!
聯想
其實上面分析出來的數據,是不可能定位到這個key是哪個業務方的,哪個開發創建的,是否重要等等,那我們應該怎麼做呢?
-
制定開發團隊的Redis Key的使用規範,通過key的命名可以得到:
- 屬於什麼業務(加域名錶示)
- 屬於什麼數據類型(加數據類型標示)
- 是否設置過期時間
- ...
-
統一平臺進行Redis Key的申請,只有申請了才能進行使用:
- 填寫申請人
- 填寫申請時間
- 填寫申請業務方
- 填寫數據類型
- 填寫Key的重要性
- 填寫Key是否存在過期時間
- 根據填寫項生成規範的key名稱
- ...(等等需要標記的)
- 上面我們已經能分析出某個redis實例rdb文件的內容,通過分析出來的內容 與 統一平臺申請的數據,進行整合,分析key的合格率、內存使用量、不同數據類型的分佈、內存佔用量Top 100的值 等等。
- 我們可以通過運維瞭解到,每個服務器與實例之間的配置關係,就可以瞭解到某臺服務器(N個實例)上的 key的合格率、內存使用量、不同數據類型的分佈、內存佔用量Top 100的值等等。
這樣,在後臺系統中就可以看到哪臺服務器,哪個實例的使用情況,解決了Redis濫用並無法進行監控的問題。
推薦閱讀