乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      一文了解 Redis 內(nèi)存監(jiān)控和內(nèi)存消耗

       西北望msm66g9f 2019-10-20

      源 / 程序員歷小兵

      Redis 是一種內(nèi)存數(shù)據(jù)庫,將數(shù)據(jù)保存在內(nèi)存中,讀寫效率要比傳統(tǒng)的將數(shù)據(jù)保存在磁盤上的數(shù)據(jù)庫要快很多。所以,監(jiān)控 Redis 的內(nèi)存消耗并了解 Redis 內(nèi)存模型對高效并長期穩(wěn)定使用 Redis 至關(guān)重要。

      內(nèi)存使用統(tǒng)計

      通過 info memory 命令可以獲得 Redis 內(nèi)存相關(guān)的指標(biāo)。較為重要的指標(biāo)和解釋如下所示:


      當(dāng) memfragmentationratio > 1 時,說明有部分內(nèi)存并沒有用于數(shù)據(jù)存儲,而是被內(nèi)存碎片所消耗,如果該值很大,說明碎片率嚴(yán)重。當(dāng) memfragmentationratio < 1 時,這種情況一般出現(xiàn)在操作系統(tǒng)把 Redis 內(nèi)存交換 (swap) 到硬盤導(dǎo)致,出現(xiàn)這種情況要格外關(guān)注,由于硬盤速度遠遠慢于內(nèi)存,Redis 性能會變得很差,甚至僵死。

      當(dāng) Redis 內(nèi)存超出可以獲得內(nèi)存時,操作系統(tǒng)會進行 swap,將舊的頁寫入硬盤。從硬盤讀寫大概比從內(nèi)存讀寫要慢5個數(shù)量級。used_memory 指標(biāo)可以幫助判斷 Redis 是否有被swap的風(fēng)險或者它已經(jīng)被swap。

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

      Redis 使用 maxmemory 參數(shù)限制最大可用內(nèi)存。限制內(nèi)存的目的主要有:

      • 用于緩存場景,當(dāng)超出內(nèi)存上限 maxmemory 時使用 LRU 等刪除策略釋放空間。

      • 防止所用的內(nèi)存超過服務(wù)器物理內(nèi)存,導(dǎo)致 OOM 后進程被系統(tǒng)殺死。

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

      內(nèi)存消耗劃分

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

      對象內(nèi)存

      對象內(nèi)存是 Redis 內(nèi)存占用最大的一塊,存儲著用戶所有的數(shù)據(jù)。Redis 所有的數(shù)據(jù)都采用 key-value 數(shù)據(jù)類型,每次創(chuàng)建鍵值對時,至少創(chuàng)建兩個類型對象:key 對象和 value 對象。對象內(nèi)存消耗可以簡單理解為這兩個對象的內(nèi)存消耗之和(還有類似過期之類的信息)。鍵對象都是字符串,在使用 Redis 時很容易忽略鍵對內(nèi)存消耗的影響,應(yīng)當(dāng)避免使用過長的鍵。

      緩沖內(nèi)存

      緩沖內(nèi)存主要包括:客戶端緩沖、復(fù)制積壓緩沖區(qū)和 AOF 緩沖區(qū)。

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

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

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

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

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

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

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

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

      訂閱客戶端用于發(fā)布訂閱功能,連接客戶端使用單獨的輸出緩沖區(qū),默認(rèn)配置為 client-output-buffer-limit pubsub 32mb 8mb 60,當(dāng)訂閱服務(wù)的消息生產(chǎn)快于消費速度時,輸出緩沖區(qū)會產(chǎn)生積壓造成內(nèi)存空間溢出。

      輸入輸出緩沖區(qū)在大流量場景中容易失控,造成 Redis 內(nèi)存不穩(wěn)定,需要重點監(jiān)控??梢远ㄆ趫?zhí)行 client list 命令,監(jiān)控每個客戶端的輸入輸出緩沖區(qū)大小和其他信息。

      1. 127.0.0.1:6379> client list

      2. id=3 addr=127.0.0.1:58161 fd=8 name= \

      3. age=1408 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 \

      4. qbuf=26 qbuf-free=32742 obl=0 oll=0 omem=0 \

      5. events=r cmd=client

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

      1. 127.0.0.1:6379> info clients

      2. # Clients

      3. connected_clients:1

      4. client_recent_max_input_buffer:2

      5. client_recent_max_output_buffer:0

      6. blocked_clients:0

      復(fù)制積壓緩沖區(qū)是Redis 在 2.8 版本后提供的一個可重用的固定大小緩沖區(qū),用于實現(xiàn)部分復(fù)制功能。根據(jù) repl-backlog-size 參數(shù)控制,默認(rèn) 1MB。對于復(fù)制積壓緩沖區(qū)整個主節(jié)點只有一個,所有的從節(jié)點共享此緩沖區(qū)。因此可以設(shè)置較大的緩沖區(qū)空間,比如說 100MB,可以有效避免全量復(fù)制。

      AOF 重寫緩沖區(qū):這部分空間用于在 Redis AOF 重寫期間保存最近的寫入命令。AOF 重寫緩沖區(qū)的大小用戶無法控制,取決于 AOF 重寫時間和寫入命令量,不過一般都很小。

      Redis 內(nèi)存碎片

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

      • 頻繁做更新操作,例如頻繁對已經(jīng)存在的鍵執(zhí)行 append、setrange 等更新操作。

      • 大量過期鍵刪除,鍵對象過期刪除后,釋放的空間無法得到重復(fù)利用,導(dǎo)致碎片率上升。

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

      子進程內(nèi)存消耗

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

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

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

      1. // 開啟 THP

      2. C * AOF rewrite: 1039 MB of memory used by copy-on-write

      3. // 關(guān)閉 THP

      4. C * AOF rewrite: 9MB of memory used by copy-on-write

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

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

        本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
        轉(zhuǎn)藏 分享 獻花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多