Redis集羣性能問題深度分析

Redis集羣性能問題深度分析


參考

Redis開發與運維 https://redis.io/ http://www.redis.cn/ https://github.com/antirez/redis https://github.com/sohutv/cachecloud


源起

優化之路永無止境,在此之前一做過一些架構優化彙總如下: 1,Redis集羣3.0.7升級到3.2.9解決讀從節點KEY過期不刪除問題,集羣有幾千萬KEY原來經覈查3.0.7版本只有主上保存過期時間,所以需要主觸發才能刪除過期的KEY,默認有主動刪除與惰性刪除同時工作,但是KEY比較多,寫的比刪除的KEY,另外讀從的話不能觸發主動刪KEY所以會有KEY沒更新問題,升級3.2.X之後解決。 2,發現持久化操作時容易導致超時,後來從節點的持久化關閉,效果良好;後續計劃持久化非持久化業務分開,過期時間短的與過期時間長的分開。 2,集羣擴容,升級到3.2.9版本後爲了均攤QPS擴容了幾個節點,後續發現有2個節點內核版本比其他的高但是性能反而表現比其他差,後替換了同版本的內核。 3,Bigkeys掃描發現有幾個hashkey元素過大超過幾千萬,單個KEY佔用內存幾個G後聯繫開發解決。 4,建立了CacheCloud監控系統,便於分析觀察問題,另外Zabbix也使用Redis模版出現大故障時會報錯。 5,後續優化方向轉爲客戶端使用規劃的問題,主要是解決各個量大的命令平均用時超過10微秒的問題。 6,每個Redis集羣版本升級在功能與性能上都有比較大的提升,需要持久化功能的集羣后續可以使用4.0.2版本,另外如果使用虛擬化不建議使用XEN、Hyper-V等,最好使用vSphere壓力測試vSphere在各方面表現良好。


一,發現問題

1,慢查詢

slowlog get n 默認保留128個日誌執行超過10毫秒的記錄,可以根據實際情況修改

2,應用報錯

主要是應用郵件報超時


二,分析問題

1,內在原因

1)API或數據結構使用不合理 2)CPU飽和的問題 3)持久化相關的阻塞

2,外在原因

1)CPU競爭 2)內存交換 3)網絡問題


三,解決問題之內在原因

1,API或數據結構使用不合理

1)發現慢查詢 slowlog get n 慢查詢日誌有兩個參數: slowlog-log-slower-than: 單位微妙,指定redis執行命令的最大時間,超過將記錄到慢查詢日誌中, 不接受負值,如果設置爲0每條命令都要記錄到慢查詢日誌中,默認10微妙。 slowlog-max-len: 設置慢查詢日誌長度,如果慢查詢日誌已經到最大值,如果有新命令需要記錄,就將最老那條記錄刪除,默認保存128,可以在線修改,CONFIG REWRITE保存。 redis-cli 127.0.0.1:6379> config get slowlog-max-len

  1. "slowlog-max-len"
  2. "128" 127.0.0.1:6379> config set slowlog-max-len 1000 OK 127.0.0.1:6379> config rewrite OK

2)發現大key redis-cli --bigkeys

2,CPU飽和

1)統計Redis狀態 500QPS左右,單個命令使用時間越少支持的QPS併發越大,比如平均1毫妙的支持1000QPS,平均100微妙的支持10000QPS。 redis-cli --stat ------- data ------ --------------------- load -------------------- - child - keys mem clients blocked requests connections 5088981 6.51G 514 0 578132987 (+0) 384742 5088997 6.51G 514 0 578133573 (+586) 384742 5089018 6.51G 514 0 578134096 (+523) 384742 5089005 6.51G 515 0 578134720 (+624) 384743 5089048 6.51G 515 0 578135195 (+475) 384743 5089093 6.51G 513 0 578135829 (+634) 384743 5089117 6.51G 513 0 578136455 (+626) 384743 5089081 6.51G 512 0 578136850 (+395) 384743 5089121 6.51G 512 0 578137226 (+376) 384743

2)命令統計 時間單位爲微秒 單個命令10微妙以內,儘量避免高算法複雜的命令 setex平均26 del 平均43 hmset平均229 hmget平均12 以上特別是hmset要優化,另外hgetall命令不建議使用

redis-cli info commandstats

Commandstats

cmdstat_get:calls=2814596805,usec=12130889716,usec_per_call=4.31 cmdstat_set:calls=25674338,usec=234328226,usec_per_call=9.13 cmdstat_setex:calls=910333006,usec=20767349072,usec_per_call=22.81 cmdstat_del:calls=780287520,usec=33983500560,usec_per_call=43.55 cmdstat_lpush:calls=1,usec=34,usec_per_call=34.00 cmdstat_hset:calls=145663119,usec=499130659,usec_per_call=3.43 cmdstat_hget:calls=2841141555,usec=13763160250,usec_per_call=4.84 cmdstat_hmset:calls=1452658,usec=333516295,usec_per_call=229.59 cmdstat_hmget:calls=970024532,usec=11909915205,usec_per_call=12.28 cmdstat_hdel:calls=581004,usec=3925702,usec_per_call=6.76 cmdstat_hgetall:calls=28985688,usec=555451600,usec_per_call=19.16 cmdstat_hexists:calls=262547,usec=2867627,usec_per_call=10.92 cmdstat_select:calls=1,usec=1,usec_per_call=1.00 cmdstat_expire:calls=72409493,usec=101731304,usec_per_call=1.40 cmdstat_auth:calls=1544789,usec=2890530,usec_per_call=1.87 cmdstat_ping:calls=4977672,usec=2672430,usec_per_call=0.54 cmdstat_echo:calls=697770,usec=380462,usec_per_call=0.55 cmdstat_info:calls=32700948,usec=7243085428,usec_per_call=221.49 cmdstat_config:calls=2176619,usec=31168795,usec_per_call=14.32 cmdstat_subscribe:calls=1717,usec=7283,usec_per_call=4.24 cmdstat_unsubscribe:calls=5506966,usec=21985846,usec_per_call=3.99 cmdstat_cluster:calls=696482,usec=210160284,usec_per_call=301.75 cmdstat_readonly:calls=696449,usec=437883,usec_per_call=0.63 cmdstat_client:calls=697770,usec=1869891,usec_per_call=2.68 cmdstat_slowlog:calls=2,usec=214,usec_per_call=107.00 cmdstat_command:calls=2,usec=11824,usec_per_call=5912.00

3)持久化阻塞 由於從已經關閉持久化,主要分析主的,主上只開啓了RDB且10分鐘一次,沒有開啓AOF刷盤阻塞(故不用考慮) fork阻塞:latest_fork_usec該指標不能超過1秒,這裏是275毫秒 redis-cli info stats

Stats

total_connections_received:384861 total_commands_processed:578276973 instantaneous_ops_per_sec:509 total_net_input_bytes:530863235402 total_net_output_bytes:1584445816901 instantaneous_input_kbps:668.38 instantaneous_output_kbps:838.84 rejected_connections:0 sync_full:1 sync_partial_ok:0 sync_partial_err:0 expired_keys:164683638 evicted_keys:0 keyspace_hits:193101765 keyspace_misses:12414607 pubsub_channels:0 pubsub_patterns:0 latest_fork_usec:275078 275毫秒 migrate_cached_sockets:0

另外HugePage寫操作阻塞,這個內核已經關閉HugePages,方法如下 echo never > /sys/kernel/mm/transparent_hugepage/enabled


四,解決問題之外在原因

1,CPU競爭

Redis是典型的CPU密集型應用,同一臺服務器不建議部署其他服務,如果需要不是多個Redis實例也建議綁定CPU。

2,內存交換

1)根據進程號cat /proc/5413/smaps |grep Swap可以查看內存交換,爲了避免內存交換,首先服務器最好富餘1/3-1/2內存,fork時會生成一個進程佔用當前實例大小的內存,等於說內存加倍。

2)設置最大可用內存及觸發內存啓動lru算法(Redis版本越高該算法效率越高,因爲Redis一直在進化)以防萬一,方法如下: 127.0.0.1:6379> CONFIG GET maxmemory

  1. "maxmemory"
  2. "21474836480" 127.0.0.1:6379> CONFIG GET maxmemory-policy
  3. "maxmemory-policy"
  4. "allkeys-lru"

3)可以降低系統使用swap的優先級,由於前面對內存做了優化這裏沒有對swap調優,畢竟這些都是不得已手段,需要從架構與使用上修改效果纔好。

3,網絡問題

1)連接拒絕 主要是網絡閃斷接Redis連接數超過默認的10000,可以通過監控與修改默認值規避。目前連接不多,如果連接過多服務端的timeout可以修改一個具體的值,默認是0代表永遠不主動斷開連接。 另外連接溢出,這個服務端與客戶端都需要排查,主要是看進程限制與backlog隊列是否溢出。 2)網絡延遲 3)網卡軟中斷

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章