源起

優化之路永無止境,在此之前一做過一些架構優化匯總如下: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,慢查詢 Java自學網推薦-javazx.com

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-cli127.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 1000OK127.0.0.1:6379> config rewriteOK

2)發現大keyredis-cli --bigkeys

2,CPU飽和

1)統計Redis狀態500QPS左右,單個命令使用時間越少支持的QPS並發越大,比如平均1毫妙的支持1000QPS,平均100微妙的支持10000QPS。redis-cli --stat------- data ------ --------------------- load -------------------- - child -keys mem clients blocked requests connections5088981 6.51G 514 0 578132987 (+0) 3847425088997 6.51G 514 0 578133573 (+586) 3847425089018 6.51G 514 0 578134096 (+523) 3847425089005 6.51G 515 0 578134720 (+624) 3847435089048 6.51G 515 0 578135195 (+475) 3847435089093 6.51G 513 0 578135829 (+634) 3847435089117 6.51G 513 0 578136455 (+626) 3847435089081 6.51G 512 0 578136850 (+395) 3847435089121 6.51G 512 0 578137226 (+376) 384743

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

redis-cli info commandstats

Commandstats

cmdstat_get:calls=2814596805,usec=12130889716,usec_per_call=4.31cmdstat_set:calls=25674338,usec=234328226,usec_per_call=9.13cmdstat_setex:calls=910333006,usec=20767349072,usec_per_call=22.81cmdstat_del:calls=780287520,usec=33983500560,usec_per_call=43.55cmdstat_lpush:calls=1,usec=34,usec_per_call=34.00cmdstat_hset:calls=145663119,usec=499130659,usec_per_call=3.43cmdstat_hget:calls=2841141555,usec=13763160250,usec_per_call=4.84cmdstat_hmset:calls=1452658,usec=333516295,usec_per_call=229.59cmdstat_hmget:calls=970024532,usec=11909915205,usec_per_call=12.28cmdstat_hdel:calls=581004,usec=3925702,usec_per_call=6.76cmdstat_hgetall:calls=28985688,usec=555451600,usec_per_call=19.16cmdstat_hexists:calls=262547,usec=2867627,usec_per_call=10.92cmdstat_select:calls=1,usec=1,usec_per_call=1.00cmdstat_expire:calls=72409493,usec=101731304,usec_per_call=1.40cmdstat_auth:calls=1544789,usec=2890530,usec_per_call=1.87cmdstat_ping:calls=4977672,usec=2672430,usec_per_call=0.54cmdstat_echo:calls=697770,usec=380462,usec_per_call=0.55cmdstat_info:calls=32700948,usec=7243085428,usec_per_call=221.49cmdstat_config:calls=2176619,usec=31168795,usec_per_call=14.32cmdstat_subscribe:calls=1717,usec=7283,usec_per_call=4.24cmdstat_unsubscribe:calls=5506966,usec=21985846,usec_per_call=3.99cmdstat_cluster:calls=696482,usec=210160284,usec_per_call=301.75cmdstat_readonly:calls=696449,usec=437883,usec_per_call=0.63cmdstat_client:calls=697770,usec=1869891,usec_per_call=2.68cmdstat_slowlog:calls=2,usec=214,usec_per_call=107.00cmdstat_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:384861total_commands_processed:578276973instantaneous_ops_per_sec:509total_net_input_bytes:530863235402total_net_output_bytes:1584445816901instantaneous_input_kbps:668.38instantaneous_output_kbps:838.84rejected_connections:0sync_full:1sync_partial_ok:0sync_partial_err:0expired_keys:164683638evicted_keys:0keyspace_hits:193101765keyspace_misses:12414607pubsub_channels:0pubsub_patterns:0latest_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)網卡軟中斷


推薦閱讀:
相關文章