日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

redis 是一種內存數據庫,將數據保存在內存中,讀寫效率要比傳統的將數據保存在磁盤上的數據庫要快很多。所以,監控 Redis 的內存消耗并了解 Redis 內存模型對高效并長期穩定使用 Redis 至關重要。

一文了解 Redis 內存監控和內存消耗

 

內存使用統計

通過 info memory 命令可以獲得 Redis 內存相關的指標。較為重要的指標和解釋如下所示:

一文了解 Redis 內存監控和內存消耗

 


一文了解 Redis 內存監控和內存消耗

 

當 memfragmentationratio > 1 時,說明有部分內存并沒有用于數據存儲,而是被內存碎片所消耗,如果該值很大,說明碎片率嚴重。

當 memfragmentationratio < 1 時,這種情況一般出現在操作系統把 Redis 內存交換 (swap) 到硬盤導致,出現這種情況要格外關注,由于硬盤速度遠遠慢于內存,Redis 性能會變得很差,甚至僵死。

當 Redis 內存超出可以獲得內存時,操作系統會進行 swap,將舊的頁寫入硬盤。從硬盤讀寫大概比從內存讀寫要慢5個數量級。used_memory 指標可以幫助判斷 Redis 是否有被swap的風險或者它已經被swap。

在 Redis Administration 一文 (鏈接在文末) 建議要設置和內存一樣大小的交換區,如果沒有交換區,一旦 Redis 突然需要的內存大于當前操作系統可用內存時,Redis 會因為 out of memory 而被 Linix Kernel 的 OOM Killer 直接殺死。雖然當 Redis 的數據被換出 (swap out) 時,Redis的性能會變差,但是總比直接被殺死的好。

Redis 使用 maxmemory 參數限制最大可用內存。限制內存的目的主要有:

  • 用于緩存場景,當超出內存上限 maxmemory 時使用 LRU 等刪除策略釋放空間。
  • 防止所用的內存超過服務器物理內存,導致 OOM 后進程被系統殺死。

maxmemory 限制的是 Redis 實際使用的內存量,也就是 used_memory 統計項對應的內存。實際消耗的內存可能會比 maxmemory 設置的大,要小心因為這部內存導致 OOM。所以,如果你有 10GB 的內存,最好將 maxmemory 設置為 8 或者 9G

內存消耗劃分

Redis 進程內消耗主要包括:自身內存 + 對象內存 + 緩沖內存 + 內存碎片,其中 Redis 空進程自身內存消耗非常少,通常 usedmemoryrss 在 3MB 左右時,used_memory 一般在 800KB 左右,一個空的 Redis 進程消耗內存可以忽略不計。

一文了解 Redis 內存監控和內存消耗

 

對象內存

對象內存是 Redis 內存占用最大的一塊,存儲著用戶所有的數據。Redis 所有的數據都采用 key-value 數據類型,每次創建鍵值對時,至少創建兩個類型對象:key 對象和 value 對象。對象內存消耗可以簡單理解為這兩個對象的內存消耗之和(還有類似過期之類的信息)。鍵對象都是字符串,在使用 Redis 時很容易忽略鍵對內存消耗的影響,應當避免使用過長的鍵。有關 Redis 對象系統的詳細內容,請看我之前的文章十二張圖帶你了解 Redis 的數據結構和對象系統。

緩沖內存

緩沖內存主要包括:客戶端緩沖、復制積壓緩沖區和 AOF 緩沖區。

客戶端緩沖指的是所有接入到 Redis 服務器 TCP 連接的輸入輸出緩沖。

一文了解 Redis 內存監控和內存消耗

 

輸入緩沖無法控制,最大空間為 1G,如果超過將斷開連接。而且輸入緩沖區不受 maxmemory 控制,假設一個 Redis 實例設置了 maxmemory 為 4G,已經存儲了 2G 數據,但是如果此時輸入緩沖區使用了 3G,就已經超出了 maxmemory 限制,可能導致數據丟失、鍵值淘汰或者 OOM。

輸入緩沖區過大主要是因為 Redis 的處理速度跟不上輸入緩沖區的輸入速度,并且每次進入輸入緩沖區的命令包含了大量的 bigkey。

輸出緩沖通過參數 client-output-buffer-limit 控制,其格式如下所示。

client-output-buffer-limit [hard limit] [soft limit] [duration]

hard limit 是指一旦緩沖區大小達到了這個閾值,Redis 就會立刻關閉該連接。而 soft limit 和時間 duration 共同生效,比如說 soft time 為 64mb、duration 為 60,則只有當緩沖區持續 60s 大于 64mb 時,Redis 才會關閉該連接。

普通客戶端是除了復制和訂閱的客戶端之外的所有連接。Reids 對其的默認配置是 client-output-buffer-limit normal 0 0 0 , Redis 并沒有對普通客戶端的輸出緩沖區做限制,一般普通客戶端的內存消耗可以忽略不計,但是當有大量慢連接客戶端接入時這部分內存消耗就不能忽略,可以設置 maxclients 做限制。特別當使用大量數據輸出的命令且數據無法及時推送到客戶端時,如 monitor 命令,容易造成 Redis 服務器內存突然飆升。相關案例可以查看這篇文章美團在Redis上踩過的一些坑-3.redis內存占用飆升。

從客戶端用于主從復制,主節點會為每個從節點單獨建立一條連接用于命令復制,默認配置為 client-output-buffer-limit slave 256mb 64mb 60。當主從節點之間網絡延遲較高或主節點掛載大量從節點時這部分內存消耗將占用很大一部分,建議主節點掛載的從節點不要多于 2 個,主從節點不要部署在較差的網絡環境下,如異地跨機房環境,防止復制客戶端連接緩慢造成溢出。與主從復制相關的一共有兩類緩沖區,一個是從客戶端輸出緩沖區,另外一個是下面會介紹到的復制積壓緩沖區。

一文了解 Redis 內存監控和內存消耗

 

訂閱客戶端用于發布訂閱功能,連接客戶端使用單獨的輸出緩沖區,默認配置為 client-output-buffer-limit pubsub 32mb 8mb 60,當訂閱服務的消息生產快于消費速度時,輸出緩沖區會產生積壓造成內存空間溢出。

輸入輸出緩沖區在大流量場景中容易失控,造成 Redis 內存不穩定,需要重點監控。可以定期執行 client list 命令,監控每個客戶端的輸入輸出緩沖區大小和其他信息。

一文了解 Redis 內存監控和內存消耗

 

127.0.0.1:6379> client list
id=3 addr=127.0.0.1:58161 fd=8 name= 
age=1408 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 
qbuf=26 qbuf-free=32742 obl=0 oll=0 omem=0 
events=r cmd=client

client list 命令執行速度慢,客戶端較多時頻繁執行存在阻塞redis的可能,所以一般可以先使用 info clients 命令獲取最大的客戶端緩沖區大小。

127.0.0.1:6379> info clients
# Clients
connected_clients:1
client_recent_max_input_buffer:2
client_recent_max_output_buffer:0
blocked_clients:0

復制積壓緩沖區是Redis 在 2.8 版本后提供的一個可重用的固定大小緩沖區,用于實現部分復制功能。根據 repl-backlog-size 參數控制,默認 1MB。對于復制積壓緩沖區整個主節點只有一個,所有的從節點共享此緩沖區。因此可以設置較大的緩沖區空間,比如說 100MB,可以有效避免全量復制。有關復制積壓緩沖區的詳情可以看我的舊文章 Redis 復制過程詳解。

AOF 重寫緩沖區:這部分空間用于在 Redis AOF 重寫期間保存最近的寫入命令。AOF 重寫緩沖區的大小用戶無法控制,取決于 AOF 重寫時間和寫入命令量,不過一般都很小。有關 AOF 持久化的詳情可以看我的舊文章 Redis AOF 持久化詳解。

Redis 內存碎片

Redis 默認的內存分配器采用 jemalloc,可選的分配器還有:glibc、tcmalloc。內存分配器為了更好地管理和重復利用內存,分配內存策略一般采用固定范圍的內存塊進行分配。具體的分配策略后續會具體講解,但是 Redis 正常碎片率一般在 1.03 左右(為什么是這個值)。但是當存儲的數據長度長度差異較大時,以下場景容易出現高內存碎片問題:

  • 頻繁做更新操作,例如頻繁對已經存在的鍵執行 Append、setrange 等更新操作。
  • 大量過期鍵刪除,鍵對象過期刪除后,釋放的空間無法得到重復利用,導致碎片率上升。

這部分內容我們后續再詳細講解 jemalloc,因為大量的框架都會使用內存分配器,比如說 Netty 等。

子進程內存消耗

子進程內存消耗主要指執行 AOF 重寫 或者進行 RDB 保存時 Redis 創建的子進程內存消耗。Redis 執行 fork 操作產生的子進程內存占用量表現為與父進程相同,理論上需要一倍的物理內存來完成相應的操作。但是 linux 具有寫時復制技術 (copy-on-write),父子進程會共享相同的物理內存頁,當父進程處理寫請求時會對需要修改的頁復制出一份副本完成寫操作,而子進程依然讀取 fork 時整個父進程的內存快照。

一文了解 Redis 內存監控和內存消耗

 

如上圖所示,fork 時只拷貝 page table,也就是頁表。只有等到某一頁發生修改時,才真正進行頁的復制。

但是 Linux Kernel 在 2.6.38 內存增加了 Transparent Huge Pages (THP) 機制,簡單理解,它就是讓頁大小變大,本來一頁為 4KB,開啟 THP 機制后,一頁大小為 2MB。它雖然可以加快 fork 速度( 要拷貝的頁的數量減少 ),但是會導致 copy-on-write 復制內存頁的單位從 4KB 增大為 2MB,如果父進程有大量寫命令,會加重內存拷貝量,都是修改一個頁的內容,但是頁單位變大了,從而造成過度內存消耗。例如,以下兩個執行 AOF 重寫時的內存消耗日志:

// 開啟 THP
C * AOF rewrite: 1039 MB of memory used by copy-on-write
// 關閉 THP
C * AOF rewrite: 9MB of memory used by copy-on-write

這兩個日志出自同一個 Redis 進程,used_memory 總量是 1.5GB,子進程執行期間每秒寫命令量都在 200 左右。當分別開啟和關閉 THP 時,子進程內存消耗有天壤之別。所以,在高并發寫的場景下開啟 THP,子進程內存消耗可能是父進程的數倍,造成機器物理內存溢出。

所以說,Redis 產生的子進程并不需要消耗 1 倍的父進程內存,實際消耗根據期間寫入命令量決定,所以需要預留一些內存防止溢出。并且建議關閉系統的 THP,防止 copy-on-write 期間內存過度消耗。不僅是 Redis,部署 MySQL 的機器一般也會關閉 THP。

 

參考

  • https://www.datadoghq.com/pdf/Understanding-the-Top-5-Redis-Performance-Metrics.pdf
  • Redis Administration https://redis.io/topics/admin

分享到:
標簽:監控 內存 Redis
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定