Redis內存使用率增長的一些解決思路


可以把Redis存儲想象成一個有進有出的蓄水池

哪些情況會是Redis服務的內存使用率不斷升高呢

1、將大量新寫入Redis的key的TTL設置為-1,永遠不過期,也就相當於一直往容量一定的蓄水池中加水但是不往外面排水,這時內存使用率一直升高是很顯然的。

2、大量新寫入Redis的eky的TTL時間設置的有點長,相當於這樣的場景:蓄水池的水龍頭快速往水池中加水,但是排水口從蓄水池中排水的速度遠小於加水的速度,那么此時Redis的內存使用率也會一直升高!

一些建議

1、建議把項目中設置Redis的key的地方寫在一起,方便知道線上代碼寫入Redis的key的格式有哪些(因為Redis不像關系型數據庫那樣有很多很好的可視化工具支持查看表結構、表字段等信息~)

2、對於一些非固定的數據,不建議將TTL值設置為-1,比如用戶的一些常用信息我們會緩存到redis中,這樣確實降低了讀取數據庫的IO,提高了效率,但是互聯網的用戶流動量比較大,有可能存入到Redis中的用戶信息,這個用戶到后面不玩我們的產品了,他也沒有注銷~ 這時候我們再redis中存儲的其實就是一條永久的無用的臟數據了!!!—— 實際上建議存24小時或者其他時間,每天只存一些當天活躍或者7天活躍的用戶~~ 這樣效果會更好 —— 網站的session一般都會存7天。

3、Redis的TTL,設置的要合理一些~ 不要太長,這樣排水口的水流出的會很慢,如果進水口進入的水量增加的話,也會使Redis的內存使用率爆增!

問題描述

線上Redis監控發現某一段時間redis的內存使用率在一直升高,當時的時間點是升高的時間:

經過線上處理,首先是停止Redis內存繼續往上升~然后可以去掉一些無用的key~最終使內存使用率降下來。

記得根據實際情況解決問題 ******

❗️但是,提醒一下:需要先評估一下,刪除這些key,對於業務有沒有特別大的影響!如果影響很小,是一個很邊緣的需求,可以這么搞。 

必須的key不要刪除

如果刪除這些key,對於業務的影響很大的話(比如用戶每日的任務等,TTL到當天的24點,刪除的話用戶任務白做了!),這時候就不要去想刪除key去解決內存使用率增高的問題了!

建議:適當的去調整一下新的進入Redis中這些key的TTL值~ 或者 升級一下Redis機器~現在的雲服務器基本都支持平滑升級,並且升級還是很快的,可以將損失降到很低~

非必要的key可以批量刪除

我們自己的業務中,刪除這些key,對於正常業務沒有任何影響!

❗️先在業務代碼中,取消往Redis中寫入這些key的邏輯 ~~ 保證沒有新的key進入Redis,然后再刪除 ———— 刪除完,等Redis的內存下來以后,可以再加回來相關的邏輯,但是TTL不要設置的太大了!!!

使用一個demo來說明一下解決思路 ***

在本地docker搭建一下redis服務,使用db1,里面有1個key

 

寫一個python腳本往里面分別插入3種不同的key

import random
from datetime import date

import redis


today_str = date.today().strftime("%Y-%m-%d")
print(">>> ", today_str, type(today_str))

# redis key 的格式
key1 = "redis_demo:test1:{}:{}"  # redis_demo:test1:(2021-12-25):(隨機字符串)
key2 = "redis_demo:test2:{}:{}"  # redis_demo:test1:(2021-12-25):(隨機字符串)
key3 = "redis_demo:test3:{}:{}"  # redis_demo:test1:(2021-12-25):(隨機字符串)

# redis鏈接 # 注意這里我用的是 db1 ———— 沒有用Redis集群,用的是一個Redis實例
r = redis.Redis(host="127.0.0.1", port=6379, db=1)


# 往Redis中模擬插入1w個key1、key2、key3類型的字符串
for i in range(10000):
    curr_key1 = key1.format(today_str, str(random.randint(0,1000000)))
    curr_key2 = key2.format(today_str, str(random.randint(0,1000000)))
    curr_key3 = key3.format(today_str, str(random.randint(0,1000000)))
    curr_value = str(random.randint(0,10000))

    # 都在10000秒后失效
    r.set(curr_key1, curr_value, 10000)
    r.set(curr_key2, curr_value, 10000)
    r.set(curr_key3, curr_value, 10000)

看看db1中的dbsize

如果線上key比較多千萬不能使用 keys * 相關命令!會阻塞Redis服務!

如果線上key比較多千萬不能使用keys *相關命令!會阻塞Redis服務!

使用scan命令找key

scan 0 match redis_demo:test1* 

但是找出來以后,不可能一個一個執行 del 命令刪除~~ 太浪費時間了。

可以在終端執行 redis-cli 相關命令。

使用redis-cli命令將所有key輸出到文件中然后寫腳本del相關的key ***

選擇db1,然后將match到的key輸出到文件中:

redis-cli -h 127.0.0.1 -p 6379 -n 1 --scan --pattern "redis_demo:test1*" > redis_demo的test1的key.txt

也可以看看文件有多少行:

cat redis_demo的test1的key.txt |wc -l

—— 也就是有9962個key,里面都是完整的redis的key,后面可以寫一個腳本,一行一行從文件中讀取這些key,然后在redis中執行del操作刪除key!

使用redis-cli配合xargs命令使用命令刪除scan命令獲取到的key ***

注意:需要選擇 db1  —— 實際上可以同時刪除1000條數據~~

redis-cli -h 127.0.0.1 -p 6379 -n 1 --scan --pattern "redis_demo:test1*" |xargs -L 10 redis-cli -h 127.0.0.1 -p 6379 -n 1  del

把test2與test3也一起刪掉,可以同時刪1000條數據

最后再進去看看只剩下一開始的那個key了

參考文章

Redis在命令行中操作指定數據庫下的key

redis cli命令 ***

redis scan 優雅的批量刪除

深入理解Redis的scan命令

Redis scan命令解析——替代keys命令可以在生產環境使用實現遍歷

Redis Scan 原理解析與踩坑 

~~~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM