隔離技術線程池(ThreadPool)和信號量(semaphore)


一、首先要明白Semaphore和線程池各自是干什么?

  信號量Semaphore是一個並發工具類,用來控制可同時並發的線程數,其內部維護了一組虛擬許可,通過構造器指定許可的數量,每次線程執行操作時先通過acquire方法獲得許可,執行完畢再通過release方法釋放許可。如果無可用許可,那么acquire方法將一直阻塞,直到其它線程釋放許可。

  線程池用來控制實際工作的線程數量,通過線程復用的方式來減小內存開銷。線程池可同時工作的線程數量是一定的,超過該數量的線程需進入線程隊列等待,直到有可用的工作線程來執行任務。

  使用Seamphore,你創建了多少線程,實際就會有多少線程進行執行,只是可同時執行的線程數量會受到限制。但使用線程池,你創建的線程只是作為任務提交給線程池執行,實際工作的線程由線程池創建,並且實際工作的線程數量由線程池自己管理。

  簡單來說,線程池實際工作的線程是work線程,不是你自己創建的,是由線程池創建的,並由線程池自動控制實際並發的work線程數量。而Seamphore相當於一個信號燈,作用是對線程做限流,Seamphore可以對你自己創建的的線程做限流(也可以對線程池的work線程做限流),Seamphore的限流必須通過手動acquire和release來實現。

  區別就是兩點:

1、實際工作的線程是誰創建的?

使用線程池,實際工作線程由線程池創建;使用Seamphore,實際工作的線程由你自己創建。

2、限流是否自動實現?

線程池自動,Seamphore手動。

 

二 Hystrix中的實現

先給個總結對比:

隔離方式 是否支持超時 是否支持熔斷 隔離原理 是否是異步調用 資源消耗
線程池隔離 支持,可直接返回 支持,當線程池到達maxSize后,再請求會觸發fallback接口進行熔斷 每個服務單獨用線程池 可以是異步,也可以是同步。看調用的方法 大,大量線程的上下文切換,容易造成機器負載高
信號量隔離 不支持,如果阻塞,只能通過調用協議(如:socket超時才能返回) 支持,當信號量達到maxConcurrentRequests后。再請求會觸發fallback 通過信號量的計數器 同步調用,不支持異步

 

小,只是個計數器

  信號量模式

  在該模式下,接收請求和執行下游依賴在同一個線程內完成,不存在線程上下文切換所帶來的性能開銷,所以大部分場景應該選擇信號量模式,但是在下面這種情況下,信號量模式並非是一個好的選擇。

  比如一個接口中依賴了3個下游:serviceA、serviceB、serviceC,且這3個服務返回的數據互相不依賴,這種情況下如果針對A、B、C的熔斷降級使用信號量模式,那么接口耗時就等於請求A、B、C服務耗時的總和,無疑這不是好的方案。

  另外,為了限制對下游依賴的並發調用量,可以配置Hystrix的execution.isolation.semaphore.maxConcurrentRequests,當並發請求數達到閾值時,請求線程可以快速失敗,執行降級

  實現也很簡單,一個簡單的計數器,當請求進入熔斷器時,執行tryAcquire(),計數器加1,結果大於閾值的話,就返回false,發生信號量拒絕事件,執行降級邏輯。當請求離開熔斷器時,執行release(),計數器減1。

  線程池模式

  在該模式下,用戶請求會被提交到各自的線程池中執行,把執行每個下游服務的線程分離,從而達到資源隔離的作用。當線程池來不及處理並且請求隊列塞滿時,新進來的請求將快速失敗,可以避免依賴問題擴散。

  在信號量模式提到的問題,對所依賴的多個下游服務,通過線程池的異步執行,可以有效的提高接口性能。

優勢

  • 減少所依賴服務發生故障時的影響面,比如ServiceA服務發生異常,導致請求大量超時,對應的線程池被打滿,這時並不影響ServiceB、ServiceC的調用。
  • 如果接口性能有變動,可以方便的動態調整線程池的參數或者是超時時間,前提是Hystrix參數實現了動態調整。

缺點

  • 請求在線程池中執行,肯定會帶來任務調度、排隊和上下文切換帶來的開銷。
  • 因為涉及到跨線程,那么就存在ThreadLocal數據的傳遞問題,比如在主線程初始化的ThreadLocal變量,在線程池線程中無法獲取

 

三 Zuul中的實現

  Zuul默認是使用信號量隔離,並且信號量的大小是100,請求的並發線程超過100就會報錯

  可以調大該信號量的最大值來提高性能,配置如下:

zuul:
  semaphore:
    max-semaphores: 5000

  也可以改為使用線程隔離,調大hystrix線程池線程大小,該線程池默認10個線程,配置如下:

zuul:
  ribbonIsolationStrategy: THREAD

hystrix:
  threadpool:
    default:
      coreSize: 100
      maximumSize: 400
      allowMaximumSizeToDivergeFromCoreSize: true
      maxQueueSize: -1
maximumSize:最大線程數量

allowMaximumSizeToDivergeFromCoreSize:是否讓maximumSize生效,false的話則只有coreSize會生效
maxQueueSize:線程池的隊列大小,-1代表使用SynchronousQueue隊列

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM