Redis Cluster內存爆滿

今天遇到一個問題
MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk. Commands that may modify the data set are disabled. Please check Redis logs for details about the error.

在這裏插入圖片描述
網上很多帖子都說通過redis-cli 執行命令 config set stop-writes-on-bgsave-error no可以解決,但是這僅僅是讓程序忽略了這個異常,使得程序能夠繼續往下運行,但實際上數據還是會存儲到硬盤失敗!
不過爲了先快速解決問題,讓用戶先能夠登錄進系統,所以我還是在每個主節點執行了config set stop-writes-on-bgsave-error no。

但是進入系統的時候報了MISSCONF Errors writing to the AOF file:No space left on device錯誤,這是因爲我訪問這個頁面的時候代碼有對redis集羣做寫操作,要往redis集羣寫數據,但是內存空間不足造成的。
在這裏插入圖片描述
遇到這個類似內存不足的情況不要慌,大致的解決思路無非就兩個,要不就是加大redis集羣的內存,要不就把redis集羣中沒用的數據清除掉,把空間騰出來。

我選擇把redis 集羣中沒用的數據清除掉這種解決思路。

首先我就要排查是什麼數據導致redis的內存撐爆了,哪些數據是可以清楚的。

由於我使用的是JedisCluster對集羣做操作的,所以往redis集羣寫數據的地方必定是調用了redisCluster.set方法的,通過IntelliJ工具(按ctrl+H快捷鍵),我們可以很方便的找到我們哪些地方往redis集羣寫數據,如下圖
在這裏插入圖片描述
通過對每一個jedisCluster.set方法的檢查,我把對redis集羣的寫操作總結爲以下五種。發現造成redis集羣內存爆滿應該是因爲第3點與第6點。
第3點因爲用戶的token不是固定的,每次token改變都會往redis集羣裏寫一條新的數據,有沒有清除機制,導致數據堆積。
第6點是因爲只要這四種列表有新的數據,就會往redis集羣裏寫一條新的數據(爲了實現未讀顯示紅點功能),而且value還是一個多字段的對象,佔用內存比較嚴重。
在這裏插入圖片描述

發現了產生堆積的地方,接下來就是如果去改正了。
首先我先修改程序,爲第3點的manager token增加一個過期時間,把第6點的業務邏輯由永遠不過期該爲只要查看了就從redis集羣中移除。

然後就是清除以往堆積的數據了(先根據實際情況考慮是否能清除,清除後會有什麼影響),我這裏把第3點的manager token清除對用戶沒什麼影響,只需要重新登錄就可以了。把第6點的數據清除,只是會在訪問列表的時候,會多了一個紅點。

如果批量清除redis cluster中的某個前綴key的數據?
我的是linux系統,
新建一個redis_del.sh文件,文件的內容如下

#!/bin/bash
redis_comm=/home/docker-compose/redis/redis-5.0.5/src/redis-cli
redis_ser01=120.24.168.90
redis_ser02=120.24.168.90
redis_ser03=120.24.168.90
port01=7000
port02=7001
port03=7002
$redis_comm -c -h $redis_ser01 -p $port01 -a 123456 keys $1 | xargs -i ./redis-cli -c -h $redis_ser01 -p $port01 -a 123456 del {}
$redis_comm -c -h $redis_ser02 -p $port02 -a 123456 keys $1 | xargs -i ./redis-cli -c -h $redis_ser02 -p $port02 -a 123456 del {}
$redis_comm -c -h $redis_ser03 -p $port03 -a 123456 keys $1 | xargs -i ./redis-cli -c -h $redis_ser03 -p $port03 -a 123456 del {}

在這裏插入圖片描述
這裏注意的是,建議直接在linux系統上面新建一個文件touch redis_del.sh,不要在windows系統上面建好再複製上去,因爲例如上我上一張截圖,在windows下使用nodepad++寫好這個redis_del文件再上傳上linux服務器,這個文件會有一個編碼問題,導致執行會出錯-bash: ./redis_del.sh: /bin/bash^M: bad interpreter: No such file or directory。

另外,如果執行redis_del.sh腳本的時候報-bash: ./redis_del.sh: Permission denied,先執行以下命令chmod -R 777 redis_del.sh

開始執行sh腳本刪除數據,輸入命令./redis_del.sh keys*
刪除成功,如下圖
在這裏插入圖片描述

=分割線===================
上面以爲修復了的MISCONF Errors writing to the AOF file: No space left on device,今天又報了,也就是說昨天的解決思路是不完全正確的,這個錯誤說磁盤空間不足了,我們首先應該在宿主機執行df -h命令看一下內存的使用情況,如下圖,可以看到,use%已經100%了。
在這裏插入圖片描述
到時是哪裏佔用了那麼大的內存呢?我們首先回到根目錄,然後使用du -sh * 命令,從根目錄一層一層往裏面看,看看到底是哪個目錄佔用的資源最大,如下圖
在這裏插入圖片描述
先看看log目錄,佔了15G,我整個雲服務器磁盤空間才40G,日誌給我整了15G!?這不是開玩笑嗎,首先想到這裏面的日誌有哪些是可以刪的,裏面有個journalctl 目錄,佔的空間比較大,佔了3.9G
在這裏插入圖片描述
在這裏插入圖片描述

journal 目錄是什麼?

journalctl 用來查詢 systemd-journald 服務收集到的日誌。systemd-journald 服務是 systemd init 系統提供的收集系統日誌的服務。

只要你不需要日誌進行任何調試,可以刪除 /var/log/journal/* 內的所有內容,但不要刪除目錄本身。

你應該看看/etc/systemd/journald.conf,有一個設置可以限制系統存儲的日誌量(下文有介紹),因此舊的日誌會被輪換出來。這個設置並不完美,因爲損壞的文件顯然不會計入這個總數(至少在幾個月之前是這種情況,不確定它現在是否已修復)。

控制 journal 目錄大小

可以使用/etc/systemd/journald.conf中的此參數控制此目錄的大小:

SystemMaxUse=50M

關於journald.conf文件裏面的參數配置的具體含義,可以參考這篇博客:
https://blog.51cto.com/wutengfei/2336490?source=dra

如果上述信令方法不這樣做,你可能需要重新啓動日誌記錄服務以強制進行日誌輪換。你可以像這樣重啓服務:

$ sudo systemctl kill --kill-who=main --signal=SIGUSR2 systemd-journald.service

系統日誌messages佔用空間

/var/log/messages ** – 包含整個系統的信息,包括系統啓動期間被記錄的日誌。mail, cron, daemon, kern, auth等相關的日誌信息在這裏記錄。**
https://blog.csdn.net/zzq900503/article/details/79345929
在這裏插入圖片描述

docker的鏡像文件佔用很大的空間

我們一層層的du -sh * 進來,可以發現/var/lib/docker/overlay2目錄佔用了很大的內存。
https://blog.csdn.net/weixin_32820767/article/details/81196250
在這裏插入圖片描述
可以發現鏡像文件佔用了22.23G
在這裏插入圖片描述
然後用docker images 命令查看一下現有的鏡像,什麼鬼,這些不知道怎麼創建的(可以是構建reids cluster的時候創建的,因爲當時我構建redis cluster時構建了很多次才成功)。
在這裏插入圖片描述
清掉這些沒用的鏡像之後,釋放了大部分的資源。
在這裏插入圖片描述
https://blog.csdn.net/weixin_32820767/article/details/81196250

總結:
1. 在設計redis的時候,不管是單機還是集羣,都需要考慮內存的分配是否合理。
2. 往redis裏存數據的時候,一定要考慮存進去的數據是否應該清除,什麼時清除,以免造成數據堆積。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章