性能分析及優(yōu)化
內(nèi)存診斷
內(nèi)存使用率是Redis服務(wù)最關(guān)鍵的一部分前鹅。
如果Redis實(shí)例的內(nèi)存使用率超過(guò)最大可用內(nèi)存霍衫,即“used_memory”>最大可用內(nèi)存,那么操作系統(tǒng)會(huì)將內(nèi)存與Swap空間交換,把內(nèi)存中舊的或不再使用的內(nèi)容寫入硬盤上的Swap分區(qū)忧陪,以便留出新的物理內(nèi)存給新頁(yè)或活動(dòng)頁(yè)(page)使用虐先。
通過(guò)查看“used_memory”指標(biāo)可知道Redis的內(nèi)存情況秉扑,當(dāng)“used_memory”>最大可用內(nèi)存時(shí)吸占,Redis實(shí)例正在進(jìn)行內(nèi)存交換或者已經(jīng)內(nèi)存交換完畢。如果Redis進(jìn)程上發(fā)生內(nèi)存交換瓶您,那么Redis及使用Redis數(shù)據(jù)的應(yīng)用性能都會(huì)受到嚴(yán)重影響麻捻。
理想情況下,“used_memory_rss”的值應(yīng)該比“used_memory”略微高一點(diǎn)呀袱。
“used_memory_rss”>“used_memory”贸毕,且兩者的值相差較大時(shí),表示存在(內(nèi)部或外部的)內(nèi)存碎片夜赵。內(nèi)存碎片的比率可以通過(guò)“mem_fragmentation_ratio”的值確定明棍。
“used_memory”>“used_memory_rss”,表示Redis的部分內(nèi)存被操作系統(tǒng)換出到Swap空間了寇僧,在這種情況下摊腋,操作可能會(huì)產(chǎn)生明顯延遲。
當(dāng)Redis釋放內(nèi)存時(shí)婉宰,分配器有可能會(huì)將內(nèi)存返還給操作系統(tǒng)歌豺,也可能不會(huì)推穷。
如果Redis釋放了內(nèi)存心包,卻沒(méi)有將內(nèi)存返還給操作系統(tǒng),那么“used_memory”的值可能和操作系統(tǒng)顯示的Redis內(nèi)存占用并不一致馒铃,通過(guò)查看“used_memory_peak”可以驗(yàn)證這種情況是否發(fā)生蟹腾。
①跟蹤內(nèi)存使用率
當(dāng)Redis內(nèi)存使用率超過(guò)可用內(nèi)存的95%時(shí),部分?jǐn)?shù)據(jù)開始在內(nèi)存與Swap空間來(lái)回交換区宇,如果沒(méi)有開啟RDB快照或AOF持久化策略娃殖,緩存數(shù)據(jù)在Redis崩潰時(shí)會(huì)有丟失風(fēng)險(xiǎn)。
當(dāng)開啟并觸發(fā)快照功能時(shí)议谷,Redis會(huì)fork一個(gè)子進(jìn)程炉爆,復(fù)制當(dāng)前內(nèi)存中的數(shù)據(jù)到硬盤,若當(dāng)前使用內(nèi)存超過(guò)可用內(nèi)存的45%時(shí)觸發(fā)快照功能,那么此時(shí)進(jìn)行的內(nèi)存交換可能會(huì)丟失數(shù)據(jù)芬首。如果此時(shí)Redis實(shí)例上有大量頻繁的更新操作赴捞,問(wèn)題會(huì)更加嚴(yán)重。
我們可以減少Redis的內(nèi)存占用率來(lái)解決該問(wèn)題郁稍,或者使用下面的技巧來(lái)避免內(nèi)存交換:
盡可能的使用Hash數(shù)據(jù)結(jié)構(gòu)
Redis在儲(chǔ)存小于100個(gè)字段的Hash結(jié)構(gòu)時(shí)赦政,存儲(chǔ)效率非常高,因此在不需要集合“set”操作或“l(fā)ist”的“push/pop”操作時(shí)耀怜,我們應(yīng)盡可能地使用Hash結(jié)構(gòu)恢着。
設(shè)置“key”的過(guò)期時(shí)間
通過(guò)在存儲(chǔ)對(duì)象時(shí)設(shè)置“key”的過(guò)期時(shí)間可以減少內(nèi)存使用率。倘若“key”在明確的時(shí)間周期內(nèi)使用或者舊“key”不大可能被使用時(shí)财破,就可以用Redis過(guò)期時(shí)間命令(expire,expireat, pexpire, pexpireat)去設(shè)置過(guò)期時(shí)間掰派,這樣Redis會(huì)在“key”過(guò)期時(shí)自動(dòng)將其刪除。
回收“key”狈究。
在Redis配置文件中(一般為“redis.conf”文件)碗淌,設(shè)置“maxmemory”的值可以限制Redis最大使用內(nèi)存,修改后重啟實(shí)例生效抖锥。
當(dāng)內(nèi)存使用達(dá)到設(shè)置的最大閥值時(shí)亿眠,需要選擇一種“key”的回收策略,可在“redis.conf”配置文件中修改“maxmemory-policy”屬性磅废。若是Redis數(shù)據(jù)集中的“key”都設(shè)置了過(guò)期時(shí)間纳像,那么“volatile-ttl”策略是比較好的選擇,但如果“key”在達(dá)到最大內(nèi)存限制時(shí)沒(méi)能迅速過(guò)期拯勉,或根本沒(méi)有設(shè)置過(guò)期時(shí)間竟趾,那么設(shè)置為“allkeys-lru”更加合適,它允許Redis從整個(gè)數(shù)據(jù)集中挑選近期最少使用的“key”進(jìn)行刪除(LRU淘汰算法)宫峦。
Redis還提供了一些其他淘汰策略岔帽,如下:
“volatile-lru”:使用LRU算法從已設(shè)置過(guò)期時(shí)間的數(shù)據(jù)集合中淘汰數(shù)據(jù)
“volatile-ttl”:從已設(shè)置過(guò)期時(shí)間的數(shù)據(jù)集合中淘汰即將過(guò)期的數(shù)據(jù)
“volatile-random”:從已設(shè)置過(guò)期時(shí)間的數(shù)據(jù)集合中隨機(jī)淘汰數(shù)據(jù)
“allkeys-lru”:使用LRU算法從所有數(shù)據(jù)集合中淘汰數(shù)據(jù)
“allkeys-random”:從數(shù)據(jù)集合中任意淘汰數(shù)據(jù)
“no-enviction”:禁止淘汰數(shù)據(jù)
設(shè)置“maxmemory”的值為系統(tǒng)可用內(nèi)存的45%或95%(取決于持久化策略),設(shè)置“maxmemory-policy”為“volatile-ttl”或“allkeys-lru”(取決于過(guò)期設(shè)置)导绷,可以比較準(zhǔn)確的限制Redis最大內(nèi)存使用率犀勒,在絕大多數(shù)場(chǎng)景下使用這2種方式可確保Redis不會(huì)進(jìn)行內(nèi)存交換。
延遲診斷
Redis之所以這么流行的主要原因之一就是低延遲特性帶來(lái)的高性能妥曲,所以說(shuō)解決延遲問(wèn)題是提高Redis性能最直接的辦法贾费。
以1G帶寬來(lái)說(shuō),若是延遲時(shí)間遠(yuǎn)高于200μs檐盟,那明顯是出現(xiàn)了性能問(wèn)題褂萧。Redis是單核執(zhí)行所有客戶端的請(qǐng)求的, 即使在服務(wù)器上會(huì)有一些慢的IO操作葵萎,這些請(qǐng)求也都是按序排隊(duì)等待執(zhí)行的导犹。
①通過(guò)slowlog查出引發(fā)延遲的慢命令
Redis中的“slowlog”命令可以讓我們快速定位到超出指定執(zhí)行時(shí)間的慢命令唱凯,默認(rèn)情況下命令若是執(zhí)行時(shí)間超過(guò)10ms就會(huì)被記錄到日志』蚜。“slowlog”只會(huì)記錄其命令執(zhí)行的時(shí)間波丰,不包含IO往返操作及由網(wǎng)絡(luò)延遲引起的慢響應(yīng) 。
通常1GB帶寬的網(wǎng)絡(luò)延遲預(yù)期在200μs左右舶得,倘若一個(gè)命令僅執(zhí)行時(shí)間就超過(guò)10ms(近網(wǎng)絡(luò)延遲的50倍)掰烟,此時(shí)可以使用“redis-cli”工具,輸入“slowlog get”命令進(jìn)行查看沐批,此時(shí)返回結(jié)果的第三個(gè)字段將以微秒為單位顯示命令的執(zhí)行時(shí)間纫骑,假如只需要查看最后10個(gè)慢命令,輸入“slowlog get 10”即可九孩。
②客戶端連接監(jiān)控
Redis是單線程模型先馆,只能單核處理客戶端的請(qǐng)求。由于客戶端連接數(shù)的增長(zhǎng)躺彬,處理請(qǐng)求的線程資源將降低分配給單個(gè)客戶端連接的處理時(shí)間煤墙,這時(shí)每個(gè)客戶端等待Redis共享服務(wù)的響應(yīng)時(shí)間將延長(zhǎng)。
因此宪拥,監(jiān)控客戶端連接數(shù)是非常有必要的仿野,通過(guò)監(jiān)控,可以確定客戶端創(chuàng)建連接數(shù)的數(shù)量是否超出預(yù)期她君,以及客戶端是否沒(méi)有有效釋放連接脚作。
查看命令如下:
“./redis-cli -p 6379 info |grep connected_clients”
Redis默認(rèn)允許客戶端連接的最大數(shù)量是10000,連接數(shù)超過(guò)5000以上缔刹,可能會(huì)影響Redis的性能球涛。
可嘗試通過(guò)如下辦法降低客戶端連接數(shù):
服務(wù)器內(nèi)存足夠:可增加Redis的實(shí)例個(gè)數(shù),均攤客戶端連接校镐。
服務(wù)器內(nèi)存足夠:可增加maxmemory配置亿扁,提高處理速度。
應(yīng)用通過(guò)連接池調(diào)用Redis:可適當(dāng)降低Redis連接的空閑數(shù)量鸟廓。
若以上方法未能降低Redis的連接數(shù)从祝,可限制客戶端連接數(shù)來(lái)提高性能。
③限制客戶端連接數(shù)
設(shè)置最大連接數(shù)可限制非預(yù)期的連接數(shù)增長(zhǎng)肝箱,并保持Redis的性能最優(yōu)哄褒。
Redis2.6版本及以上允許使用者通過(guò)配置文件(redis.conf)配置“maxclients”屬性稀蟋,來(lái)修改客戶端連接的最大值煌张。根據(jù)連接數(shù)負(fù)載的情況,這個(gè)數(shù)字應(yīng)該設(shè)置為預(yù)期連接數(shù)峰值的110到150之間退客,若連接數(shù)超出這個(gè)數(shù)值骏融,Redis會(huì)拒絕并立刻關(guān)閉新來(lái)的連接链嘀。
如新連接嘗試失敗,將返回一個(gè)錯(cuò)誤消息档玻,客戶端可執(zhí)行對(duì)應(yīng)的處理措施怀泊。
內(nèi)存碎片診斷
“info”信息中的“mem_fragmentation_ratio”給出了內(nèi)存碎片率的數(shù)據(jù)指標(biāo),該指標(biāo)由操作系統(tǒng)分配的內(nèi)存除Redis分配的內(nèi)存得出:
“mem_fragmentation_ratio = used_memory_rss / used_memory”
“used_memory”和“used_memory_rss”都包含的內(nèi)存分配有:
用戶定義的數(shù)據(jù):內(nèi)存被用來(lái)存儲(chǔ)“key-value”值
內(nèi)部開銷:存儲(chǔ)內(nèi)部Redis信息來(lái)表示不同的數(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)存得到的枣申。
如內(nèi)存碎片率超過(guò)1.5,可能是操作系統(tǒng)或Redis實(shí)例中內(nèi)存管理變差的表現(xiàn)看杭。
下面列舉3種解決內(nèi)存管理變差并提高Redis性能的方法:
①重啟Redis服務(wù)器
如內(nèi)存碎片率超過(guò)1.5忠藤,重啟Redis服務(wù)器可讓額外產(chǎn)生的內(nèi)存碎片失效并作為新內(nèi)存使用,使操作系統(tǒng)恢復(fù)高效的內(nèi)存管理楼雹。
額外碎片的產(chǎn)生是由于Redis釋放了內(nèi)存塊模孩,但編譯時(shí)制定的內(nèi)存分配器(“l(fā)ibc”、“jemalloc”或“tcmalloc”)并沒(méi)有返回內(nèi)存給操作系統(tǒng)贮缅。
通過(guò)比較“used_memory_peak”榨咐、“used_memory_rss”和“used_memory_metrics”的數(shù)據(jù)指標(biāo)可檢查額外內(nèi)存碎片的占用。如果過(guò)去Redis內(nèi)存使用的峰值“used_memory_peak”和“used_memory_rss”的值大致相等谴供,且二者明顯超過(guò)“used_memory”的值祭芦,則額外的內(nèi)存碎片正在產(chǎn)生。 在“redis-cli”工具上輸入“info memory”可以查看上面三個(gè)指標(biāo)的信息憔鬼。
重啟服務(wù)器前龟劲,需在“redis-cli”工具上輸入“shutdown save”命令,強(qiáng)制讓Redis數(shù)據(jù)庫(kù)執(zhí)行保存操作并關(guān)閉Redis服務(wù)轴或,這樣能保證關(guān)閉Redis時(shí)不丟失任何數(shù)據(jù)昌跌。在重啟后,Redis會(huì)從硬盤上加載持久化的文件照雁,確保數(shù)據(jù)集持續(xù)可用蚕愤。
②限制內(nèi)存交換
如果內(nèi)存碎片率低于1,Redis實(shí)例可能會(huì)把部分?jǐn)?shù)據(jù)交換到硬盤上饺蚊,將嚴(yán)重影響Redis的性能萍诱。我們可以增加可用物理內(nèi)存或減少Redis實(shí)例內(nèi)存占用。具體可查看“used_memory”章節(jié)的優(yōu)化建議污呼。
③修改內(nèi)存分配器
Redis支持“glibc’s malloc”裕坊、“jemalloc11”和“tcmalloc”等幾種不同的內(nèi)存分配器,每個(gè)分配器在內(nèi)存分配和碎片上都有不同的實(shí)現(xiàn)燕酷。
修改Redis默認(rèn)內(nèi)存分配器籍凝,需要完全理解這幾種內(nèi)存分配器的差異周瞎,也需重新編譯Redis,因此饵蒂,不建議普通管理員修改声诸。通過(guò)這個(gè)方法可了解Redis內(nèi)存分配器所做的工作,改善內(nèi)存碎片問(wèn)題退盯。
Redis優(yōu)化總結(jié)
①根據(jù)業(yè)務(wù)需要選擇合適的數(shù)據(jù)類型彼乌,并為不同的應(yīng)用場(chǎng)景設(shè)置相應(yīng)的緊湊存儲(chǔ)參數(shù)。
②若業(yè)務(wù)場(chǎng)景不需要數(shù)據(jù)持久化渊迁,關(guān)閉持久化方式用以提高處理性能及內(nèi)存使用率囤攀。
③不要讓你的Redis所在機(jī)器物理內(nèi)存使用超過(guò)實(shí)際內(nèi)存總量的60%。
④默認(rèn)情況下宫纬,盡量不要讓Redis實(shí)例的客戶端連接數(shù)超出5000