在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文件随便建立一个就能够了。