Redis性能監控問題

關注 「Java藝術」一塊兒來充電吧!

併發數上升,究竟是哪一個服務處理能力到了瓶頸,仍是Redis性能到了瓶頸,只有找出是哪裏的性能問題,才能對症下藥。因此,瞭解redis的一些運維知識可以幫助咱們快速斷定是否Redis集羣的性能問題。
css


1
redis-cli命令的 --stat選項


關於stat選項,官網也是介紹的比較簡單。使用redis-cli命令加上stat選項能夠實時監視redis實例,好比當前節點內存中緩存的 key總數以及每秒處理請求數等。stat默認每隔一秒會輸出一行信息,若是須要改變頻率可以使用-i <interval> 指定頻率,單位爲秒,如--stat -i 100。須要配合-h選項使用。java



關於requests與connections官方也沒有介紹,本身結合本地和線上的輸出,作了對比得出的結論。nginx

 ------- data ------ --------------------- load -------------------- - child -keys mem clients blocked requests connections 97146 6.82G 1724 0 60068357585 (+49536) 93936323 97146 6.82G 1724 0 60068403702 (+46117) 93936323 97146 6.82G 1724 0 60068451875 (+48173) 93936323 97146 6.82G 1724 0 60068496037 (+44162) 93936323


  • keys:當前節點緩存的key總數redis

  • mem:當前節點緩存總的佔用內存swift

  • clients:當前節點的活躍鏈接數,或者說未斷開鏈接的總鏈接數緩存

  • blocked:當前節點正在等待阻塞命令的數量安全

  • requests:當前處理的請求數,與上一次請求數相減可知1秒所處理的請求,或者說所執行的命令數。服務器

  • connections:是歷史鏈接總數,即到目前爲止,一共新建了多少個鏈接。與前一次相減,能夠得出一秒內新建的鏈接數。微信


Requests列括號裏的數是每間隔所處理的命令數。好比當前60068496037減去前一次60068451875 等於44162,因爲stat默認頻率是每秒輸出一次,44162就是每秒執行4萬多條命令。正好是括號裏面的數字,也所以能夠知道,括號裏面的數字表明每秒(interval)執行的命令數。網絡



固然--stat每秒輸出一次結果也是一條命令,因此在沒有任何請求的狀況下,你看到的requests是自增的,能夠本地起個redsi服務,而後使用redis-cli --stat觀察下輸出。



Blocked並非排隊等待執行的命令數,而是客戶端執行阻塞命令的總數。好比BLPOP。


Connections也是頗有用的參數,若是發現connections與前一次的差值很大,且很頻繁,那就要看下代碼中鏈接池配置是否生效了。


2
使用--stat分析讀寫分離的主從集羣缺點


在此以前,咱們項目中用的是古老的主從集羣模式,使用讀寫分離的鏈接池,全部寫請求都會訪問主節點,全部讀請求都會訪問從節點,那麼讀寫分離會存在哪些問題?


觀察主節點,全部寫請求都會發到這個節點。

------- data ------ --------------------- load -------------------- - child -keys mem clients blocked requests connections 382453 1.22G 1305 0 53636611824 (+5112) 70953183 382453 1.22G 1305 0 53636616926 (+5102) 70953183 382453 1.22G 1305 0 53636622056 (+5130) 70953183

觀察從節點,全部讀請求都會發到這個節點。

------- data ------ --------------------- load -------------------- - child -keys mem clients blocked requests connections 382551 1.22G 1307 0 197046636517 (+34705) 75561440 382551 1.22G 1307 0 197046669775 (+33258) 75561440 382552 1.22G 1307 0 197046701747 (+31972) 75561440 382551 1.22G 1307 0 197046734329 (+32582) 75561440

很明顯,主節點每秒處理的寫請求數遠小於從節點每秒處理的讀請求數。在極端狀況下,好比寫少讀多的場景,使用這種主從讀寫分離方案,會致使一個節點無請求,而另外一個節點忙得不可開交。


主從讀寫分離還有一個缺點,若是一時間批量寫了不少數據,因爲主從同步的延時問題,會出現一個空白期,從從節點上讀不到數據。若是有實時性要求高的場景,或者大批量數據更新很頻繁的場景,仍是不建議使用讀寫分離。從節點應該只用來提供高可用的保證,在主節點掛的狀況下從節點保證這部分槽位可用。固然,這不用也是浪費。


3
分析兩主無從Cluster集羣模式


只有兩個主節點的Cluster集羣,槽位平均分配。使用redis-cli --stat實時監視實例。

節點1輸出片斷:

------- data ------ --------------------- load -------------------- - child -keys mem clients blocked requests connections 97270 6.82G 1726 0 60242433804 (+26930) 94154236 97270 6.81G 1726 0 60242457927 (+24123) 94154236 97270 6.82G 1725 0 60242485748 (+27821) 94154236 97270 6.82G 1725 0 60242511827 (+26079) 94154236

節點2輸出片斷:

------- data ------ --------------------- load -------------------- - child -keys mem clients blocked requests connections 96077 4.20G 1725 0 61244385399 (+32594) 94349868 96076 4.20G 1725 0 61244417031 (+31632) 94349868 96075 4.21G 1725 0 61244443142 (+26111) 94350076 96075 4.20G 1725 0 61244466682 (+23540) 94350076

從兩個節點的當前鏈接數能夠看出,JedisCluster配置的鏈接池會爲每一個節點建立一個鏈接池,每一個節點的鏈接池鏈接數都是相同的。之因此會每一個節點都維持相同的鏈接數,由於每一個請求的key都有可能落在其中的一個節點上,你沒法預知程序運行過程當中落在哪一個節點的請求數較多,哪一個較少。


當各個服務的集羣總節點數不少的狀況下,就須要合理分配鏈接池的最大鏈接數。官方推薦單個redis節點最大鏈接數不超過1w,假設有20個服務節點須要用到redis,那麼每一個節點的鏈接池最大鏈接數最大不能超過10000/20 = 500。建議鏈接池的最大鏈接數比業務線程的最大線程數多20個鏈接,只要確保每一個工做線程都能有一個redis鏈接,不至於爲了等待鏈接而阻塞就能夠,由於不可能一個線程同時會用到2個以上的鏈接。假設工做線程數爲200,那麼redis鏈接池能夠配置爲200~220。


從兩個節點的內存使用和每秒處理的請求數可以看出,數據的傾斜仍是較爲嚴重的,每秒請求數相差在1w左右,這個差距還在可接受範圍內。若是請求和內存的傾斜比較嚴重,就能夠從新分配槽位,給請求和存儲較少的一方分配更多的槽位以達到平衡狀態。


4
使用info也能統計每秒處理的命令數


stat對於性能監控仍是頗有幫助的。可以獲取到每秒處理的命令數還能夠經過info Stats。

172.31.x.x:6379> info stats# Stats.....instantaneous_ops_per_sec:8589....


instantaneous_ops_per_sec:redis內部較實時的每秒執行的命令數。


若是想要獲取更詳細的每種命令的平均耗時,可使用info Commandstats查看如:

172.31.x.x:6379> info Commandstatscmdstat_zrangebyscore:calls=1006828954,usec=9633479351,usec_per_call=9.57cmdstat_rpush:calls=49673,usec=278402,usec_per_call=5.60cmdstat_setbit:calls=86267170,usec=2645199883,usec_per_call=30.66......


  • cmdstat_zrangebyscore: 即zrangebyscore命令

  • calls:命令調用總次數

  • usec: 總耗時

  • usec_per_call: 平均耗時,單位微秒


5
slowlog慢查詢分析


當命令的執行耗時超過配置的慢查詢時間,則會被放入一個慢查詢的隊列中。可經過config set slowlog-log-slower-than xxx修改慢查詢時間,單位微秒,默認狀況下,這個值爲10000,即全部執行時間超過10ms的都會記錄到慢查詢隊列。使用slowlog get能夠查看慢查詢信息。

172.31.x.x:6379> slowlog get 1 1) 1) (integer) 6018 2) (integer) 1575108134 3) (integer) 19861 4) 1) "ZRANGEBYSCORE" 2) "ip-country-city-locations-range-3708" 3) "3.72526109E9" 4) "1.7976931348623157E308" 5) "limit" 6) "0" 7) "1"     5)"172.31.x.x:xxx" ......
1)、慢查詢自增id;
2)、命令執行完成時間,時間戳;
3)、命令執行耗時,單位爲微秒,1秒=1000毫秒,1毫秒等於1000微秒;
4)、執行的命令;
5) 、發起該命令請求的客戶端ip及端口號。

經過分析慢查詢,能夠分析項目中哪些地方用到這些命令,及時優化這些命令可以在大流量來臨以前杜絕隱患,也能及時對代碼進行調優,經過替換存儲的數據結構優化查詢性能,減小單次請求的耗時。

6
網絡延遲也是咱們要關注的問題


redis-cli命令--latency選項能夠測試當前服務器與redis某個節點的網絡延遲。
>src/redis-cli --latency -h 172.31.1.1min: 0, max: 12, avg: 0.25 (1047 samples)
avg:0.25,即延遲爲250μs。若是經過外網鏈接網絡延遲會很高,好比跨機房的redis調用,延遲高的狀況下使用redis反而比使用本地硬盤讀寫性能更差。

還有其它影響redis性能的因素,好比內存的使用,持久化策略等。

7
AOF持久化策略影響性能問題


若是數據不須要持久化,或者要求不嚴格,建議直接禁用掉AOF持久化策略,同時RDB快照的保存時間間隔也要調高一些,好比一小時一次,以此達到更高的性能。

# 是否開啓持久化策略# (支持同時開啓RDB和AOF,即混合策略)appendonly no
# yes: 在aof重寫期間不作fsync刷盤操做,可能丟失整個AOF重寫期間的數據,no-appendfsync-on-rewrite yes
# fsync針對單個文件操做(好比AOF文件),作強制硬盤同步,fsync將阻塞直到寫入硬盤完成後返回,保證了數據持久化。# always:每次寫入都要同步AOF文件。# no:同步硬盤操做由操做系統負責,一般同步週期爲30秒,數據安全性沒法保證。# everysec:由專門線程每秒同步一次fsync。理論上只有在系統忽然宕機的狀況下丟失1秒的數據。appendfsync no
#當前aof文件大小與上次重寫後文件大小的比值超過該值時進行重寫,200即等於以前的2倍auto-aof-rewrite-percentage 200
#當aof文件大小大於該值時進程重寫,以減少aof文件佔用的磁盤空間auto-aof-rewrite-min-size 64mb

appendfsync爲everysec時的刷盤過程。



1)主線程負責寫入AOF緩衝區。
2)AOF線程負責每秒執行一次同步磁盤操做,並記錄最近一次同步時間。
3)主線程負責對比上次AOF同步時間。若是距上次同步成功時間在2秒內,主線程直接返回;若是距上次同步成功時間超過2秒,主線程將會阻塞,直到同步操做完成。

果系統fsync緩慢,將會致使Redis主線程阻塞影響效率。


上次我將一千兩百萬記錄的ip庫數據寫入redis時,就由於開啓了aof持久化策略,因爲大批量數據的寫入,致使aof文件幾乎每秒重寫一次,後面改成1g時重寫也由於文件過大重寫時間長,沒有一次可以成功將一千兩百萬數據成功寫入的。


往期原創精選
時隔一年再次觸碰asm,動態字節碼技術的妙用
Dubbo自適應隨機負載均衡策略的實現
基於Redis實現範圍查詢的IP庫緩存設計方案




公衆號ID:javaskill
掃碼關注最新動態


本文分享自微信公衆號 - Java藝術(javaskill)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索