首頁>Club>
11
回覆列表
  • 1 # Java架構達人

    源起

    最佳化之路永無止境,在此之前一做過一些架構最佳化彙總如下: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

    "slowlog-max-len""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

    "maxmemory""21474836480"127.0.0.1:6379> CONFIG GET maxmemory-policy"maxmemory-policy""allkeys-lru"

    3)可以降低系統使用swap的優先順序,由於前面對記憶體做了最佳化這裡沒有對swap調優,畢竟這些都是不得已手段,需要從架構與使用上修改效果才好。

    3,網路問題

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

  • 中秋節和大豐收的關聯?
  • 故宮裡的“水”有多少講究?