1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        萬字總結(jié),Redis 性能問題排查解決手冊!

        共 10719字,需瀏覽 22分鐘

         ·

        2021-05-29 04:37

        公眾號關(guān)注杰哥的IT之旅”,

        選擇“星標(biāo)”,重磅干貨,第一時(shí)間送達(dá)!

        性能相關(guān)的數(shù)據(jù)指標(biāo)

        通過Redis-cli命令行界面訪問到Redis服務(wù)器,然后使用info命令獲取所有與Redis服務(wù)相關(guān)的信息。通過這些信息來分析文章后面提到的一些性能指標(biāo)。

        info命令輸出的數(shù)據(jù)可分為10個類別,分別是:

        1、server
        2、clients
        3、memory
        4、persistence
        5、stats
        6、replication
        7、cpu
        8、commandstats
        9、cluster
        10、keyspace

        這篇主要介紹比較重要的2部分性能指標(biāo)memory和stats。

        需要注意的是info命令返回的信息,并沒有命令響應(yīng)延遲相關(guān)的數(shù)據(jù)信息,所以后面會詳細(xì)介紹怎么獲取與延遲相關(guān)的數(shù)據(jù)指標(biāo)。

        倘若你覺得info輸出的信息太多并且雜亂無章,可以指定info命令的參數(shù)來獲取單個分類下的數(shù)據(jù)。比如輸入info memory命令,會只返回與內(nèi)存相關(guān)的數(shù)據(jù)。

        為了快速定位并解決性能問題,這里選擇5個關(guān)鍵性的數(shù)據(jù)指標(biāo),它包含了大多數(shù)人在使用Redis上會經(jīng)常碰到的性能問題。

        內(nèi)存使用率used_memory

        上圖中used_memory 字段數(shù)據(jù)表示的是:由Redis分配器分配的內(nèi)存總量,以字節(jié)(byte)為單位。其中used_memory_human上的數(shù)據(jù)和used_memory是一樣的值,它以M為單位顯示,僅為了方便閱讀。

        used_memory是Redis使用的內(nèi)存總量,它包含了實(shí)際緩存占用的內(nèi)存和Redis自身運(yùn)行所占用的內(nèi)存(如元數(shù)據(jù)、lua)。它是由Redis使用內(nèi)存分配器分配的內(nèi)存,所以這個數(shù)據(jù)并沒有把內(nèi)存碎片浪費(fèi)掉的內(nèi)存給統(tǒng)計(jì)進(jìn)去。

        其他字段代表的含義,都以字節(jié)為單位:

        1、used_memory_rss:從操作系統(tǒng)上顯示已經(jīng)分配的內(nèi)存總量。
        2、mem_fragmentation_ratio:內(nèi)存碎片率。
        3、used_memory_lua:Lua腳本引擎所使用的內(nèi)存大小。

        mem_allocator:在編譯時(shí)指定的Redis使用的內(nèi)存分配器,可以是libc、jemalloc、tcmalloc。

        因內(nèi)存交換引起的性能問題

        內(nèi)存使用率是Redis服務(wù)最關(guān)鍵的一部分。如果一個Redis實(shí)例的內(nèi)存使用率超過可用最大內(nèi)存 (used_memory > 可用最大內(nèi)存),那么操作系統(tǒng)開始進(jìn)行內(nèi)存與swap空間交換,把內(nèi)存中舊的或不再使用的內(nèi)容寫入硬盤上(硬盤上的這塊空間叫Swap分區(qū)),以便騰出新的物理內(nèi)存給新頁或活動頁(page)使用。
        在硬盤上進(jìn)行讀寫操作要比在內(nèi)存上進(jìn)行讀寫操作,時(shí)間上慢了近5個數(shù)量級,內(nèi)存是0.1μs單位、而硬盤是10ms。如果Redis進(jìn)程上發(fā)生內(nèi)存交換,那么Redis和依賴Redis上數(shù)據(jù)的應(yīng)用會受到嚴(yán)重的性能影響。通過查看used_memory指標(biāo)可知道Redis正在使用的內(nèi)存情況,如果used_memory>可用最大內(nèi)存,那就說明Redis實(shí)例正在進(jìn)行內(nèi)存交換或者已經(jīng)內(nèi)存交換完畢。管理員根據(jù)這個情況,執(zhí)行相對應(yīng)的應(yīng)急措施。

        跟蹤內(nèi)存使用率

        若是在使用Redis期間沒有開啟rdb快照或aof持久化策略,那么緩存數(shù)據(jù)在Redis崩潰時(shí)就有丟失的危險(xiǎn)。因?yàn)楫?dāng)Redis內(nèi)存使用率超過可用內(nèi)存的95%時(shí),部分?jǐn)?shù)據(jù)開始在內(nèi)存與swap空間來回交換,這時(shí)就可能有丟失數(shù)據(jù)的危險(xiǎn)。

        當(dāng)開啟并觸發(fā)快照功能時(shí),Redis會fork一個子進(jìn)程把當(dāng)前內(nèi)存中的數(shù)據(jù)完全復(fù)制一份寫入到硬盤上。因此若是當(dāng)前使用內(nèi)存超過可用內(nèi)存的45%時(shí)觸發(fā)快照功能,那么此時(shí)進(jìn)行的內(nèi)存交換會變的非常危險(xiǎn)(可能會丟失數(shù)據(jù))。倘若在這個時(shí)候?qū)嵗嫌写罅款l繁的更新操作,問題會變得更加嚴(yán)重。

        通過減少Redis的內(nèi)存占用率,來避免這樣的問題,或者使用下面的技巧來避免內(nèi)存交換發(fā)生:

        1、假如緩存數(shù)據(jù)小于4GB,就使用32位的Redis實(shí)例。因?yàn)?2位實(shí)例上的指針大小只有64位的一半,它的內(nèi)存空間占用空間會更少些。這有一個壞處就是,假設(shè)物理內(nèi)存超過4GB,那么32位實(shí)例能使用的內(nèi)存仍然會被限制在4GB以下。要是實(shí)例同時(shí)也共享給其他一些應(yīng)用使用的話,那可能需要更高效的64位Redis實(shí)例,這種情況下切換到32位是不可取的。不管使用哪種方式,Redis的dump文件在32位和64位之間是互相兼容的, 因此倘若有減少占用內(nèi)存空間的需求,可以嘗試先使用32位,后面再切換到64位上。

        2、盡可能的使用Hash數(shù)據(jù)結(jié)構(gòu)。因?yàn)镽edis在儲存小于100個字段的Hash結(jié)構(gòu)上,其存儲效率是非常高的。所以在不需要集合(set)操作或list的push/pop操作的時(shí)候,盡可能的使用Hash結(jié)構(gòu)。比如,在一個web應(yīng)用程序中,需要存儲一個對象表示用戶信息,使用單個key表示一個用戶,其每個屬性存儲在Hash的字段里,這樣要比給每個屬性單獨(dú)設(shè)置一個key-value要高效的多。通常情況下倘若有數(shù)據(jù)使用string結(jié)構(gòu),用多個key存儲時(shí),那么應(yīng)該轉(zhuǎn)換成單key多字段的Hash結(jié)構(gòu)。如上述例子中介紹的Hash結(jié)構(gòu)應(yīng)包含,單個對象的屬性或者單個用戶各種各樣的資料。Hash結(jié)構(gòu)的操作命令是HSET(key, fields, value)和HGET(key, field),使用它可以存儲或從Hash中取出指定的字段。

        3、設(shè)置key的過期時(shí)間。一個減少內(nèi)存使用率的簡單方法就是,每當(dāng)存儲對象時(shí)確保設(shè)置key的過期時(shí)間。倘若key在明確的時(shí)間周期內(nèi)使用或者舊key不大可能被使用時(shí),就可以用Redis過期時(shí)間命令(expire,expireat, pexpire, pexpireat)去設(shè)置過期時(shí)間,這樣Redis會在key過期時(shí)自動刪除key。假如你知道每秒鐘有多少個新key-value被創(chuàng)建,那可以調(diào)整key的存活時(shí)間,并指定閥值去限制Redis使用的最大內(nèi)存。

        4、回收key。在Redis配置文件中(一般叫Redis.conf),通過設(shè)置“maxmemory”屬性的值可以限制Redis最大使用的內(nèi)存,修改后重啟實(shí)例生效。也可以使用客戶端命令config set maxmemory 去修改值,這個命令是立即生效的,但會在重啟后會失效,需要使用config rewrite命令去刷新配置文件。若是啟用了Redis快照功能,應(yīng)該設(shè)置“maxmemory”值為系統(tǒng)可使用內(nèi)存的45%,因?yàn)榭煺諘r(shí)需要一倍的內(nèi)存來復(fù)制整個數(shù)據(jù)集,也就是說如果當(dāng)前已使用45%,在快照期間會變成95%(45%+45%+5%),其中5%是預(yù)留給其他的開銷。如果沒開啟快照功能,maxmemory最高能設(shè)置為系統(tǒng)可用內(nèi)存的95%。

        當(dāng)內(nèi)存使用達(dá)到設(shè)置的最大閥值時(shí),需要選擇一種key的回收策略,可在Redis.conf配置文件中修改“maxmemory-policy”屬性值。若是Redis數(shù)據(jù)集中的key都設(shè)置了過期時(shí)間,那么“volatile-ttl”策略是比較好的選擇。但如果key在達(dá)到最大內(nèi)存限制時(shí)沒能夠迅速過期,或者根本沒有設(shè)置過期時(shí)間。那么設(shè)置為“allkeys-lru”值比較合適,它允許Redis從整個數(shù)據(jù)集中挑選最近最少使用的key進(jìn)行刪除(LRU淘汰算法)。Redis還提供了一些其他淘汰策略,如下:

        1、volatile-lru:使用LRU算法從已設(shè)置過期時(shí)間的數(shù)據(jù)集合中淘汰數(shù)據(jù)。
        2、volatile-ttl:從已設(shè)置過期時(shí)間的數(shù)據(jù)集合中挑選即將過期的數(shù)據(jù)淘汰。
        3、volatile-random:從已設(shè)置過期時(shí)間的數(shù)據(jù)集合中隨機(jī)挑選數(shù)據(jù)淘汰。
        4、allkeys-lru:使用LRU算法從所有數(shù)據(jù)集合中淘汰數(shù)據(jù)。
        5、allkeys-random:從數(shù)據(jù)集合中任意選擇數(shù)據(jù)淘汰
        6、no-enviction:禁止淘汰數(shù)據(jù)。

        通過設(shè)置maxmemory為系統(tǒng)可用內(nèi)存的45%或95%(取決于持久化策略)和設(shè)置“maxmemory-policy”為“volatile-ttl”或“allkeys-lru”(取決于過期設(shè)置),可以比較準(zhǔn)確的限制Redis最大內(nèi)存使用率,在絕大多數(shù)場景下使用這2種方式可確保Redis不會進(jìn)行內(nèi)存交換。倘若你擔(dān)心由于限制了內(nèi)存使用率導(dǎo)致丟失數(shù)據(jù)的話,可以設(shè)置noneviction值禁止淘汰數(shù)據(jù)。

        命令處理數(shù)total_commands_processed

        在info信息里的total_commands_processed字段顯示了Redis服務(wù)處理命令的總數(shù),其命令都是從一個或多個Redis客戶端請求過來的。Redis每時(shí)每刻都在處理從客戶端請求過來的命令,它可以是Redis提供的140種命令的任意一個。total_commands_processed字段的值是遞增的,比如Redis服務(wù)分別處理了client_x請求過來的2個命令和client_y請求過來的3個命令,那么命令處理總數(shù)(total_commands_processed)就會加上5。

        分析命令處理總數(shù),診斷響應(yīng)延遲。

        在Redis實(shí)例中,跟蹤命令處理總數(shù)是解決響應(yīng)延遲問題最關(guān)鍵的部分,因?yàn)镽edis是個單線程模型,客戶端過來的命令是按照順序執(zhí)行的。比較常見的延遲是帶寬,通過千兆網(wǎng)卡的延遲大約有200μs。倘若明顯看到命令的響應(yīng)時(shí)間變慢,延遲高于200μs,那可能是Redis命令隊(duì)列里等待處理的命令數(shù)量比較多。如上所述,延遲時(shí)間增加導(dǎo)致響應(yīng)時(shí)間變慢可能是由于一個或多個慢命令引起的,這時(shí)可以看到每秒命令處理數(shù)在明顯下降,甚至于后面的命令完全被阻塞,導(dǎo)致Redis性能降低。要分析解決這個性能問題,需要跟蹤命令處理數(shù)的數(shù)量和延遲時(shí)間。

        比如可以寫個腳本,定期記錄total_commands_processed的值。當(dāng)客戶端明顯發(fā)現(xiàn)響應(yīng)時(shí)間過慢時(shí),可以通過記錄的total_commands_processed歷史數(shù)據(jù)值來判斷命理處理總數(shù)是上升趨勢還是下降趨勢,以便排查問題。

        使用命令處理總數(shù)解決延遲時(shí)間增加。

        通過與記錄的歷史數(shù)據(jù)比較得知,命令處理總數(shù)確實(shí)是處于上升或下降狀態(tài),那么可能是有2個原因引起的:

        1、命令隊(duì)列里的命令數(shù)量過多,后面命令一直在等待中。
        2、幾個慢命令阻塞Redis。

        下面有三個辦法可以解決,因上面2條原因引起的響應(yīng)延遲問題。

        1、使用多參數(shù)命令:若是客戶端在很短的時(shí)間內(nèi)發(fā)送大量的命令過來,會發(fā)現(xiàn)響應(yīng)時(shí)間明顯變慢,這由于后面命令一直在等待隊(duì)列中前面大量命令執(zhí)行完畢。有個方法可以改善延遲問題,就是通過單命令多參數(shù)的形式取代多命令單參數(shù)的形式。舉例來說,循環(huán)使用LSET命令去添加1000個元素到list結(jié)構(gòu)中,是性能比較差的一種方式,更好的做法是在客戶端創(chuàng)建一個1000元素的列表,用單個命令LPUSH或RPUSH,通過多參數(shù)構(gòu)造形式一次性把1000個元素發(fā)送的Redis服務(wù)上。下面的表格是Redis的一些操作命令,有單個參數(shù)命令和支持多個參數(shù)的命令,通過這些命令可盡量減少使用多命令的次數(shù)。 

        2、管道命令:另一個減少多命令的方法是使用管道(pipeline),把幾個命令合并一起執(zhí)行,從而減少因網(wǎng)絡(luò)開銷引起的延遲問題。因?yàn)?0個命令單獨(dú)發(fā)送到服務(wù)端會引起10次網(wǎng)絡(luò)延遲開銷,使用管道會一次性把執(zhí)行結(jié)果返回,僅需要一次網(wǎng)絡(luò)延遲開銷。Redis本身支持管道命令,大多數(shù)客戶端也支持,倘若當(dāng)前實(shí)例延遲很明顯,那么使用管道去降低延遲是非常有效的。

        3、避免操作大集合的慢命令:如果命令處理頻率過低導(dǎo)致延遲時(shí)間增加,這可能是因?yàn)槭褂昧烁邥r(shí)間復(fù)雜度的命令操作導(dǎo)致,這意味著每個命令從集合中獲取數(shù)據(jù)的時(shí)間增大。所以減少使用高時(shí)間復(fù)雜的命令,能顯著的提高的Redis的性能。下面的表格是高時(shí)間復(fù)雜度命令的列表,其詳細(xì)描述了命令的屬性,有這助于高效合理的、最優(yōu)化的使用這些命令(如果不得不使用的話),以提高Redis性能。

        延遲時(shí)間

        Redis的延遲數(shù)據(jù)是無法從info信息中獲取的。倘若想要查看延遲時(shí)間,可以用 Redis-cli工具加--latency參數(shù)運(yùn)行,如:

        Redis-cli --latency -h 127.0.0.1 -p 6379

        其host和port是Redis實(shí)例的ip及端口。由于當(dāng)前服務(wù)器不同的運(yùn)行情況,延遲時(shí)間可能有所誤差,通常1G網(wǎng)卡的延遲時(shí)間是200μs。

        以毫秒為單位測量Redis的響應(yīng)延遲時(shí)間,樓主本機(jī)的延遲是300μs:

        跟蹤Redis延遲性能

        Redis之所以這么流行的主要原因之一就是低延遲特性帶來的高性能,所以說解決延遲問題是提高Redis性能最直接的辦法。拿1G帶寬來說,若是延遲時(shí)間遠(yuǎn)高于200μs,那明顯是出現(xiàn)了性能問題。雖然在服務(wù)器上會有一些慢的IO操作,但Redis是單核接受所有客戶端的請求,所有請求是按良好的順序排隊(duì)執(zhí)行。因此若是一個客戶端發(fā)過來的命令是個慢操作,那么其他所有請求必須等待它完成后才能繼續(xù)執(zhí)行。

        使用延遲命令提高性能

        一旦確定延遲時(shí)間是個性能問題后,這里有幾個辦法可以用來分析解決性能問題。

        1. 使用slowlog查出引發(fā)延遲的慢命令:Redis中的slowlog命令可以讓我們快速定位到那些超出指定執(zhí)行時(shí)間的慢命令,默認(rèn)情況下命令若是執(zhí)行時(shí)間超過10ms就會被記錄到日志。slowlog只會記錄其命令執(zhí)行的時(shí)間,不包含io往返操作,也不記錄單由網(wǎng)絡(luò)延遲引起的響應(yīng)慢。通常1gb帶寬的網(wǎng)絡(luò)延遲,預(yù)期在200μs左右,倘若一個命令僅執(zhí)行時(shí)間就超過10ms,那比網(wǎng)絡(luò)延遲慢了近50倍。想要查看所有執(zhí)行時(shí)間比較慢的命令,可以通過使用Redis-cli工具,輸入slowlog get命令查看,返回結(jié)果的第三個字段以微妙位單位顯示命令的執(zhí)行時(shí)間。假如只需要查看最后10個慢命令,輸入slowlog get 10即可。關(guān)于怎么定位到是由慢命令引起的延遲問題,可查看total_commands_processed介紹章節(jié)。

        圖中字段分別意思是:

        1、1=日志的唯一標(biāo)識符
        2、2=被記錄命令的執(zhí)行時(shí)間點(diǎn),以 UNIX 時(shí)間戳格式表示
        3、3=查詢執(zhí)行時(shí)間,以微秒為單位。例子中命令使用54毫秒。
        4、4=執(zhí)行的命令,以數(shù)組的形式排列。完整命令是config get *。

        倘若你想自定義慢命令的標(biāo)準(zhǔn),可以調(diào)整觸發(fā)日志記錄慢命令的閥值。若是很少或沒有命令超過10ms,想降低記錄的閥值,比如5毫秒,可在Redis-cli工具中輸入下面的命令配置:

        config set slowlog-log-slower-than 5000

        也可以在Redis.config配置文件中設(shè)置,以微妙位單位。

        2.監(jiān)控客戶端的連接:因?yàn)镽edis是單線程模型(只能使用單核),來處理所有客戶端的請求, 但由于客戶端連接數(shù)的增長,處理請求的線程資源開始降低分配給單個客戶端連接的處理時(shí)間,這時(shí)每個客戶端需要花費(fèi)更多的時(shí)間去等待Redis共享服務(wù)的響應(yīng)。這種情況下監(jiān)控客戶端連接數(shù)是非常重要的,因?yàn)榭蛻舳藙?chuàng)建連接數(shù)的數(shù)量可能超出預(yù)期的數(shù)量,也可能是客戶端端沒有有效的釋放連接。在Redis-cli工具中輸入info clients可以查看到當(dāng)前實(shí)例的所有客戶端連接信息。如下圖,第一個字段(connected_clients)顯示當(dāng)前實(shí)例客戶端連接的總數(shù):

        Redis默認(rèn)允許客戶端連接的最大數(shù)量是10000。若是看到連接數(shù)超過5000以上,那可能會影響Redis的性能。倘若一些或大部分客戶端發(fā)送大量的命令過來,這個數(shù)字會低的多。

        3.限制客戶端連接數(shù):自Redis2.6以后,允許使用者在配置文件(Redis.conf)maxclients屬性上修改客戶端連接的最大數(shù),也可以通過在Redis-cli工具上輸入config set maxclients 去設(shè)置最大連接數(shù)。根據(jù)連接數(shù)負(fù)載的情況,這個數(shù)字應(yīng)該設(shè)置為預(yù)期連接數(shù)峰值的110%到150之間,若是連接數(shù)超出這個數(shù)字后,Redis會拒絕并立刻關(guān)閉新來的連接。通過設(shè)置最大連接數(shù)來限制非預(yù)期數(shù)量的連接數(shù)增長,是非常重要的。另外,新連接嘗試失敗會返回一個錯誤消息,這可以讓客戶端知道,Redis此時(shí)有非預(yù)期數(shù)量的連接數(shù),以便執(zhí)行對應(yīng)的處理措施。上述二種做法對控制連接數(shù)的數(shù)量和持續(xù)保持Redis的性能最優(yōu)是非常重要的,

        4.加強(qiáng)內(nèi)存管理:較少的內(nèi)存會引起Redis延遲時(shí)間增加。如果Redis占用內(nèi)存超出系統(tǒng)可用內(nèi)存,操作系統(tǒng)會把Redis進(jìn)程的一部分?jǐn)?shù)據(jù),從物理內(nèi)存交換到硬盤上,內(nèi)存交換會明顯的增加延遲時(shí)間。關(guān)于怎么監(jiān)控和減少內(nèi)存使用,可查看used_memory介紹章節(jié)。

        5. 性能數(shù)據(jù)指標(biāo):分析解決Redis性能問題,通常需要把延遲時(shí)間的數(shù)據(jù)變化與其他性能指標(biāo)的變化相關(guān)聯(lián)起來。命令處理總數(shù)下降的發(fā)生可能是由慢命令阻塞了整個系統(tǒng),但如果命令處理總數(shù)的增加,同時(shí)內(nèi)存使用率也增加,那么就可能是由于內(nèi)存交換引起的性能問題。對于這種性能指標(biāo)相關(guān)聯(lián)的分析,需要從歷史數(shù)據(jù)上來觀察到數(shù)據(jù)指標(biāo)的重要變化,此外還可以觀察到單個性能指標(biāo)相關(guān)聯(lián)的所有其他性能指標(biāo)信息。這些數(shù)據(jù)可以在Redis上收集,周期性的調(diào)用內(nèi)容為Redis info的腳本,然后分析輸出的信息,記錄到日志文件中。當(dāng)延遲發(fā)生變化時(shí),用日志文件配合其他數(shù)據(jù)指標(biāo),把數(shù)據(jù)串聯(lián)起來排查定位問題。

        內(nèi)存碎片率

        info信息中的mem_fragmentation_ratio給出了內(nèi)存碎片率的數(shù)據(jù)指標(biāo),它是由操系統(tǒng)分配的內(nèi)存除以Redis分配的內(nèi)存得出:

        used_memory和used_memory_rss數(shù)字都包含的內(nèi)存分配有:

        1、用戶定義的數(shù)據(jù):內(nèi)存被用來存儲key-value值。
        2、內(nèi)部開銷:存儲內(nèi)部Redis信息用來表示不同的數(shù)據(jù)類型。

        used_memory_rss的rss是Resident Set Size的縮寫,表示該進(jìn)程所占物理內(nèi)存的大小,是操作系統(tǒng)分配給Redis實(shí)例的內(nèi)存大小。除了用戶定義的數(shù)據(jù)和內(nèi)部開銷以外,used_memory_rss指標(biāo)還包含了內(nèi)存碎片的開銷,內(nèi)存碎片是由操作系統(tǒng)低效的分配/回收物理內(nèi)存導(dǎo)致的。

        操作系統(tǒng)負(fù)責(zé)分配物理內(nèi)存給各個應(yīng)用進(jìn)程,Redis使用的內(nèi)存與物理內(nèi)存的映射是由操作系統(tǒng)上虛擬內(nèi)存管理分配器完成的。

        舉個例子來說,Redis需要分配連續(xù)內(nèi)存塊來存儲1G的數(shù)據(jù)集,這樣的話更有利,但可能物理內(nèi)存上沒有超過1G的連續(xù)內(nèi)存塊,那操作系統(tǒng)就不得不使用多個不連續(xù)的小內(nèi)存塊來分配并存儲這1G數(shù)據(jù),也就導(dǎo)致內(nèi)存碎片的產(chǎn)生。
        內(nèi)存分配器另一個復(fù)雜的層面是,它經(jīng)常會預(yù)先分配一些內(nèi)存塊給引用,這樣做會使加快應(yīng)用程序的運(yùn)行。

        理解資源性能

        跟蹤內(nèi)存碎片率對理解Redis實(shí)例的資源性能是非常重要的。內(nèi)存碎片率稍大于1是合理的,這個值表示內(nèi)存碎片率比較低,也說明redis沒有發(fā)生內(nèi)存交換。但如果內(nèi)存碎片率超過1.5,那就說明Redis消耗了實(shí)際需要物理內(nèi)存的150%,其中50%是內(nèi)存碎片率。若是內(nèi)存碎片率低于1的話,說明Redis內(nèi)存分配超出了物理內(nèi)存,操作系統(tǒng)正在進(jìn)行內(nèi)存交換。內(nèi)存交換會引起非常明顯的響應(yīng)延遲,可查看used_memory介紹章節(jié)。

        上圖中的0.99即99%。

        用內(nèi)存碎片率預(yù)測性能問題

        倘若內(nèi)存碎片率超過了1.5,那可能是操作系統(tǒng)或Redis實(shí)例中內(nèi)存管理變差的表現(xiàn)。下面有3種方法解決內(nèi)存管理變差的問題,并提高Redis性能:

        1. 重啟Redis服務(wù)器:如果內(nèi)存碎片率超過1.5,重啟Redis服務(wù)器可以讓額外產(chǎn)生的內(nèi)存碎片失效并重新作為新內(nèi)存來使用,使操作系統(tǒng)恢復(fù)高效的內(nèi)存管理。額外碎片的產(chǎn)生是由于Redis釋放了內(nèi)存塊,但內(nèi)存分配器并沒有返回內(nèi)存給操作系統(tǒng),這個內(nèi)存分配器是在編譯時(shí)指定的,可以是libc、jemalloc或者tcmalloc。通過比較used_memory_peak, used_memory_rss和used_memory_metrics的數(shù)據(jù)指標(biāo)值可以檢查額外內(nèi)存碎片的占用。從名字上可以看出,used_memory_peak是過去Redis內(nèi)存使用的峰值,而不是當(dāng)前使用內(nèi)存的值。如果used_memory_peak和used_memory_rss的值大致上相等,而且二者明顯超過了used_memory值,這說明額外的內(nèi)存碎片正在產(chǎn)生。在Redis-cli工具上輸入info memory可以查看上面三個指標(biāo)的信息:

        在重啟服務(wù)器之前,需要在Redis-cli工具上輸入shutdown save命令,意思是強(qiáng)制讓Redis數(shù)據(jù)庫執(zhí)行保存操作并關(guān)閉Redis服務(wù),這樣做能保證在執(zhí)行Redis關(guān)閉時(shí)不丟失任何數(shù)據(jù)。在重啟后,Redis會從硬盤上加載持久化的文件,以確保數(shù)據(jù)集持續(xù)可用。

        2.限制內(nèi)存交換:如果內(nèi)存碎片率低于1,Redis實(shí)例可能會把部分?jǐn)?shù)據(jù)交換到硬盤上。內(nèi)存交換會嚴(yán)重影響Redis的性能,所以應(yīng)該增加可用物理內(nèi)存或減少實(shí)Redis內(nèi)存占用??刹榭磚sed_memory章節(jié)的優(yōu)化建議。

        3.修改內(nèi)存分配器:Redis支持glibc’s malloc、jemalloc11、tcmalloc幾種不同的內(nèi)存分配器,每個分配器在內(nèi)存分配和碎片上都有不同的實(shí)現(xiàn)。不建議普通管理員修改Redis默認(rèn)內(nèi)存分配器,因?yàn)檫@需要完全理解這幾種內(nèi)存分配器的差異,也要重新編譯Redis。這個方法更多的是讓其了解Redis內(nèi)存分配器所做的工作,當(dāng)然也是改善內(nèi)存碎片問題的一種辦法。

        回收key

        info信息中的evicted_keys字段顯示的是,因?yàn)閙axmemory限制導(dǎo)致key被回收刪除的數(shù)量。關(guān)于maxmemory的介紹見前面章節(jié),回收key的情況只會發(fā)生在設(shè)置maxmemory值后,不設(shè)置會發(fā)生內(nèi)存交換。當(dāng)Redis由于內(nèi)存壓力需要回收一個key時(shí),Redis首先考慮的不是回收最舊的數(shù)據(jù),而是在最近最少使用的key或即將過期的key中隨機(jī)選擇一個key,從數(shù)據(jù)集中刪除。

        這可以在配置文件中設(shè)置maxmemory-policy值為“volatile-lru”或“volatile-ttl”,來確定Redis是使用lru策略還是過期時(shí)間策略。倘若所有的key都有明確的過期時(shí)間,那過期時(shí)間回收策略是比較合適的。若是沒有設(shè)置key的過期時(shí)間或者說沒有足夠的過期key,那設(shè)置lru策略是比較合理的,這可以回收key而不用考慮其過期狀態(tài)。

        根據(jù)key回收定位性能問題

        跟蹤key回收是非常重要的,因?yàn)橥ㄟ^回收key,可以保證合理分配Redis有限的內(nèi)存資源。如果evicted_keys值經(jīng)常超過0,那應(yīng)該會看到客戶端命令響應(yīng)延遲時(shí)間增加,因?yàn)镽edis不但要處理客戶端過來的命令請求,還要頻繁的回收滿足條件的key。

        需要注意的是,回收key對性能的影響遠(yuǎn)沒有內(nèi)存交換嚴(yán)重,若是在強(qiáng)制內(nèi)存交換和設(shè)置回收策略做一個選擇的話,選擇設(shè)置回收策略是比較合理的,因?yàn)榘褍?nèi)存數(shù)據(jù)交換到硬盤上對性能影響非常大。

        減少回收key以提升性能

        減少回收key的數(shù)量是提升Redis性能的直接辦法,下面有2種方法可以減少回收key的數(shù)量:

        1.增加內(nèi)存限制:倘若開啟快照功能,maxmemory需要設(shè)置成物理內(nèi)存的45%,這幾乎不會有引發(fā)內(nèi)存交換的危險(xiǎn)。若是沒有開啟快照功能,設(shè)置系統(tǒng)可用內(nèi)存的95%是比較合理的,具體參考前面的快照和maxmemory限制章節(jié)。如果maxmemory的設(shè)置是低于45%或95%(視持久化策略),通過增加maxmemory的值能讓Redis在內(nèi)存中存儲更多的key,這能顯著減少回收key的數(shù)量。若是maxmemory已經(jīng)設(shè)置為推薦的閥值后,增加maxmemory限制不但無法提升性能,反而會引發(fā)內(nèi)存交換,導(dǎo)致延遲增加、性能降低。maxmemory的值可以在Redis-cli工具上輸入config set maxmemory命令來設(shè)置。

        需要注意的是,這個設(shè)置是立即生效的,但重啟后丟失,需要永久化保存的話,再輸入config rewrite命令會把內(nèi)存中的新配置刷新到配置文件中。

        2.對實(shí)例進(jìn)行分片:分片是把數(shù)據(jù)分割成合適大小,分別存放在不同的Redis實(shí)例上,每一個實(shí)例都包含整個數(shù)據(jù)集的一部分。通過分片可以把很多服務(wù)器聯(lián)合起來存儲數(shù)據(jù),相當(dāng)于增加總的物理內(nèi)存,使其在沒有內(nèi)存交換和回收key的策略下也能存儲更多的key。假如有一個非常大的數(shù)據(jù)集,maxmemory已經(jīng)設(shè)置,實(shí)際內(nèi)存使用也已經(jīng)超過了推薦設(shè)置的閥值,那通過數(shù)據(jù)分片能明顯減少key的回收,從而提高Redis的性能。分片的實(shí)現(xiàn)有很多種方法,下面是Redis實(shí)現(xiàn)分片的幾種常見方式:

        a. Hash分片:一個比較簡單的方法實(shí)現(xiàn),通過Hash函數(shù)計(jì)算出key的Hash值,然后值所在范圍對應(yīng)特定的Redis實(shí)例。
        b. 代理分片:客戶端把請求發(fā)送到代理上,代理通過分片配置表選擇對應(yīng)的Redis實(shí)例。如Twitter的Twemproxy,豌豆莢的codis。
        c. 一致性Hash分片
        d. 虛擬桶分片

        總結(jié)

        對于開發(fā)者來說,Redis是個速度非??斓膋ey-value內(nèi)存數(shù)據(jù)庫,并提供了方便的API接口。為了最好最優(yōu)的使用Redis,需要理解哪些因素能影響到Redis性能,哪些數(shù)據(jù)指標(biāo)能幫助我們避免性能陷阱。通過本篇,能理解Redis中的重要性能指標(biāo),怎么查看,更重要的是怎么利用這些數(shù)據(jù)排查解決Redis性能問題。

        本篇文章還翻譯了一電子書的中間15頁,電子書可以在公眾號后臺回復(fù):Redis性能 獲取。

        來源:https://www.cnblogs.com/mushroom/p/4738170.html

        推薦閱讀

        Redis是什么?看這一篇就夠了!

        推薦幾款 Redis 可視化工具

        學(xué) Redis,至少要看看這篇!7000 字小結(jié)

        史上最全 Redis 總結(jié),你想知道的都在這里啦!

        Redis 使用的 10 個小技巧!

        Redis 性能監(jiān)控指標(biāo)匯總

        大廠面試!我和面試官之間關(guān)于Redis的一場對弈!

        瀏覽 30
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評論
        圖片
        表情
        推薦
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            国产午夜在线一区二区三区 | 亚洲三级久久 | 女人脱衣服网站 | 色婷婷精品久久二区二区我来 | 九色国产在线 | 香蕉在线播放 | 黑料不打烊tttzzz入口 | 美女被c免费网站 | 九九视频热播 | 亚洲婷婷无码 |