這段時間接了個需求,須要在我目前負責的數據系統上加個接口,主要是實現用戶行爲的記錄。前端對接的項目主要有公司的PC,WAP,WEIXIN,APP等,每一個端大概有兩臺左右的負載。由於目前個人這個項目主要是面向內部,負責數據運營相關的內容,是個單體項目。若是線上各個接入點不作限制,瞬間大量的併發進入必然會致使目前項目的崩潰,其餘的功能也沒法正常使用。前端
經過前期的需求分析,目前線上系統沒法進行限流處理,因此最終解決問題仍是要從接口入手。java
目前我對接口的處理有兩種實現方案:git
其實我認爲最好的實現方案就是第一種了,能夠保證消息的準確送達,避免併發資源的佔用。不過,由於公司條件的限制暫時不能新增中間件,因此只能在現有系統上進行改造,最後只能採用第二種方法了。github
官方的定義就不說了,這裏簡單說下個人理解。Hystrix做爲斷路器主要是實現對服務的容錯保護,簡單來講就是服務隔離、服務降級、服務熔斷,服務限流這幾項。web
舉個常見的例子,當你某寶【搶購】一個產品時,常常會彈出[網絡錯誤,請重試。]的提示,這種時候是真的網絡問題嗎?顯示不是。這種狀況下實際上是對調用的接口進行了降級處理,當降級的次數或比例達到必定的條件後,斷路器就會直接打開,以後的訪問就會直接降級,而不會判斷是否降級了。達到對服務的容錯保護以及給用戶友好提示的目的。詳細的流程能夠看下圖。apache
通常Hystrix的容錯保護在微服務中是用在客戶端,也就是調用方。而我此次其實是用在了提供方,主要是前臺的項目我沒法控制,只能在接口上想方法了。目前我使用Hystrix的主要目的就是實現對服務的隔離和限流,而對降級和熔斷反而不是特別的關心,固然實際的使用要結合場景。json
由於通常Tomcat默認是一個線程池150個線程,若是單個熱點接口的請求過多,就會形成其餘功能沒有線程可用甚至直接程序崩潰的問題。Hystrix的服務隔離主要有兩種,經常使用的就是線程池隔離的方式,對熱點接口創建單獨的線程池避免對主程序的影響。另外一種是信號量的方式,用的場景不是太多。二者的區別其實就是一個增大系統的開銷,一個則直接限制了線程總的併發數,開銷更小一些。服務器
Hystrix服務調用邏輯圖網絡
本文是在傳統Spring項目中的應用,Springboot中的相關配置和依賴有稍許的不一樣。併發
maven依賴:
<!-- hystrix --> <dependency> <groupId>com.netflix.hystrix</groupId> <artifactId>hystrix-core</artifactId> <version>1.5.9</version> </dependency> <dependency> <groupId>com.netflix.hystrix</groupId> <artifactId>hystrix-metrics-event-stream</artifactId> <version>1.5.9</version> </dependency> <dependency> <groupId>com.netflix.hystrix</groupId> <artifactId>hystrix-javanica</artifactId> <version>1.5.9</version> </dependency>
在Spring的配置文件中配置Hystrix的切面信息
<bean id="hystrixAspect" class="com.netflix.hystrix.contrib.javanica.aop.aspectj.HystrixCommandAspect"></bean> <aop:aspectj-autoproxy />
主要是開啓註解的AOP掃描,這裏咱們能夠在這個類的源碼中看到實現
能夠看到咱們主要是經過這個類切面掃描Hystrix的相關注解,以達到接口處理前,提早執行Hystrix相關邏輯的代碼。
/** * 提供客戶行爲接口 * */ @Controller @RequestMapping(value = "/test") public class BehaviorController { Logger logger = Logger.getLogger(BehaviorController.class); @Autowired private BehaviorService behaviorService; @RequestMapping(value="/addBehavior",method = RequestMethod.POST,produces = "application/json;charset=UTF-8") @ResponseBody @HystrixCommand(fallbackMethod = "fallback", threadPoolProperties = { @HystrixProperty(name = "coreSize", value = "20"), @HystrixProperty(name = "maxQueueSize", value = "100"), @HystrixProperty(name = "queueSizeRejectionThreshold", value = "20")}, commandProperties = { @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "30000"), @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "20") }) public String addBehavior(@RequestBody String parms) { //業務邏輯實現 return result; } public String fallback(@RequestBody String parms){ logger.info("fallback"); //失敗的實現 return result; } }
注意:
請求的接口必須爲public,fallback爲降級的接口邏輯,能夠爲private,也能夠爲public。
可是要特別注意fallback方法的返回值和參數必須和請求方法相同。
另外須要說的是,當請求失敗、被拒絕、超時或者斷路器打開時,都會進入回退方法,可是進入回退方法並不意味着斷路器已經被打開。
參數 |
描述 |
默認值 |
execution.isolation.strategy |
隔離策略,有THREAD和SEMAPHORE THREAD - 它在單獨的線程上執行,併發請求受線程池中的線程數量的限制 |
默認使用THREAD模式,如下幾種場景可使用SEMAPHORE模式: 只想控制併發度 外部的方法已經作了線程隔離 調用的是本地方法或者可靠度很是高、耗時特別小的方法(如medis)
|
execution.isolation.thread.timeoutInMilliseconds |
超時時間 |
默認值:1000 在THREAD模式下,達到超時時間,能夠中斷 在SEMAPHORE模式下,會等待執行完成後,再去判斷是否超時 設置標準: 有retry,99meantime+avg meantime 沒有retry,99.5meantime
|
execution.timeout.enabled |
HystrixCommand.run()執行是否應該有超時。 |
默認值:true |
fallback.isolation.semaphore.maxConcurrentRequests |
設置在使用時容許執行fallback方法的最大併發請求數 |
默認值:10 |
circuitBreaker.requestVolumeThreshold |
設置滾動時間窗中,斷路器熔斷的最小請求數 |
默認值:20 滾動窗口默認10s,即10s內失敗請求達到20個,熔斷器即打開 |
coreSize |
設置執行命令線程池的核心線程數。 |
默認值:10 |
maxQueueSize |
設置執行命令線程池的核心線程數。 |
默認值:-1 當設置爲-1時,線程池使用SynchronousQueue實現的隊列,不然將使用LinkedBlockingQueue實現的隊列 |
queueSizeRejectionThreshold |
爲隊列設置拒絕閾值 |
默認值:5 當設置該參數後,即便隊列沒有達到最大值也能拒絕請求。 注意:當maxQueueSize屬性爲-1的時候,該屬性不會生效 |
另外須要特別注意的是:fallback的屬性maxConcurrentRequests,當請求達到了最大併發數時,後續的請求將會被拒絕並拋出異常(由於它已經沒有後續的fallback能夠被調用了),異常信息通常爲com.netflix.hystrix.exception.HystrixRuntimeException: xxxxxxx fallback execution rejected.
更多參數見官方文檔:https://github.com/Netflix/Hystrix/wiki/Configuration
另外附一個網友翻譯的文檔:https://blog.csdn.net/tongtong_use/article/details/78611225
併發接口測試的方法不少,能夠寫代碼,也能夠用apache batch以及jmeter等工具。以經常使用的jmeter爲例,測試本接口。
設置環境變量:
JMETER_HOME D:\apache-jmeter-3.0
CLASSPATH %JMETER_HOME%\lib\ext\ApacheJMeter_core.jar;%JMETER_HOME%\lib\jorphan.jar;%JMETER_HOME%\lib/logkit-2.0.jar;
新建線程組:
設置併發參數:
第一個參數爲線程數,第二個參數爲啓動時間,第三個參數爲請求次數。以上述配置爲例即爲1秒內啓動50個線程,每一個線程請求一次。
添加HTTP請求
這裏設置請求的路徑,參數等等。
設置請求頭信息,因人而異
個人設置:Content-Type:application/json
表格查看結果
查看結果:
這個能夠根據機器的性能進行測試,以個人接口爲例,當設置併發數爲100之內時,基本上不會有降級處理,當併發數大於100時,就會有部分請求進入降級接口了。
實際項目中,常常須要對咱們的接口和項目狀況進行監控,Hystrix已經爲咱們考慮到了。Hystrix提供了近乎實時的監控,Hystrix會實時的,累加的記錄全部關於HystrixCommand的執行信息,包括執行了每秒執行了多少請求,多少成功,多少失敗等等,更多指標請查看:https://github.com/Netflix/Hystrix/wiki/Metrics-and-Monitoring
在web.xml中添加下述配置:
<!-- for Hystrix --> <servlet> <display-name>HystrixMetricsStreamServlet</display-name> <servlet-name>HystrixMetricsStreamServlet</servlet-name> <servlet-class>com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsStreamServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>HystrixMetricsStreamServlet</servlet-name> <url-pattern>/hystrix.stream</url-pattern> </servlet-mapping>
啓動應用。訪問http://hostname:port/項目名/hystrix.stream,能夠看到下面信息
這種是最原生的監控使用方式,你們能夠另外集成Hystrix 提供的一個 Dashboard 應用。Dashboard 是一個單獨的應用,咱們能夠獨立部署。若是須要監控整個 Hystrix 集羣,就須要使用 Turbine 應用。Turbine 也是 Netflix 開源的一個服務。可是使用 Hystrix Stream 和 Turbine 存在一個明顯的不足,那就是沒法查看歷史的監控數據。解決這個問題就須要咱們本身來實現了。
監控的相關不是本文的重點,就很少介紹了,你們能夠百度下hystrix在微服務項目中監控的實現,這裏網上文章不少,基本上和傳統項目沒有任何區別了,你們能夠參考實現。