在Hystrix配置中咱們簡單的瞭解了Hystrix經常使用的一些配置,這一篇咱們簡單的經過一些實例來加深對這些配置的理解。html
而且經過ab作一點簡單的併發測試,來看一下Hystrix對系統在流量比較高的時候的影響。java
import java.util.concurrent.TimeUnit; public class ServiceMockUtil { public static String mock() { double random = Math.random(); System.out.println(random); if(Double.compare(0.2,random) >= 0) { try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { return "interrupted"; } return "5"; }else if(Double.compare(0.2,random) < 0 && Double.compare(0.8,random)>0){ try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { return "interrupted"; } return "1"; } return "im"; } public static String mockSixtyFiveSecond() { double random = Math.random(); System.out.println(random); if(Double.compare(0.5,random) >= 0) { try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { return "interrupted"; } return "5"; } return "im"; } }
先來一個模擬的服務的類,用來模擬服務的調用時間,經過隨機的方式讓休眠一些時間。web
import cn.freemethod.service.ServiceMockUtil; import com.netflix.hystrix.*; public class LoginHystrixCommand extends HystrixCommand<String>{ private static Setter getSetter() { return Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("groupOne")) .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey(Thread.currentThread().getId() + "login")) .andCommandPropertiesDefaults( HystrixCommandProperties.Setter() .withCircuitBreakerRequestVolumeThreshold(1) .withCircuitBreakerSleepWindowInMilliseconds(30000) .withCircuitBreakerErrorThresholdPercentage(1) // .withCircuitBreakerForceOpen(true) // .withCircuitBreakerForceClosed(true) .withExecutionTimeoutEnabled(true) .withExecutionTimeoutInMilliseconds(3000)) .andThreadPoolPropertiesDefaults( HystrixThreadPoolProperties.Setter() .withCoreSize(10)); } public LoginHystrixCommand() { super(getSetter()); } @Override protected String run() throws Exception { // return ServiceMockUtil.mock(); return ServiceMockUtil.mockSixtyFiveSecond(); } @Override protected String getFallback() { return "hys failure"; } }
上面就模擬了一個登陸的服務繼承了HystrixCommand類。最好每個方法都是一個Command,把業務封裝在run中。spring
在構造函數中須要一個Setter來配置Hystrix,能夠調整這些參數來改變Command的行爲。express
上面咱們爲了方便都是經過字面量的方式寫在了程序之中。最經常使用的一些配置都包含在上面了,能夠根據本身的理解,測試一下是否正確。spring-mvc
爲了方便咱們作一下簡單的測試,這裏咱們來一個Controller類:併發
import cn.freemethod.hys.LoginHystrixCommand; import cn.freemethod.service.ServiceMockUtil; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; @Controller public class HystrixController { @RequestMapping("/normal") @ResponseBody public String normal(){ // return ServiceMockUtil.mock(); return ServiceMockUtil.mockSixtyFiveSecond(); } @RequestMapping("/hys") @ResponseBody public String hys(){ LoginHystrixCommand command = new LoginHystrixCommand(); return command.execute(); } @RequestMapping("/gologin") public String goLogin(){ return "dologin"; } }
其餘配置文件稍後附錄,這裏先看使用ab簡單的模擬測試一下:mvc
ab的參數-n表示請求的總數量,-c表示併發數量,因此上面模擬的是10000次請求,併發爲200,咱們能夠從執行時間,平均請求執行時間,失敗數量等來對比使用Hystrix和沒有Hystrix的區別。app
從上面咱們能夠看到使用Hystrix的失敗的請求數很高,那是由於咱們的熔斷時間窗口設置的是30秒,整個10000請求執行的時間才16秒不到。dom
因此咱們能夠調整一下下面的三個參數:
HystrixCommandProperties.Setter() .withCircuitBreakerRequestVolumeThreshold(10) .withCircuitBreakerSleepWindowInMilliseconds(1000) .withCircuitBreakerErrorThresholdPercentage(30)
上面的調整,表示併發數要達到10纔有可能觸發熔斷,熔斷時間1秒,而後從新接受部分流量開始統計,而且要錯誤率要達到30%之上纔會觸發熔斷。
咱們來看一下調整以後的測試結果:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="cn.freemethod"> <context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation" /> </context:component-scan> </beans>
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <mvc:annotation-driven /> <context:component-scan base-package="cn.freemethod.controller"> <context:include-filter expression="org.springframework.stereotype.Controller" type="annotation" /> </context:component-scan> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/> <property name="contentType" value="text/html; charset=utf-8"/> <property name="prefix" value="/WEB-INF/view/"/> <property name="suffix" value=".jsp" /> </bean> </beans>
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <context-param> <param-name>webAppRootKey</param-name> <param-value>root</param-value> </context-param> <!-- Sping配置文件 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-application.xml</param-value> </context-param> <!-- Spring 容器啓動監聽器 --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- 字符集 過濾器 --> <filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- Spring view分發器 --> <servlet> <servlet-name>dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>WEB-INF/dispatcher-servlet.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcher</servlet-name> <!--<url-pattern>*.html</url-pattern>--> <url-pattern>*.do</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>
其餘jsp文件隨便建立一個就能夠了。