共計 6843 個字符,預計需要花費 18 分鐘才能閱讀完成。
這篇文章主要介紹“redis4.0 下 MEMORY 命令詳解”,在日常操作中,相信很多人在 redis4.0 下 MEMORY 命令詳解問題上存在疑惑,丸趣 TV 小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”redis4.0 下 MEMORY 命令詳解”的疑惑有所幫助!接下來,請跟著丸趣 TV 小編一起來學習吧!
前言
在過去,查看 redis 的內存使用狀態只有 info memory 命令,而且也只有一些基礎信息,想要獲取全局信息就有些困難。4.0 開始 redis 提供了 MEMORY 命令,一切都變得簡單起來。
MEMORY 命令
MEMORY 命令一共有 5 個子命令,可以通過 MEMORY HELP 來查看:
127.0.0.1:6379 memory help
1) MEMORY DOCTOR – Outputs memory problems report
2) MEMORY USAGE key [SAMPLES count] – Estimate memory usage of key
3) MEMORY STATS – Show memory usage details
4) MEMORY PURGE – Ask the allocator to release memory
5) MEMORY MALLOC-STATS – Show allocator internal stats
接下來我們從 MEMORY STATS 開始,一一介紹各個子命令的功能。
1. MEMORY STATS
首先,我們需要明確一個概念,redis 的內存使用不僅包含所有的 key-value 數據,還有描述這些 key-value 的元信息,以及許多管理功能的消耗,比如持久化、主從復制,通過 MEMORY STATS 可以更好的了解到 redis 的內存使用狀況。
這里我們啟動了一個打開持久化功能并且帶 slave 的 redis,向其中隨機寫入了一些數據(某些數據還帶有過期時間),以便讀者可以更好的了解 redis 的內存使用,接下來執行 MEMORY STATS 命令:
127.0.0.1:6379 memory stats
1) peak.allocated
2) (integer) 423995952
3) total.allocated
4) (integer) 11130320
5) startup.allocated
6) (integer) 9942928
7) replication.backlog
8) (integer) 1048576
9) clients.slaves
10) (integer) 16858
11) clients.normal
12) (integer) 49630
13) aof.buffer
14) (integer) 3253
15) db.0
16) 1) overhead.hashtable.main
2) (integer) 5808
3) overhead.hashtable.expires
4) (integer) 104
17) overhead.total
18) (integer) 11063904
19) keys.count
20) (integer) 94
21) keys.bytes-per-key
22) (integer) 12631
23) dataset.bytes
24) (integer) 66416
25) dataset.percentage
26) 5.5934348106384277
27) peak.percentage
28) 2.6251003742218018
29) fragmentation
30) 1.1039986610412598
一共有 15 項內容,內存使用量均以字節為單位,我們一個一個來看:
1. peak.allocated
redis 啟動到現在,最多使用過多少內存。
2. total.allocated
當前使用的內存總量。
3. startup.allocated
redis 啟動初始化時使用的內存,有很多讀者會比較奇怪,為什么我的 redis 啟動以后什么都沒做就已經占用了幾十 MB 的內存?
這是因為 redis 本身不僅存儲 key-value,還有其他的內存消耗,比如共享變量、主從復制、持久化和 db 元信息,下面各項會有詳細介紹。
4. replication.backlog
主從復制 backlog 使用的內存,默認 10MB,backlog 只在主從斷線重連時發揮作用,主從復制本身并不依賴此項。
5. clients.slaves
主從復制中所有 slave 的讀寫緩沖區,包括 output-buffer(也即輸出緩沖區)使用的內存和 querybuf(也即輸入緩沖區),這里簡單介紹一下主從復制:
redis 把一次事件循環中,所有對數據庫發生更改的內容先追加到 slave 的 output-buffer 中,在事件循環結束后統一發送給 slave。
那么主從之間就難免會有數據的延遲,如果主從之間連接斷開,重連時為了保證數據的一致性就要做一次全量同步,這顯然是不夠高效的。backlog 就是為此而設計,master 在 backlog 中緩存一部分主從復制的增量數據,斷線重連時如果 slave 的偏移量在 backlog 中,那就可以只把偏移量之后的增量數據同步給 slave 即可,避免了全量同步的開銷。
6. clients.normal
除 slave 外所有其他客戶端的讀寫緩沖區。
有時候一些客戶端讀取不及時,就會造成 output-buffer 積壓占用內存過多的情況,可以通過配置項 client-output-buffer-limit 來限制,當超過閾值之后 redis 就會主動斷開連接以釋放內存,slave 亦是如此。
7. aof.buffer
此項為 aof 持久化使用的緩存和 aofrewrite 時產生的緩存之和,當然如果關閉了 appendonly 那這項就一直為 0:
redis 并不是在有寫入時就立即做持久化的,而是在一次事件循環內把所有的寫入數據緩存起來,待到事件循環結束后再持久化到磁盤。
aofrewrite 時緩存增量數據使用的內存,只在 aofrewrite 時才會使用,aofrewrite 機制可以參考之前的文章《redis4.0 之利用管道優化 aofrewrite》。
可以看出這一項的大小與寫入流量成正比。
8. db.0
redis 每個 db 的元信息使用的內存,這里只使用了 db0,所以只打印了 db0 的內存使用狀態,當使用其他 db 時也會有相應的信息。
db 的元信息有以下三項:
a) redis 的 db 就是一張 hash 表,首先就是這張 hash 表使用的內存(redis 使用鏈式 hash,hash 表中存放所有鏈表的頭指針);
b) 每一個 key-value 對都有一個 dictEntry 來記錄他們的關系,元信息便包含該 db 中所有 dictEntry 使用的內存;
c) redis 使用 redisObject 來描述 value 所對應的不同數據類型(string、list、hash、set、zset),那么 redisObject 占用的空間也計算在元信息中。
overhead.hashtable.main:
db 的元信息也即是以上三項之和,計算公式為:
hashtable + dictEntry + redisObject
overhead.hashtable.expires:
對于 key 的過期時間,redis 并沒有把它和 value 放在一起,而是單獨用一個 hashtable 來存儲,但是 expires 這張 hash 表記錄的是 key-expire 信息,所以不需要 `redisObject` 來描述 value,其元信息也就少了一項,計算公式為:
hashtable + dictEntry
9. overhead.total
3- 8 項之和:startup.allocated+replication.backlog+clients.slaves+clients.normal+aof.buffer+dbx
10. dataset.bytes
所有數據所使用的內存——也即 total.allocated – overhead.total——當前內存使用量減去管理類內存使用量。
11. dataset.percentage
所有數據占比,這里并沒有直接使用 total.allocated 做分母,而是除去了 redis 啟動初始化的內存,計算公式為:
100 * dataset.bytes / (total.allocated – startup.allocated)
12. keys.count
redis 當前存儲的 key 總量
13. keys.bytes-per-key
平均每個 key 的內存大小,直覺上應該是用 dataset.bytes 除以 keys.count 即可,但是 redis 并沒有這么做,而是把管理類內存也平攤到了每個 key 的內存使用中,計算公式為:
(total.allocated – startup.allocated) / keys.count
14. peak.percentage
當前使用內存與歷史最高值比例
15. fragmentation
內存碎片率
2. MEMORY USAGE
相信所有 redis 用戶都希望對每一個 key-value 的內存使用了如指掌,然而 4.0 之前 redis 并沒有提供一個明確的方法來進行內存評估,不過從 4.0 開始,MEMORY 命令實現了這一功能。
首先看下使用方法:MEMORY usage [samples]
命令參數不多,通過字面意思也可以看出來是評估指定 key 的內存使用情況。samples 是可選參數默認為 5,以 hash 為例看下其如果工作:
首先類似于上一節中的 overhead.hashtable.main,要計算 hash 的元信息內存,包括 hash 表的大小以及所有 dictEntry 的內存占用信息。
與 overhead.hashtable.main 不同的是,每個 dictEntry 中 key-value 都是字符串,所以沒 redisObject 的額外消耗。在評估真正的數據內存大小時 redis 并沒有去遍歷所有 key,而是采用的抽樣估算:隨機抽取 samples 個 key-value 對計算其平均內存占用,再乘以 key-value 對的個數即得到結果。試想一下如果要精確計算內存占用,那么就需要遍歷所有的元素,當元素很多時就是使 redis 阻塞,所以請合理設置 samples 的大小。
其他數據結構的計算方式類似于 hash,此處就不再贅述。
3. MEMORY DOCTOR
此項子命令是作者給出的關于 redis 內存使用方面的建議,在不同的允許狀態下會有不同的分析結果:
首先是沒問題的情況
運行狀態良好:
Hi Sam, I can t find any memory issue in your instance. I can only account for what occurs on this base.
redis 的數據量很小,暫無建議:
Hi Sam, this instance is empty or is using very little memory, my issues detector can t be used in these conditions. Please, leave for your mission on Earth and fill it with some data. The new Sam and I will be back to our programming as soon as I finished rebooting.
接下來出現的結果就需要注意了
內存使用峰值 1.5 倍于目前內存使用量,此時內存碎片率可能會比較高,需要注意:
Peak memory: In the past this instance used more than 150% the memory that is currently using. The allocator is normally not able to release memory after a peak, so you can expect to see a big fragmentation ratio, however this is actually harmless and is only due to the memory peak, and if the Redis instance Resident Set Size (RSS) is currently bigger than expected, the memory will be used as soon as you fill the Redis instance with more data. If the memory peak was only occasional and you want to try to reclaim memory, please try the MEMORY PURGE command, otherwise the only other option is to shutdown and restart the instance.
內存碎片率過高超過 1.4,需要注意:
High fragmentation: This instance has a memory fragmentation greater than 1.4 (this means that the Resident Set Size of the Redis process is much larger than the sum of the logical allocations Redis performed). This problem is usually due either to a large peak memory (check if there is a peak memory entry above in the report) or may result from a workload that causes the allocator to fragment memory a lot. If the problem is a large peak memory, then there is no issue. Otherwise, make sure you are using the Jemalloc allocator and not the default libc malloc.
每個 slave 緩沖區的平均內存超過 10MB,原因可能是 master 寫入流量過高,也有可能是主從同步的網絡帶寬不足或者 slave 處理較慢:
Big slave buffers: The slave output buffers in this instance are greater than 10MB for each slave (on average). This likely means that there is some slave instance that is struggling receiving data, either because it is too slow or because of networking issues. As a result, data piles on the master output buffers. Please try to identify what slave is not receiving data correctly and why. You can use the INFO output in order to check the slaves delays and the CLIENT LIST command to check the output buffers of each slave.
普通客戶端緩沖區的平均內存超過 200KB,原因可能是 pipeline 使用不當或者 Pub/Sub 客戶端處理消息不及時導致:
Big client buffers: The clients output buffers in this instance are greater than 200K per client (on average). This may result from different causes, like Pub/Sub clients subscribed to channels bot not receiving data fast enough, so that data piles on the Redis instance output buffer, or clients sending commands with large replies or very large sequences of commands in the same pipeline. Please use the CLIENT LIST command in order to investigate the issue if it causes problems in your instance, or to understand better why certain clients are using a big amount of memory.
4. MEMORY MALLOC-STATS
打印內存分配器狀態,只在使用 jemalloc 時有用。
5. MEMORY PURGE
請求分配器釋放內存,同樣只對 jemalloc 生效。
到此,關于“redis4.0 下 MEMORY 命令詳解”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注丸趣 TV 網站,丸趣 TV 小編會繼續努力為大家帶來更多實用的文章!