記錄一次高併發引發的生產事故的溯源記錄

一次高併發搶購活動引發的生產事故的過程分析記錄

1.在日誌中觀察到的不少dubbo超時報錯

Caused by: com.alibaba.dubbo.remoting.TimeoutException: Waiting server-side response timeout.

排查過程:數據庫sql負載偏高,有接口直接查sql沒有加緩存的,數據庫瓶頸沒辦法,一個sql延遲幾十毫秒,併發上來以後,就會把總體日後拖了node

緣由分析:redis

1.執行sql沒有超時時間,慢就慢了,可是rpc接口和對外接口是有timeout的,單個dubbo服務是的線程池數量是有上限的,spring

2.每一個rpc接口調用1個sql,一個sql延遲100ms,就算一個rpc調用100ms,好比這個進程給的線程數是100,那麼一秒鐘1000ms/200ms * 100 = 500次,也就是這個rpc接口的性能是500次/秒,剛好可以沒有線程阻塞等待處理完畢,當501併發時第501個就會阻塞100ms才能進到rpc中執行代碼處理,最後由於sql的超時致使了調用dubbo provider進程阻塞,繼而致使rpc外層調用的consumer超時,接口返回異常。sql

將sql所有優化以後,發如今高併發的時候日誌中仍是有超時的報錯,看問題仍是同樣的,最後排查發現是由於A服務對外提供了一個按id查惟一信息的rpc接口,B服務中有邏輯爲了獲取多個id的信息,循環進行屢次rpc調用。因此若是B服務獲取的id信息越多對應的rpc循環調用的次數也就越多,從而B的這個業務操做會更加耗時,最後致使超時問題的出現。數據庫

最後把這裏優化掉,改爲一次rpc調用從A服務中批量拿到所有的數據後再在B服務這裏分組依次獲取。 緩存

2.修復上面的問題後發現又出現了dubbo線程池滿了的報錯

\[DUBBO\] Thread pool is EXHAUSTED! Thread Name: DubboServerHandler-ip:70882, Pool Size: 400 (active: 400, core: 400, max: 400, largest: 400), Task: 8640430 (completed: 8640030), Executor status:(isShutdown:false, isTerminated:false, isTerminating:false), in dubbo://ip:70882!, dubbo version: 2.6.2, current host: ip

dubbo線程池滿了,咱們經過從新設置線程池大小dubbo.provider.threads = 1000網絡

3.調大線程池後又出現了另一個問題,Redis鏈接數跑滿了

org.springframework.data.redis.RedisConnectionFailureException: No reachable node in cluster; nested exception is redis.clients.jedis.exceptions.JedisNoReachableClusterNodeException: No reachable node in cluster

redis鏈接數跑滿了,這個問題尋找了很久,最終發現是Jedis的版本問題版本問題,致使連接沒有釋放,鏈接泄露,咱們經過升級jedis版本到2.10.2就解決了這個問題。併發

詳情見這裏https://blog.csdn.net/RL_LEEE/article/details/99831991ide

4.修復了上面的問題後,又出現了redis鏈接池跑滿了問題

org.springframework.dao.InvalidDataAccessApiUsageException: Could not get a resource since the pool is exhausted; nested exception is redis.clients.jedis.exceptions.JedisExhaustedPoolException: Could not get a resource since the pool is exhausted

redis鏈接池數量過小了,咱們經過增大spring.redis.jedis.pool.max-idle = 100,spring.redis.jedis.pool.max-active = 100,這兩個配置從新進行了調整。高併發

5.鏈接池跑滿了的問題解決了,緊接着又出現了熱點Key的分佈不均勻的問題

redis.clients.jedis.exceptions.JedisClusterMaxRedirectionsException: Too many Cluster redirections?

這個是一個熱點大Key的問題,把一個在高峯期會頻繁訪問的對象所有緩存成一個大對象放到redis裏面,最終致使這個對象的大小超過了5MB,由於redis是單線程,每次讀取5MB而後再進行傳輸,會致使網絡io上升,併發數上來後,很容易把熱點Key所在的節點給壓掛。

解決方法就是將整存整取的大對象,分拆爲多個小對象。能夠嘗試將對象分拆成幾個key-value, 使用multiGet獲取值,這樣分拆的意義在於分拆單次操做的壓力,將操做壓力平攤到多個redis實例中,下降對單個redis的IO影響。

6.最終,將上面的問題都解決了以後事故得以最終解決,特此記錄,備忘。

若是對您有幫助,請不要忘了給翎野君點贊。

相關文章
相關標籤/搜索