spring-cloud中zuul的兩種隔離機制實驗

ZuulException REJECTED_SEMAPHORE_EXECUTION 是一個最近在性能測試中常常遇到的異常。查詢資料發現是由於zuul默認每一個路由直接用信號量作隔離,而且默認值是100,也就是當一個路由請求的信號量高於100那麼就拒絕服務了,返回500。spring

信號量隔離

既然默認值過小,那麼就在gateway的配置提升各個路由的信號量再實驗。docker

routes:
    linkflow:
      path: /api1/**
      serviceId: lf
      stripPrefix: false
      semaphore:
        maxSemaphores: 2000
    oauth:
      path: /api2/**
      serviceId: lf
      stripPrefix: false
      semaphore:
        maxSemaphores: 1000

兩個路由的信號量分開提升到2000和1000。咱們再用gatling測試一下。數據庫

setUp(scn.inject(rampUsers(200) over (3 seconds)).protocols(httpConf))

這是咱們的模型,3s內啓動200個用戶,順序訪問5個API。因此會有1000個request。機器配置只有2核16G,而且是docker化的數據庫。因此總體性能不高。api

信號量統計

看結果仍然有57個KO,可是比以前1000個Request有900個KO的比例好不少了。性能

線程隔離

Edgware版本的spring cloud提供了另外一種基於線程池的隔離機制。實現起來也很是簡單,測試

zuul:
  ribbon-isolation-strategy: THREAD
  thread-pool:
    use-separate-thread-pools: true
    thread-pool-key-prefix: zuulgw
    
hystrix:
  threadpool:
    default:
      coreSize: 50
      maximumSize: 10000
      allowMaximumSizeToDivergeFromCoreSize: true
      maxQueueSize: -1
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 60000

use-separate-thread-pools的意思是每一個路由都有本身的線程池,而不是共享一個。
thread-pool-key-prefix會指定一個線程池前綴方便調試。
hystrix的部分主要設置線程池的大小,這裏設置了10000,其實並非越大越好。線程池越大削峯填谷的效果越顯著,也就是時間換空間。系統的總體負載會上升,致使響應時間愈來愈長,那麼當響應時間超過某個限度,其實系統也算是不可用了。後面能夠看到數據。spa

線程池統計

此次沒有500的狀況了,1000個Request都正常返回了。線程

比較

從幾張圖對比下兩種隔離的效果,上圖是信號量隔離,下圖是線程隔離。3d

響應時間分佈

信號量隔離響應時間分佈

線程隔離響應時間分佈

直觀上能發現使用線程隔離的分佈更好看一些,600ms內的響應會更多一些。調試

QPS

信號量隔離QPS

線程隔離QPS

兩張圖展現的是同一時刻的Request和Response的數量。

先看信號量隔離的場景,Response per second是逐步提高的,可是達到一個量級後,gateway開始拒絕服務。猜想是超過了信號量的限制或是超時?

線程隔離的這張就比較有意思了,能夠看到Request per second上升的速度要比上面的快,說明系統是試圖接收更多的請求而後分發給線程池。再看在某個時間點Response per second反而開始降低,由於線程不斷的建立消耗了大量的系統資源,響應變慢。以後由於請求少了,負載下降,Response又開始擡升。因此線程池也並不是越大越好,須要不斷調試尋找一個平衡點。

小結

線程池提供了比信號量更好的隔離機制,而且從實際測試發現高吞吐場景下能夠完成更多的請求。可是信號量隔離的開銷更小,對於自己就是10ms之內的系統,顯然信號量更合適。

相關文章
相關標籤/搜索