佳木斯湛栽影视文化发展公司

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

詳解Redis瘦身指南

熱門標(biāo)簽:呼叫中心市場需求 服務(wù)外包 百度競價(jià)排名 地方門戶網(wǎng)站 網(wǎng)站排名優(yōu)化 AI電銷 Linux服務(wù)器 鐵路電話系統(tǒng)

Redis內(nèi)存回收

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

那么 Redis 使用內(nèi)存達(dá)到了上限怎么辦?Redis 為我們提供了幾種選項(xià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無疑是最合適的。如果存儲了稍微重要的數(shù)據(jù),為了防止 Redis 誤刪一些重要鍵,則需要選用 noeviction;

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

問題原由

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

持久鍵廢棄

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

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

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

過期鍵未回收

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

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

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

遍歷清除垃圾鍵

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

如何遍歷鍵

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

這里介紹一個鍵遍歷命令: SCAN。

SCAN cursor:

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

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

如何判斷鍵是否垃圾

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

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

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

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

獲取鍵大小

而獲取 Redis 某鍵占用內(nèi)存大小,則通過另一個命令 DEBUG OBJECT 來獲取,此命令會返回比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)存會使 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)多個請求。這樣就可以將多個命令同時(shí)發(fā)送到服務(wù)器,不等待回復(fù),直接在最后獲取多個結(jié)果。

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

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

下面是個簡單的腳本:

$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);

從根源避免問題

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

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

小結(jié)

Redis假死

我在使用守護(hù)進(jìn)程時(shí) Redis 有假死情況,PHP 和 Redis 都不報(bào)錯,但命令都返回 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)簽:銅川 衡水 湘潭 仙桃 黃山 蘭州 崇左 湖南

巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《詳解Redis瘦身指南》,本文關(guān)鍵詞  ;如發(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)文章
  • 收縮
    • 微信客服
    • 微信二維碼
    • 電話咨詢

    • 400-1100-266
    图片| 东光县| 嵩明县| 汤原县| 梨树县| 咸丰县| 深圳市| 房产| 阿巴嘎旗| 呼和浩特市| 棋牌| 文成县| 遵义市| 双江| 鹰潭市| 湟中县| 桦川县| 泸溪县| 莎车县| 中山市| 平罗县| 清镇市| 临潭县| 渭南市| 云和县| 太仆寺旗| 高唐县| 沧州市| 武宣县| 渭南市| 乐至县| 茌平县| 仁寿县| 蒙城县| 仙桃市| 扶风县| 北海市| 石河子市| 舒兰市| 砚山县| 贵德县|