文章轉(zhuǎn)摘自:http://www.cnblogs.com/mushroom/p/4738170.html
性能相關(guān)的數(shù)據(jù)指標(biāo)
通過Redis-cli命令行界面訪問到Redis服務(wù)器,然后使用info命令獲取所有與Redis服務(wù)相關(guān)的信息。通過這些信息來分析文章后面提到的一些性能指標(biāo)护侮。info命令輸出的數(shù)據(jù)可分為10個類別坡贺,分別是:
server
clients
memory
persistence
stats
replication
cpu
commandstats
cluster
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ù)周荐。
(2)]為了快速定位并解決性能問題狭莱,這里選擇5個關(guān)鍵性的數(shù)據(jù)指標(biāo),它包含了大多數(shù)人在使用Redis上會經(jīng)常碰到的性能問題概作。
內(nèi)存使用率used_memory
其他字段代表的含義,都以字節(jié)為單位:
used_memory_rss:從操作系統(tǒng)上顯示已經(jīng)分配的內(nèi)存總量丘跌。
mem_fragmentation_ratio: 內(nèi)存碎片率袭景。
used_memory_lua: Lua腳本引擎所使用的內(nèi)存大小。
mem_allocator: 在編譯時指定的Redis使用的內(nèi)存分配器闭树,可以是libc耸棒、jemalloc、tcmalloc报辱。
因內(nèi)存交換引起的性能問題
內(nèi)存使用率是Redis服務(wù)最關(guān)鍵的一部分与殃。如果一個Redis實例的內(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)行讀寫操作鸵赫,時間上慢了近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實例正在進(jìn)行內(nèi)存交換或者已經(jīng)內(nèi)存交換完畢。管理員根據(jù)這個情況者吁,執(zhí)行相對應(yīng)的應(yīng)急措施窘俺。
跟蹤內(nèi)存使用率
若是在使用Redis期間沒有開啟rdb快照或aof持久化策略,那么緩存數(shù)據(jù)在Redis崩潰時就有丟失的危險复凳。因為當(dāng)Redis內(nèi)存使用率超過可用內(nèi)存的95%時瘤泪,部分?jǐn)?shù)據(jù)開始在內(nèi)存與swap空間來回交換灶泵,這時就可能有丟失數(shù)據(jù)的危險。當(dāng)開啟并觸發(fā)快照功能時对途,Redis會fork一個子進(jìn)程把當(dāng)前內(nèi)存中的數(shù)據(jù)完全復(fù)制一份寫入到硬盤上赦邻。因此若是當(dāng)前使用內(nèi)存超過可用內(nèi)存的45%時觸發(fā)快照功能,那么此時進(jìn)行的內(nèi)存交換會變的非常危險(可能會丟失數(shù)據(jù))实檀。 倘若在這個時候?qū)嵗嫌写罅款l繁的更新操作惶洲,問題會變得更加嚴(yán)重。
通過減少Redis的內(nèi)存占用率膳犹,來避免這樣的問題恬吕,或者使用下面的技巧來避免內(nèi)存交換發(fā)生:
假如緩存數(shù)據(jù)小于4GB,就使用32位的Redis實例须床。因為32位實例上的指針大小只有64位的一半铐料,它的內(nèi)存空間占用空間會更少些。 這有一個壞處就是侨颈,假設(shè)物理內(nèi)存超過4GB,那么32位實例能使用的內(nèi)存仍然會被限制在4GB以下芯义。 要是實例同時也共享給其他一些應(yīng)用使用的話哈垢,那可能需要更高效的64位Redis實例,這種情況下切換到32位是不可取的扛拨。 不管使用哪種方式耘分,Redis的dump文件在32位和64位之間是互相兼容的, 因此倘若有減少占用內(nèi)存空間的需求绑警,可以嘗試先使用32位求泰,后面再切換到64位上。
盡可能的使用Hash數(shù)據(jù)結(jié)構(gòu)计盒。因為Redis在儲存小于100個字段的Hash結(jié)構(gòu)上渴频,其存儲效率是非常高的。所以在不需要集合(set)操作或list的push/pop操作的時候北启,盡可能的使用Hash結(jié)構(gòu)卜朗。比如,在一個web應(yīng)用程序中咕村,需要存儲一個對象表示用戶信息场钉,使用單個key表示一個用戶,其每個屬性存儲在Hash的字段里懈涛,這樣要比給每個屬性單獨設(shè)置一個key-value要高效的多逛万。 通常情況下倘若有數(shù)據(jù)使用string結(jié)構(gòu),用多個key存儲時批钠,那么應(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中取出指定的字段呛每。
設(shè)置key的過期時間。一個減少內(nèi)存使用率的簡單方法就是坡氯,每當(dāng)存儲對象時確保設(shè)置key的過期時間晨横。倘若key在明確的時間周期內(nèi)使用或者舊key不大可能被使用時,就可以用Redis過期時間命令(expire,expireat, pexpire, pexpireat)去設(shè)置過期時間箫柳,這樣Redis會在key過期時自動刪除key手形。 假如你知道每秒鐘有多少個新key-value被創(chuàng)建,那可以調(diào)整key的存活時間悯恍,并指定閥值去限制Redis使用的最大內(nèi)存库糠。
回收key。在Redis配置文件中(一般叫Redis.conf)涮毫,通過設(shè)置“maxmemory”屬性的值可以限制Redis最大使用的內(nèi)存瞬欧,修改后重啟實例生效。 也可以使用客戶端命令config set maxmemory 去修改值罢防,這個命令是立即生效的艘虎,但會在重啟后會失效,需要使用config rewrite命令去刷新配置文件咒吐。 若是啟用了Redis快照功能野建,應(yīng)該設(shè)置“maxmemory”值為系統(tǒng)可使用內(nèi)存的45%,因為快照時需要一倍的內(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è)置的最大閥值時硅确,需要選擇一種key的回收策略肿孵,可在Redis.conf配置文件中修改“maxmemory-policy”屬性值。 若是Redis數(shù)據(jù)集中的key都設(shè)置了過期時間疏魏,那么“volatile-ttl”策略是比較好的選擇停做。但如果key在達(dá)到最大內(nèi)存限制時沒能夠迅速過期,或者根本沒有設(shè)置過期時間大莫。那么設(shè)置為“allkeys-lru”值比較合適蛉腌,它允許Redis從整個數(shù)據(jù)集中挑選最近最少使用的key進(jìn)行刪除(LRU淘汰算法)。Redis還提供了一些其他淘汰策略,如下:
volatile-lru:使用LRU算法從已設(shè)置過期時間的數(shù)據(jù)集合中淘汰數(shù)據(jù)烙丛。
volatile-ttl:從已設(shè)置過期時間的數(shù)據(jù)集合中挑選即將過期的數(shù)據(jù)淘汰舅巷。
volatile-random:從已設(shè)置過期時間的數(shù)據(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”(取決于過期設(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每時每刻都在處理從客戶端請求過來的命令褥芒,它可以是Redis提供的140種命令的任意一個嚼松。 total_commands_processed字段的值是遞增的,比如Redis服務(wù)分別處理了client_x請求過來的2個命令和client_y請求過來的3個命令锰扶,那么命令處理總數(shù)(total_commands_processed)就會加上5献酗。
分析命令處理總數(shù),診斷響應(yīng)延遲坷牛。
在Redis實例中罕偎,跟蹤命令處理總數(shù)是解決響應(yīng)延遲問題最關(guān)鍵的部分,因為Redis是個單線程模型漓帅,客戶端過來的命令是按照順序執(zhí)行的锨亏。比較常見的延遲是帶寬痴怨,通過千兆網(wǎng)卡的延遲大約有200μs忙干。倘若明顯看到命令的響應(yīng)時間變慢,延遲高于200μs浪藻,那可能是Redis命令隊列里等待處理的命令數(shù)量比較多捐迫。 如上所述,延遲時間增加導(dǎo)致響應(yīng)時間變慢可能是由于一個或多個慢命令引起的爱葵,這時可以看到每秒命令處理數(shù)在明顯下降施戴,甚至于后面的命令完全被阻塞,導(dǎo)致Redis性能降低萌丈。要分析解決這個性能問題赞哗,需要跟蹤命令處理數(shù)的數(shù)量和延遲時間。比如可以寫個腳本辆雾,定期記錄total_commands_processed的值肪笋。當(dāng)客戶端明顯發(fā)現(xiàn)響應(yīng)時間過慢時,可以通過記錄的total_commands_processed歷史數(shù)據(jù)值來判斷命理處理總數(shù)是上升趨勢還是下降趨勢,以便排查問題藤乙。
使用命令處理總數(shù)解決延遲時間增加猜揪。
通過與記錄的歷史數(shù)據(jù)比較得知,命令處理總數(shù)確實是處于上升或下降狀態(tài)坛梁,那么可能是有2個原因引起的:
命令隊列里的命令數(shù)量過多而姐,后面命令一直在等待中。
幾個慢命令阻塞Redis划咐。
下面有三個辦法可以解決拴念,因上面2條原因引起的響應(yīng)延遲問題。
使用多參數(shù)命令:若是客戶端在很短的時間內(nèi)發(fā)送大量的命令過來尖殃,會發(fā)現(xiàn)響應(yīng)時間明顯變慢丈莺,這由于后面命令一直在等待隊列中前面大量命令執(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ù)状婶。
管道命令:另一個減少多命令的方法是使用管道(pipeline),把幾個命令合并一起執(zhí)行馅巷,從而減少因網(wǎng)絡(luò)開銷引起的延遲問題膛虫。因為10個命令單獨發(fā)送到服務(wù)端會引起10次網(wǎng)絡(luò)延遲開銷,使用管道會一次性把執(zhí)行結(jié)果返回钓猬,僅需要一次網(wǎng)絡(luò)延遲開銷稍刀。Redis本身支持管道命令,大多數(shù)客戶端也支持敞曹,倘若當(dāng)前實例延遲很明顯账月,那么使用管道去降低延遲是非常有效的。
避免操作大集合的慢命令:如果命令處理頻率過低導(dǎo)致延遲時間增加澳迫,這可能是因為使用了高時間復(fù)雜度的命令操作導(dǎo)致局齿,這意味著每個命令從集合中獲取數(shù)據(jù)的時間增大。 所以減少使用高時間復(fù)雜的命令橄登,能顯著的提高的Redis的性能抓歼。下面的表格是高時間復(fù)雜度命令的列表担平,其詳細(xì)描述了命令的屬性,有這助于高效合理的锭部、最優(yōu)化的使用這些命令(如果不得不使用的話)暂论,以提高Redis性能。
延遲時間
Redis的延遲數(shù)據(jù)是無法從info信息中獲取的拌禾。倘若想要查看延遲時間取胎,可以用 Redis-cli工具加--latency參數(shù)運行,如:
Redis-cli --latency -h 127.0.0.1 -p 6379
其host和port是Redis實例的ip及端口湃窍。由于當(dāng)前服務(wù)器不同的運行情況闻蛀,延遲時間可能有所誤差,通常1G網(wǎng)卡的延遲時間是200μs您市。
以毫秒為單位測量Redis的響應(yīng)延遲時間觉痛,樓主本機的延遲是300μs:
跟蹤Redis延遲性能
Redis之所以這么流行的主要原因之一就是低延遲特性帶來的高性能,所以說解決延遲問題是提高Redis性能最直接的辦法茵休。拿1G帶寬來說薪棒,若是延遲時間遠(yuǎn)高于200μs,那明顯是出現(xiàn)了性能問題榕莺。 雖然在服務(wù)器上會有一些慢的IO操作俐芯,但Redis是單核接受所有客戶端的請求,所有請求是按良好的順序排隊執(zhí)行钉鸯。因此若是一個客戶端發(fā)過來的命令是個慢操作吧史,那么其他所有請求必須等待它完成后才能繼續(xù)執(zhí)行。
使用延遲命令提高性能
一旦確定延遲時間是個性能問題后唠雕,這里有幾個辦法可以用來分析解決性能問題贸营。
1. 使用slowlog查出引發(fā)延遲的慢命令:Redis中的slowlog命令可以讓我們快速定位到那些超出指定執(zhí)行時間的慢命令,默認(rèn)情況下命令若是執(zhí)行時間超過10ms就會被記錄到日志岩睁。slowlog只會記錄其命令執(zhí)行的時間钞脂,不包含io往返操作,也不記錄單由網(wǎng)絡(luò)延遲引起的響應(yīng)慢笙僚。通常1gb帶寬的網(wǎng)絡(luò)延遲芳肌,預(yù)期在200μs左右灵再,倘若一個命令僅執(zhí)行時間就超過10ms肋层,那比網(wǎng)絡(luò)延遲慢了近50倍。 想要查看所有執(zhí)行時間比較慢的命令翎迁,可以通過使用Redis-cli工具栋猖,輸入slowlog get命令查看,返回結(jié)果的第三個字段以微妙位單位顯示命令的執(zhí)行時間汪榔。假如只需要查看最后10個慢命令蒲拉,輸入slowlog get 10即可。 關(guān)于怎么定位到是由慢命令引起的延遲問題,可查看total_commands_processed介紹章節(jié)雌团。
圖中字段分別意思是:
1=日志的唯一標(biāo)識符
2=被記錄命令的執(zhí)行時間點燃领,以 UNIX 時間戳格式表示
3=查詢執(zhí)行時間,以微秒為單位锦援。例子中命令使用54毫秒猛蔽。
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)控客戶端的連接:因為Redis是單線程模型(只能使用單核)瓤檐,來處理所有客戶端的請求蒂誉, 但由于客戶端連接數(shù)的增長,處理請求的線程資源開始降低分配給單個客戶端連接的處理時間距帅,這時每個客戶端需要花費更多的時間去等待Redis共享服務(wù)的響應(yīng)右锨。這種情況下監(jiān)控客戶端連接數(shù)是非常重要的,因為客戶端創(chuàng)建連接數(shù)的數(shù)量可能超出預(yù)期的數(shù)量碌秸,也可能是客戶端端沒有有效的釋放連接绍移。在Redis-cli工具中輸入info clients可以查看到當(dāng)前實例的所有客戶端連接信息。如下圖讥电,第一個字段(connected_clients)顯示當(dāng)前實例客戶端連接的總數(shù):
[圖片上傳中蹂窖。。恩敌。(9)]
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此時有非預(yù)期數(shù)量的連接數(shù),以便執(zhí)行對應(yīng)的處理措施是复。 上述二種做法對控制連接數(shù)的數(shù)量和持續(xù)保持Redis的性能最優(yōu)是非常重要的删顶,
4.加強內(nèi)存管理:較少的內(nèi)存會引起Redis延遲時間增加。如果Redis占用內(nèi)存超出系統(tǒng)可用內(nèi)存淑廊,操作系統(tǒng)會把Redis進(jìn)程的一部分?jǐn)?shù)據(jù)逗余,從物理內(nèi)存交換到硬盤上,內(nèi)存交換會明顯的增加延遲時間季惩。關(guān)于怎么監(jiān)控和減少內(nèi)存使用录粱,可查看used_memory介紹章節(jié)。
5. 性能數(shù)據(jù)指標(biāo):
分析解決Redis性能問題画拾,通常需要把延遲時間的數(shù)據(jù)變化與其他性能指標(biāo)的變化相關(guān)聯(lián)起來啥繁。命令處理總數(shù)下降的發(fā)生可能是由慢命令阻塞了整個系統(tǒng),但如果命令處理總數(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ù)據(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)存分配有:
用戶定義的數(shù)據(jù):內(nèi)存被用來存儲key-value值。
內(nèi)部開銷: 存儲內(nèi)部Redis信息用來表示不同的數(shù)據(jù)類型佑吝。
used_memory_rss的rss是Resident Set Size的縮寫坐昙,表示該進(jìn)程所占物理內(nèi)存的大小绳匀,是操作系統(tǒng)分配給Redis實例的內(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)用程序的運行。
理解資源性能
跟蹤內(nèi)存碎片率對理解Redis實例的資源性能是非常重要的蜒滩。內(nèi)存碎片率稍大于1是合理的滨达,這個值表示內(nèi)存碎片率比較低,也說明redis沒有發(fā)生內(nèi)存交換俯艰。但如果內(nèi)存碎片率超過1.5捡遍,那就說明Redis消耗了實際需要物理內(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實例中內(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)存分配器是在編譯時指定的肘习,可以是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命令佃蚜,意思是強制讓Redis數(shù)據(jù)庫執(zhí)行保存操作并關(guān)閉Redis服務(wù),這樣做能保證在執(zhí)行Redis關(guān)閉時不丟失任何數(shù)據(jù)着绊。 在重啟后谐算,Redis會從硬盤上加載持久化的文件,以確保數(shù)據(jù)集持續(xù)可用归露。
2.限制內(nèi)存交換: 如果內(nèi)存碎片率低于1氯夷,Redis實例可能會把部分?jǐn)?shù)據(jù)交換到硬盤上。內(nèi)存交換會嚴(yán)重影響Redis的性能靶擦,所以應(yīng)該增加可用物理內(nèi)存或減少實Redis內(nèi)存占用腮考。 可查看used_memory章節(jié)的優(yōu)化建議。
3.修改內(nèi)存分配器:Redis支持glibc’s malloc玄捕、jemalloc11踩蔚、tcmalloc幾種不同的內(nèi)存分配器,每個分配器在內(nèi)存分配和碎片上都有不同的實現(xiàn)枚粘。不建議普通管理員修改Redis默認(rèn)內(nèi)存分配器馅闽,因為這需要完全理解這幾種內(nèi)存分配器的差異,也要重新編譯Redis馍迄。這個方法更多的是讓其了解Redis內(nèi)存分配器所做的工作福也,當(dāng)然也是改善內(nèi)存碎片問題的一種辦法。
回收key
info信息中的evicted_keys字段顯示的是攀圈,因為maxmemory限制導(dǎo)致key被回收刪除的數(shù)量暴凑。關(guān)于maxmemory的介紹見前面章節(jié),回收key的情況只會發(fā)生在設(shè)置maxmemory值后赘来,不設(shè)置會發(fā)生內(nèi)存交換现喳。 當(dāng)Redis由于內(nèi)存壓力需要回收一個key時,Redis首先考慮的不是回收最舊的數(shù)據(jù)犬辰,而是在最近最少使用的key或即將過期的key中隨機選擇一個key嗦篱,從數(shù)據(jù)集中刪除。
這可以在配置文件中設(shè)置maxmemory-policy值為“volatile-lru”或“volatile-ttl”幌缝,來確定Redis是使用lru策略還是過期時間策略灸促。 倘若所有的key都有明確的過期時間,那過期時間回收策略是比較合適的。若是沒有設(shè)置key的過期時間或者說沒有足夠的過期key浴栽,那設(shè)置lru策略是比較合理的荒叼,這可以回收key而不用考慮其過期狀態(tài)。
根據(jù)key回收定位性能問題
跟蹤key回收是非常重要的吃度,因為通過回收key甩挫,可以保證合理分配Redis有限的內(nèi)存資源贴硫。如果evicted_keys值經(jīng)常超過0椿每,那應(yīng)該會看到客戶端命令響應(yīng)延遲時間增加,因為Redis不但要處理客戶端過來的命令請求英遭,還要頻繁的回收滿足條件的key间护。需要注意的是,回收key對性能的影響遠(yuǎn)沒有內(nèi)存交換嚴(yán)重挖诸,若是在強制內(nèi)存交換和設(shè)置回收策略做一個選擇的話汁尺,選擇設(shè)置回收策略是比較合理的,因為把內(nèi)存數(shù)據(jù)交換到硬盤上對性能影響非常大(見前面章節(jié))多律。
減少回收key以提升性能
減少回收key的數(shù)量是提升Redis性能的直接辦法痴突,下面有2種方法可以減少回收key的數(shù)量:
1.增加內(nèi)存限制:倘若開啟快照功能,maxmemory需要設(shè)置成物理內(nèi)存的45%狼荞,這幾乎不會有引發(fā)內(nèi)存交換的危險辽装。若是沒有開啟快照功能,設(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.對實例進(jìn)行分片:分片是把數(shù)據(jù)分割成合適大小锁荔,分別存放在不同的Redis實例上,每一個實例都包含整個數(shù)據(jù)集的一部分雅倒。通過分片可以把很多服務(wù)器聯(lián)合起來存儲數(shù)據(jù)功咒,相當(dāng)于增加總的物理內(nèi)存,使其在沒有內(nèi)存交換和回收key的策略下也能存儲更多的key筷厘。假如有一個非常大的數(shù)據(jù)集恬总,maxmemory已經(jīng)設(shè)置前普,實際內(nèi)存使用也已經(jīng)超過了推薦設(shè)置的閥值,那通過數(shù)據(jù)分片能明顯減少key的回收壹堰,從而提高Redis的性能拭卿。 分片的實現(xiàn)有很多種方法,下面是Redis實現(xiàn)分片的幾種常見方式:
a. Hash分片:一個比較簡單的方法實現(xiàn)贱纠,通過Hash函數(shù)計算出key的Hash值峻厚,然后值所在范圍對應(yīng)特定的Redis實例。
b. 代理分片:客戶端把請求發(fā)送到代理上谆焊,代理通過分片配置表選擇對應(yīng)的Redis實例惠桃。 如Twitter的Twemproxy,豌豆莢的codis辖试。
c. 一致性Hash分片: 參見前面博客《一致性Hash分片詳解》
d. 虛擬桶分片:參見前面博客《虛擬桶分詳解》
總結(jié)
對于開發(fā)者來說辜王,Redis是個速度非常快的key-value內(nèi)存數(shù)據(jù)庫罐孝,并提供了方便的API接口呐馆。為了最好最優(yōu)的使用Redis,需要理解哪些因素能影響到Redis性能肾档,哪些數(shù)據(jù)指標(biāo)能幫助我們避免性能陷阱摹恰。 通過本篇,能理解Redis中的重要性能指標(biāo)怒见,怎么查看俗慈,更重要的是怎么利用這些數(shù)據(jù)排查解決Redis性能問題。