如下爲博主寫Hystrix系列的文章列表html
點擊查看 Hystrix入門java
點擊查看 Hystrix命令執行git
點擊查看 Hystrix處理異常機制(降級方法)github
點擊查看 Hystrix命令名稱、分組、線程池web
您能夠經過在 HystrixCommand
或 HystrixObservableCommand
上實現 getCacheKey()
方法來啓用請求緩存,以下所示:緩存
public class CommandHelloRequestCache extends HystrixCommand<Boolean> { 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); } }
點擊查看 完整源碼(含單元測試)app
因爲依賴請求上下文,因此必須初始化 HystrixRequestContext
。ide
在一個簡單單元測試中使用,以下:函數
@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<List<String>, String, Integer> { private final Integer key; public CommandHelloCollapser(Integer key) { this.key = key; } @Override public Integer getRequestArgument() { return key; } @Override protected HystrixCommand<List<String>> createCommand(final Collection<CollapsedRequest<String, Integer>> requests) { return new BatchCommand(requests); } @Override protected void mapResponseToRequests(List<String> batchResponse, Collection<CollapsedRequest<String, Integer>> requests) { int count = 0; for (CollapsedRequest<String, Integer> request : requests) { request.setResponse(batchResponse.get(count++)); } } private static final class BatchCommand extends HystrixCommand<List<String>> { private final Collection<CollapsedRequest<String, Integer>> requests; private BatchCommand(Collection<CollapsedRequest<String, Integer>> requests) { super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("ExampleGroup")) .andCommandKey(HystrixCommandKey.Factory.asKey("GetValueForKey"))); this.requests = requests; } @Override protected List<String> run() { ArrayList<String> response = new ArrayList<String>(); for (CollapsedRequest<String, Integer> 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<String> f1 = new CommandHelloCollapser(1).queue(); Future<String> f2 = new CommandHelloCollapser(2).queue(); Future<String> f3 = new CommandHelloCollapser(3).queue(); Future<String> 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
生命週期(或者實現一個可替代的 HystrixConcurrencyStrategy
)
這意味着在一個請求前必須執行以下語句:
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中添加一段配置來啓用全部進來的請求過濾器 ,示例以下:
<filter> <display-name>HystrixRequestContextServletFilter</display-name> <filter-name>HystrixRequestContextServletFilter</filter-name> <filter-class>com.netflix.hystrix.contrib.requestservlet.HystrixRequestContextServletFilter</filter-class> </filter> <filter-mapping> <filter-name>HystrixRequestContextServletFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
轉帖請註明原貼地址:https://my.oschina.net/u/2342969/blog/1817093