主頁 > 知識庫 > 詳解Redis瘦身指南

詳解Redis瘦身指南

熱門標(biāo)簽:山東外呼銷售系統(tǒng)招商 日本中國地圖標(biāo)注 十堰營銷電銷機(jī)器人哪家便宜 貴州電銷卡外呼系統(tǒng) 超呼電話機(jī)器人 鄭州人工智能電銷機(jī)器人系統(tǒng) 宿遷便宜外呼系統(tǒng)平臺(tái) 北京400電話辦理收費(fèi)標(biāo)準(zhǔn) 魔獸2青云地圖標(biāo)注

Redis內(nèi)存回收

Redis 服務(wù)器的最大占用內(nèi)存量由配置項(xiàng) maxmemory 決定,我們可以通過 config set maxmemory 2GB 的格式來配置。一旦 Redis 內(nèi)存滿,所有引起內(nèi)存增加的操作都會(huì)被返回 error。作為專業(yè) Redis 服務(wù)器我們通常將此項(xiàng)設(shè)置為0,以服務(wù)器系統(tǒng)內(nèi)存來作為限制;

那么 Redis 使用內(nèi)存達(dá)到了上限怎么辦?Redis 為我們提供了幾種選項(xiàng)以自動(dòng)回收內(nèi)存,可以通過配置項(xiàng) maxmemory-policy 來配置;

  • noeviction 不回收;
  • allkeys-lru 從所有鍵中刪除最近最少使用的鍵;
  • volatile-lru 從設(shè)置了過期時(shí)間的鍵中刪除最近最少使用的鍵;
  • allkeys-random 從所有鍵中隨機(jī)刪除;
  • volatile-random 從設(shè)置了過期時(shí)間的鍵中隨機(jī)刪除;
  • volatile-ttl 從設(shè)置了過期時(shí)間的鍵中選擇存活時(shí)間最短的鍵刪除;

最大內(nèi)存回收策略需要根據(jù)業(yè)務(wù)來配置,如果純粹做緩存,allkeys-lru無疑是最合適的。如果存儲(chǔ)了稍微重要的數(shù)據(jù),為了防止 Redis 誤刪一些重要鍵,則需要選用 noeviction;

allkeys-lru、allkeys-random 在內(nèi)存滿時(shí)都有鍵可刪,可以騰出內(nèi)存,但如果配置了其他的策略,數(shù)據(jù)庫用久了(根據(jù)業(yè)務(wù)量),隨著業(yè)務(wù)發(fā)展和數(shù)據(jù)積累,通常會(huì)累積到到服務(wù)器內(nèi)存占用率高,利用率低的情況,則可能會(huì)遇到內(nèi)存占用滿的問題。

問題原由

產(chǎn)生問題的原因有:

持久鍵廢棄

這是導(dǎo)致此問題的最常見情況。

有時(shí)候是開發(fā)人員的鍋,開發(fā)不規(guī)范,未給有時(shí)效性的鍵設(shè)置過期時(shí)間,后續(xù)又不進(jìn)行手動(dòng)刪除,鍵就成為無人管的孤兒鍵了。

還可能是整個(gè)業(yè)務(wù)慢慢被廢棄,不知道哪一天起,業(yè)務(wù)整體已不再維護(hù)了,一批鍵自然也就沒用了。比這更嚴(yán)重的是,如果使用 List 傳遞數(shù)據(jù),消費(fèi)進(jìn)程已被停止,但生產(chǎn)進(jìn)程未同步停止,還在往 Redis 里寫數(shù)據(jù)。

過期鍵未回收

這個(gè)原因首先要談到 Redis 的兩種過期鍵刪除策略:

  • 惰性刪除:在讀取鍵時(shí)發(fā)現(xiàn)鍵已過期,則將其刪除。
  • 定期刪除:Redis 會(huì)從所有設(shè)置了過期時(shí)間的鍵中選取 100 個(gè),刪除已過期的鍵,如果已過期的鍵超過 25 個(gè),則再次進(jìn)行此操作。 此刪除操作由配置項(xiàng) hz 決定,Redis 默認(rèn)每秒進(jìn)行 10 次;

如果我們產(chǎn)生過期鍵的速度很快,最多可導(dǎo)致 Redis 25% 的過期鍵沒有被及時(shí)刪除。

遍歷清除垃圾鍵

由上,明白了問題產(chǎn)生的原因,解決 Redis 內(nèi)存滿的方法就明確了:清除這些垃圾鍵。 于是就面臨著兩個(gè)問題:

如何遍歷鍵

對于查找鍵,我們首先想到的是 KEYS,但 KEYS 的時(shí)間復(fù)雜度是O(n),n 是 Redis 內(nèi)鍵的總數(shù),如果 Redis 內(nèi)鍵很多還是會(huì)有性能問題,導(dǎo)致其他命令被阻塞的。

這里介紹一個(gè)鍵遍歷命令: SCAN。

SCAN cursor:

0 => cursor, // cursor = 0 遍歷結(jié)束
1 => array(key1, key2...)

需要注意的是 SCAN 命令是在版本2.8.0 加入的,如果是之前的版本,可以考慮解析 Redis 的 RDB 文件來獲取所有的鍵。

如何判斷鍵是否垃圾

我們有三種異常鍵需要處理:

  • 過期鍵:這些鍵會(huì)在被 SCAN 到時(shí)被自動(dòng)刪除,不再考慮。如果是解析 RDB 文件獲取到的鍵,在查詢時(shí)也會(huì)被自動(dòng)刪除;
  • 長時(shí)間未讀寫的鍵,很可能是業(yè)務(wù)不再需要的鍵;
  • 占用大量內(nèi)存的鍵,有可能是在不停地寫,但未消費(fèi)。

這里介紹 Redis 的另一個(gè)命令 OBJECT,使用它可以從內(nèi)部查看 key 對象的狀態(tài)。使用 OBJECT IDLETIME key 來獲取 key 的閑置時(shí)間,我們可以判斷 key 閑置時(shí)間大于一個(gè)時(shí)間段(根據(jù)業(yè)務(wù)自定)的為已廢棄。

此外還能使用 OBJECT REFCOUNT key獲取 key 引用所儲(chǔ)存的值的次數(shù),OBJECT ENCODING key 獲取 key 儲(chǔ)存的值所使用的內(nèi)部表示。

獲取鍵大小

而獲取 Redis 某鍵占用內(nèi)存大小,則通過另一個(gè)命令 DEBUG OBJECT 來獲取,此命令會(huì)返回比OBJECT命令更詳細(xì)的內(nèi)部數(shù)據(jù)。

DEBUG OBJECT test
Value at:0x7fb0ee16ebd0 refcount:1 encoding:embstr serializedlength:6 lru:12362780 lru_seconds_idle:4

結(jié)果包括內(nèi)存地址、引用數(shù)、內(nèi)部編碼表示、序列化后的長度、最近最少使用標(biāo)識值,閑置時(shí)間,我們可以解析此結(jié)果串來獲取對應(yīng)的數(shù)據(jù)。

需要注意,key 作為復(fù)合鍵擁有大量字段時(shí)使用 DEBUG 命令計(jì)算內(nèi)存會(huì)使 Redis 阻塞較長時(shí)間,且 Redis 官方并不建議在客戶端使用此命令。

我們也可以先使用 TYPE key 獲取鍵的類型,再根據(jù)類型獲取其鍵的大小,如對字符串使用LEN,對 哈希表使用HLEN。

要注意在刪除特別大的復(fù)合鍵時(shí),建議先逐步清空鍵內(nèi)的字段,防止因字段過多,Redis 阻塞較長時(shí)間。

管道加速

Redis 支持 pipeline 管道技術(shù),一次 請求/響應(yīng) 服務(wù)器能實(shí)現(xiàn)處理并響應(yīng)多個(gè)請求。這樣就可以將多個(gè)命令同時(shí)發(fā)送到服務(wù)器,不等待回復(fù),直接在最后獲取多個(gè)結(jié)果。

PHP 中使用 MULTI(Redis::PIPELINE) 和 EXEC() 命令來實(shí)現(xiàn)管道;

腳本實(shí)現(xiàn)

下面是個(gè)簡單的腳本:

$redis = new Redis();
$redis->connect('127.0.0.1');
do {
    $keys = $redis->scan($cursor);

    $pipeline = $redis->multi(Redis::PIPELINE);
    foreach ($keys as $key) {
        $idle_time = $redis->object('idletime', $key);
        if ($idle_time > 180 * 24 * 3600) {
            $pipeline->del($key);
        }
        // todo 判斷類型進(jìn)而判斷占用內(nèi)存大小,再刪除
    }
    $pipeline->exec();
} while ($cursor != 0);

從根源避免問題

以上的腳本肯定也會(huì)在刪除鍵時(shí)影響 Redis 的效率,最好的情況還是從根源就避免此類情況,以下是一些建議:

  • 規(guī)范化開發(fā);
  • 首先是鍵命名要規(guī)范,讓人見名知義,這樣在人工排錯(cuò)或刪除時(shí)也有判斷依據(jù),然后最好有完善的 Redis 鍵文檔,以保證業(yè)務(wù)在很長時(shí)間,經(jīng)手多人后也能資料可查。
  • 使用 HashSet 替代 Key-Value;
  • 將業(yè)務(wù)中某一族的鍵以 HashSet 的方式存儲(chǔ),以替代普通的 key-value 類型。不僅可以省去為每個(gè)鍵設(shè)置前綴以節(jié)約內(nèi)存,也便于統(tǒng)一管理。
  • 有時(shí)效性的鍵注意設(shè)置過期時(shí)間;
  • 合理設(shè)置定時(shí)清除過期鍵頻率 hz,在 Redis 不做多余操作的情況下,使過期鍵盡量能被刪除;
  • 做好 Redis 內(nèi)存的監(jiān)控,在達(dá)到某個(gè)閾值時(shí)查找問題并解決。

小結(jié)

Redis假死

我在使用守護(hù)進(jìn)程時(shí) Redis 有假死情況,PHP 和 Redis 都不報(bào)錯(cuò),但命令都返回 false,這種情況可以使用 Redis 的 ping() 命令,來探測 Redis 連接是否還在,如果不在則再建立新的連接。此問題很可能是由服務(wù)器配置引起的,如果您有知道此問題的原由或有好的解決辦法,煩請指點(diǎn)一二。

危險(xiǎn)命令

不要在沒看文檔的情況下在線上使用 Redis 命令,例如 debug segfault,別問我怎么知道的。

以上就是詳解Redis瘦身指南的詳細(xì)內(nèi)容,更多關(guān)于Redis瘦身指南的資料請關(guān)注腳本之家其它相關(guān)文章!

您可能感興趣的文章:
  • 基于Docker搭建Redis主從集群的實(shí)現(xiàn)
  • redis實(shí)現(xiàn)共同好友的思路詳解

標(biāo)簽:吉安 臺(tái)州 江蘇 楊凌 大慶 朝陽 北京 果洛

巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《詳解Redis瘦身指南》,本文關(guān)鍵詞  詳解,Redis,瘦身,指南,詳解,;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問題,煩請?zhí)峁┫嚓P(guān)信息告之我們,我們將及時(shí)溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無關(guān)。
  • 相關(guān)文章
  • 下面列出與本文章《詳解Redis瘦身指南》相關(guān)的同類信息!
  • 本頁收集關(guān)于詳解Redis瘦身指南的相關(guān)信息資訊供網(wǎng)民參考!
  • 推薦文章