目录
Hystrix本系列博文
请求缓存
请求合并
请求上下文设置
声明
Hystrix本系列博文
以下为博主写Hystrix系列的文章列表
点击查看 Hystrix入门
点击查看 Hystrix命令执行
点击查看 Hystrix处理异常机制(降级方法)
点击查看 Hystrix命令名称、分组、线程池
请求缓存
您可以通过在 HystrixCommand 或 HystrixObservableCommand 上实现 getCacheKey() 方法来启用请求缓存,如下所示:
public class CommandHelloRequestCache extends HystrixCommand {
private final int value;
protected CommandHelloRequestCache(int value) {
super(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"));
this.value = value;
}
@Override
protected Boolean run() {
return value == 0 || value % 2 == 0;
}
@Override
protected String getCacheKey() {
return String.valueOf(value);
}
}
点击查看 完整源码(含单元测试)
在一个简单单元测试中使用,如下:
@Test
public void testWithoutCacheHits() {
HystrixRequestContext context = HystrixRequestContext.initializeContext();
try {
assertTrue(new CommandHelloRequestCache(2).execute());
assertFalse(new CommandHelloRequestCache(1).execute());
assertTrue(new CommandHelloRequestCache(0).execute());
assertTrue(new CommandHelloRequestCache(58672).execute());
} finally {
context.shutdown();
}
}
通常,请求上下文将被初始化,并通过封装用户请求或其他生命周期钩子的ServletFilter关闭。
下面示例,展示了在请求上下文中,命令如何从缓存检索它们的值(以及如何查询一个对象确定它的值是否来自缓存 ):
@Test
public void testWithCacheHits() {
HystrixRequestContext context = HystrixRequestContext.initializeContext();
try {
CommandHelloRequestCache command2a = new CommandHelloRequestCache(2);
CommandHelloRequestCache command2b = new CommandHelloRequestCache(2);
assertTrue(command2a.execute());
// 第一次执行这个命令时不是从缓存返回的值
assertFalse(command2a.isResponseFromCache());
assertTrue(command2b.execute());
// 第二次执行这个命令时是从缓存返回的值
assertTrue(command2b.isResponseFromCache());
} finally {
context.shutdown();
}
// 开启一个新的请求上下文
context = HystrixRequestContext.initializeContext();
try {
CommandHelloRequestCache command3b = new CommandHelloRequestCache(2);
assertTrue(command3b.execute());
// 这个新请求执行这个命令也不会从缓存返回值
assertFalse(command3b.isResponseFromCache());
} finally {
context.shutdown();
}
}
请求合并
请求合并者使多个请求在单个HystrixCommand实例被批量执行。自批处理创建后,合并者可以使用批次大小和运行时间作为执行批次处理的触发器。
Hystrix 支持的请求合并有两种:请求范围和全局范围。这个可以在合并器构造函数中配置,默认情况下是请求范围。
请求范围的合并器收集每个 HystrixRequestContext的批处理,而全局范围的合并器则会在多个 HystrixRequestContext中收集一批批处理。 因此,如果下游依赖项不能在单个命令调用中处理多个 HystrixRequestContext,那么请求作用域合并者做出了恰当的选择。
在Netflix(Hystrix开源者),只使用请求作用域的合并器,因为所有当前的系统都是建立在每个命令使用单个HystrixRequestContext的假设之上。 由于一批次仅为每个请求,在同一请求命令使用不同参数并行执行时,合并是有效的。
下面是一个简单的例子,说明如何实现一个请求范围的 HystrixCollapser:
public class CommandHelloCollapser extends HystrixCollapser, String, Integer> {
private final Integer key;
public CommandHelloCollapser(Integer key) {
this.key = key;
}
@Override
public Integer getRequestArgument() {
return key;
}
@Override
protected HystrixCommand> createCommand(final Collection> requests) {
return new BatchCommand(requests);
}
@Override
protected void mapResponseToRequests(List batchResponse, Collection> requests) {
int count = 0;
for (CollapsedRequest request : requests) {
request.setResponse(batchResponse.get(count++));
}
}
private static final class BatchCommand extends HystrixCommand> {
private final Collection> requests;
private BatchCommand(Collection> requests) {
super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"))
.andCommandKey(HystrixCommandKey.Factory.asKey("GetValueForKey")));
this.requests = requests;
}
@Override
protected List run() {
ArrayList response = new ArrayList();
for (CollapsedRequest request : requests) {
// artificial response for each argument received in the batch
response.add("ValueForKey: " + request.getArgument());
}
return response;
}
}
}
点击查看 完整源码以及单元测试
下面的单元测试展示了如何使用一个合并器自动将 CommandHelloCollapser 的4个执行在一个 HystrixCommand 中执行:
@Test
public void testCollapser() throws Exception {
HystrixRequestContext context = HystrixRequestContext.initializeContext();
try {
Future f1 = new CommandHelloCollapser(1).queue();
Future f2 = new CommandHelloCollapser(2).queue();
Future f3 = new CommandHelloCollapser(3).queue();
Future f4 = new CommandHelloCollapser(4).queue();
assertEquals("ValueForKey: 1", f1.get());
assertEquals("ValueForKey: 2", f2.get());
assertEquals("ValueForKey: 3", f3.get());
assertEquals("ValueForKey: 4", f4.get());
int numExecuted = HystrixRequestLog.getCurrentRequest().getAllExecutedCommands().size();
System.err.println("num executed: " + numExecuted);
// 断言此批次命令"Command Name:Hello Collapser"实际被执行了而却仅仅执行了它
// 一次或两次(由于这个例子使用了真实的定时器,源于调度程序的不确定性)
if (numExecuted > 2) {
fail("some of the commands should have been collapsed");
}
System.err.println("HystrixRequestLog.getCurrentRequest().getAllExecutedCommands(): " + HystrixRequestLog.getCurrentRequest().getAllExecutedCommands());
int numLogs = 0;
for (HystrixInvokableInfo> command : HystrixRequestLog.getCurrentRequest().getAllExecutedCommands()) {
numLogs++;
// 这个命令执行是我们所期望的
assertEquals("Command Name:Hello Collapser", command.getCommandKey().name());
System.err.println(command.getCommandKey().name() + " => command.getExecutionEvents(): " + command.getExecutionEvents());
// 确认是一个合并器的命令执行
assertTrue(command.getExecutionEvents().contains(HystrixEventType.COLLAPSED));
assertTrue(command.getExecutionEvents().contains(HystrixEventType.SUCCESS));
}
assertEquals(numExecuted, numLogs);
} finally {
context.shutdown();
}
}
请求上下文设置
这意味着在一个请求前必须执行如下语句:
HystrixRequestContext context = HystrixRequestContext.initializeContext();
在请求执行后执行以下语句:
context.shutdown();
在一个标准的java web应用中,可以使用 Servlet Filter (过滤器)初始化 HystrixRequestContext 生命周期,实现过滤器实现方式如下:
public class HystrixRequestContextServletFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HystrixRequestContext context = HystrixRequestContext.initializeContext();
try {
chain.doFilter(request, response);
} finally {
context.shutdown();
}
}
}
然后通过在web.xml中添加一段配置来启用所有进来的请求过滤器 ,示例如下:
HystrixRequestContextServletFilter
HystrixRequestContextServletFilter
com.netflix.hystrix.contrib.requestservlet.HystrixRequestContextServletFilter
HystrixRequestContextServletFilter
/*
声明
转帖请注明原贴地址:https://my.oschina.net/u/2342969/blog/1817093