add hystrix demo back, and improve the usage to follow the layers
This commit is contained in:
+1
-1
@@ -22,7 +22,7 @@ import org.springside.modules.utils.Threads;
|
||||
public class DependencyResourceController {
|
||||
public static final int TIMEOUT = 15000;
|
||||
|
||||
private String status = "normal";
|
||||
public static String status = "normal";
|
||||
|
||||
@Autowired
|
||||
private AccountEffectiveService accountService;
|
||||
|
||||
+1
-3
@@ -16,11 +16,9 @@ public class GetUserCommand extends HystrixCommand<UserDTO> {
|
||||
private Long id;
|
||||
|
||||
protected GetUserCommand(Setter config, RestTemplate restTemplate, Long id) {
|
||||
// 配置Command
|
||||
super(config);
|
||||
// 传入
|
||||
|
||||
this.restTemplate = restTemplate;
|
||||
// 传入请求参数
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
|
||||
+29
-23
@@ -5,6 +5,7 @@ import javax.annotation.PostConstruct;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.client.SimpleClientHttpRequestFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springside.examples.showcase.webservice.rest.UserDTO;
|
||||
|
||||
@@ -15,17 +16,24 @@ import com.netflix.hystrix.HystrixCommandProperties;
|
||||
import com.netflix.hystrix.HystrixCommandProperties.ExecutionIsolationStrategy;
|
||||
import com.netflix.hystrix.HystrixThreadPoolProperties;
|
||||
|
||||
/**
|
||||
* 使用Hystrix 封装的Service。原来直接调用restTemplate改为调用Hystrix Command的封装.
|
||||
*
|
||||
* @author calvin
|
||||
*/
|
||||
@Service
|
||||
public class UserService {
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(UserService.class);
|
||||
|
||||
private Boolean runInNewThread = true;
|
||||
private Setter config;
|
||||
private RestTemplate restTemplate = new RestTemplate();
|
||||
private boolean runInNewThread = true;
|
||||
|
||||
private Setter commandConfig;
|
||||
private RestTemplate restTemplate;
|
||||
|
||||
public UserDTO getUser(Long id) throws Exception {
|
||||
|
||||
GetUserCommand command = new GetUserCommand(config, restTemplate, id);
|
||||
GetUserCommand command = new GetUserCommand(commandConfig, restTemplate, id);
|
||||
|
||||
try {
|
||||
return command.execute();
|
||||
@@ -36,7 +44,7 @@ public class UserService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 演示Command的各种配置项,构造RestTemplate.
|
||||
* 演示Command的各种配置项, 并构造Thread-Safed的RestTemplate.
|
||||
*/
|
||||
@PostConstruct
|
||||
private void init() {
|
||||
@@ -44,41 +52,39 @@ public class UserService {
|
||||
restTemplate = new RestTemplate();
|
||||
|
||||
// 设置Command名称 //
|
||||
config = Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("ExampleGroup")).andCommandKey(
|
||||
commandConfig = Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("ExampleGroup")).andCommandKey(
|
||||
HystrixCommandKey.Factory.asKey("GetUserCommand"));
|
||||
|
||||
HystrixCommandProperties.Setter commandProperties = HystrixCommandProperties.Setter();
|
||||
commandConfig.andCommandPropertiesDefaults(commandProperties);
|
||||
|
||||
// 设置短路计算规则 //
|
||||
config.andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
|
||||
commandProperties
|
||||
// 多少百分比的失败在rolling windows内发生,计算为短路。默认为50%,无改变。
|
||||
.withCircuitBreakerErrorThresholdPercentage(50)
|
||||
// 至少多少请求在rolling window内发生,才开始触发短路的计算,默认为20, 设为3方便演示。
|
||||
.withCircuitBreakerRequestVolumeThreshold(3)
|
||||
// rolling windows 长度,默认为20秒,改为60秒方便演示。同时相应改变桶的数量。
|
||||
.withMetricsRollingStatisticalWindowInMilliseconds(60000)
|
||||
.withMetricsRollingStatisticalWindowBuckets(60));
|
||||
// rolling windows 长度,默认为20秒,改为180秒方便演示。同时相应改变桶的数量。
|
||||
.withMetricsRollingStatisticalWindowInMilliseconds(180000)
|
||||
.withMetricsRollingStatisticalWindowBuckets(180);
|
||||
|
||||
// 设置短路后的保护时间 //
|
||||
config.andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
|
||||
.withCircuitBreakerSleepWindowInMilliseconds(20000));
|
||||
// 设置短路后的保护时间 ,默认为5秒,改为20秒方便演示//
|
||||
commandProperties.withCircuitBreakerSleepWindowInMilliseconds(20000);
|
||||
|
||||
// 设置超时与并发控制 //
|
||||
if (runInNewThread) {
|
||||
// 使用Hystrix线程池的异步执行方式
|
||||
config.andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
|
||||
// 线程超时,默认为1秒,设为2秒方便演示
|
||||
.withExecutionIsolationThreadTimeoutInMilliseconds(2000))
|
||||
commandProperties.withExecutionIsolationThreadTimeoutInMilliseconds(2000);
|
||||
// 线程池属性, 线程池大小,默认为10,无改变。待执行队列的大小,默认为5,无改变。
|
||||
.andThreadPoolPropertiesDefaults(
|
||||
HystrixThreadPoolProperties.Setter().withCoreSize(10).withQueueSizeRejectionThreshold(5));
|
||||
commandConfig.andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter().withCoreSize(10)
|
||||
.withQueueSizeRejectionThreshold(5));
|
||||
} else {
|
||||
// 使用Invoker原有线程的方式, 设置使用信号量模式而不是默认的线程池模式,设置并发,默认为10,无改变
|
||||
config.andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
|
||||
.withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE)
|
||||
.withExecutionIsolationSemaphoreMaxConcurrentRequests(10));
|
||||
|
||||
// RestTemplate设置为10秒超时
|
||||
((SimpleClientHttpRequestFactory) restTemplate.getRequestFactory()).setConnectTimeout(10000);
|
||||
|
||||
// 设置使用信号量模式而不是默认的线程池模式,设置并发,默认为10,无改变
|
||||
commandProperties.withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE)
|
||||
.withExecutionIsolationSemaphoreMaxConcurrentRequests(10);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package org.springside.examples.showcase.demos.hystrix.web;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springside.examples.showcase.demos.hystrix.service.UserService;
|
||||
import org.springside.examples.showcase.webservice.rest.RestException;
|
||||
import org.springside.examples.showcase.webservice.rest.UserDTO;
|
||||
|
||||
@Controller
|
||||
public class HystrixDemoController {
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(HystrixDemoController.class);
|
||||
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
|
||||
@RequestMapping(value = "/hystrix/user/{id}", method = RequestMethod.GET)
|
||||
@ResponseBody
|
||||
public UserDTO getUser(@PathVariable("id") Long id) {
|
||||
|
||||
try {
|
||||
return userService.getUser(id);
|
||||
} catch (Exception e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
throw new RestException(HttpStatus.SERVICE_UNAVAILABLE);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -11,6 +11,7 @@
|
||||
<div class="submenu">
|
||||
<a id="web-tab" href="${ctx}/story/web">Web演示</a>
|
||||
<a id="webservice-tab"href="${ctx}/story/webservice">WebService演示</a>
|
||||
<a id="hystrix-tab" href="${ctx}/story/hystrix">JMX演示</a>
|
||||
<a id="jmx-tab" href="${ctx}/story/jmx">JMX演示</a>
|
||||
<a id="log-tab" href="${ctx}/story/log">日志高级演示</a>
|
||||
<a id="monitor-tab" href="${ctx}/story/monitor">性能监控演示</a>
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
<%@ page contentType="text/html;charset=UTF-8" %>
|
||||
<%@ page import="org.springside.examples.showcase.demos.hystrix.dependency.DependencyResourceController,com.netflix.hystrix.*,com.netflix.hystrix.HystrixCommandMetrics.HealthCounts,com.netflix.hystrix.util.*" %>
|
||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %><%! %>
|
||||
|
||||
<c:set var="ctx" value="${pageContext.request.contextPath}"/>
|
||||
<html>
|
||||
<head>
|
||||
<title>Web Service高级演示</title>
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$("#hystrix-tab").addClass("active");
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Hystrix 演示</h1>
|
||||
|
||||
<p><a href="https://github.com/Netflix/Hystrix" target="_blank">Netflix Hystrix</a> 是一个延迟与容错类库,通过独立访问远程系统、服务和第三方库的节点,在复杂的分布式系统里停止雪崩及提供恢复能力。</p>
|
||||
|
||||
<h2>演示操作</h2>
|
||||
<ul>
|
||||
<li>依赖资源当前状态为<%= DependencyResourceController.status %>:切换为<a href="${ctx}/hystrix/resource/status/normal">正常</a>、<a href="${ctx}/hystrix/resource/status/timeout">超时</a>、<a href="${ctx}/hystrix/resource/status/fail">失败</a>。</li>
|
||||
<li>访问服务:<a href="${ctx}/hystrix/user/1" target="_blank">Hystrix服务</a>、<a href="${ctx}/hystrix/resource/1" target="_blank">依赖资源</a></li>
|
||||
</ul>
|
||||
<h2>主要用户故事</h2>
|
||||
<ul>
|
||||
<li> 在默认的正常状态,访问Hystrix服务和依赖资源,均返回正常结果。</li>
|
||||
<li> 将资源状态切换为"超时",访问依赖资源,需要在15秒后才返回结果。</li>
|
||||
<li> 访问Hystrix服务,2秒后超时,返回503。</li>
|
||||
<li> 三次超时后满足短路条件(60秒滚动窗口内起码有3个请求,50%失败),再次刷新服务,立即返回503。</li>
|
||||
<li> 10秒短路保护期内,所有访问都立即返回503,不会访问依赖资源。</li>
|
||||
<li> 保护期过后,会放行一个请求,如果还是超时,则继续保持短路状态。如果成功则重置所有计数器。</li>
|
||||
</ul>
|
||||
|
||||
<h2>其他用户故事</h2>
|
||||
<ul>
|
||||
<li> 将资源状态切换为"失败",访问依赖资源,立即返回500错误,访问Hystrix服务,即时返回503错误。</li>
|
||||
<li> 默认使用Hystrix线程池模式,可修改代码使用调用线程池模式。</li>
|
||||
</ul>
|
||||
|
||||
<h2>监控结果 </h2>
|
||||
<form><input type="submit" value="刷新"/></form>
|
||||
<%
|
||||
HystrixCommandKey key = HystrixCommandKey.Factory.asKey("GetUserCommand");
|
||||
HystrixCommandMetrics metrics = HystrixCommandMetrics.getInstance(key);
|
||||
if (metrics!=null){
|
||||
HealthCounts counts = metrics.getHealthCounts();
|
||||
HystrixCircuitBreaker circuitBreaker = HystrixCircuitBreaker.Factory.getInstance(key);
|
||||
|
||||
|
||||
%>
|
||||
<ul>
|
||||
<li>是否短路:<%= circuitBreaker.isOpen() %></li>
|
||||
<li>3分钟窗口内,请求:<%= counts.getTotalRequests()%>, 成功:<%= metrics.getRollingCount(HystrixRollingNumberEvent.SUCCESS) %>, 超时:<%= metrics.getRollingCount(HystrixRollingNumberEvent.TIMEOUT) %>,失败:<%= metrics.getRollingCount(HystrixRollingNumberEvent.FAILURE) %>,短路:<%= metrics.getRollingCount(HystrixRollingNumberEvent.SHORT_CIRCUITED) %>, 失败百分比:<%= counts.getErrorPercentage() %>%
|
||||
<li>50%延时:<%= metrics.getTotalTimePercentile(50) +"ms"%>,90%延时:<%= metrics.getTotalTimePercentile(90) +"ms"%>,100%延时:<%= metrics.getTotalTimePercentile(100) +"ms"%></li>
|
||||
</ul>
|
||||
<%} %>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user