hystrix支持N個請求自動合並為一個請求,這個功能在有網絡交互的場景下尤其有用,比如每個請求都要網絡訪問遠程資源,如果把請求合並為一個,將使多次網絡交互變成一次,極大節省開銷。重要一點,兩個請求能自動合並的前提是兩者足夠“近”,即兩者啟動執行的間隔時長要足夠小,默認為10ms,即超過10ms將不自動合並。
請求合並使多個請求可以批量化成單個HystrixCommand實例執行。
合並器可以使用批量大小和自批次創建以來的經過時間作為執行批處理的觸發器。
Hystrix支持2種請求折疊方式:請求范圍和全局范圍。這是在collapser構造中配置的,默認為請求范圍。
一個請求范圍的collapser收集每個HystrixRequestContext的一個批次,而一個全局范圍的collapser收集一個批次跨多個HystrixRequestContexts。因此,如果您的下游依賴關系在單個命令調用中無法處理多個HystrixRequestContexts,則請求范圍的折疊是正確的選擇。
測試代碼如下:
/**
* hystrix支持N個請求自動合並為一個請求,這個功能在有網絡交互的場景下尤其有用
* 比如每個請求都要網絡訪問遠程資源,如果把請求合並為一個,將使多次網絡交互變成一次,極大節省開銷
* 重要一點,兩個請求能自動合並的前提是兩者足夠“近”,即兩者啟動執行的間隔時長要足夠小,默認為10ms,即超過10ms將不自動合並
* @author liucongcong 2017年10月17日
*
*/
public class HystrixCollapser extends com.netflix.hystrix.HystrixCollapser<List<String>, String, Integer>{
private final Integer key;
public HystrixCollapser(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) {
// 批量收到的每個參數的響應
response.add("collapser: " + request.getArgument());
}
return response;
}
}
}
public class TestCollapser {
@Test
public void testCollapser() throws Exception {
HystrixRequestContext context = HystrixRequestContext.initializeContext();
try {
Future<String> f1 = new HystrixCollapser(1).queue();
//Thread.sleep(100);
Future<String> f2 = new HystrixCollapser(2).queue();
Future<String> f3 = new HystrixCollapser(3).queue();
Future<String> f4 = new HystrixCollapser(4).queue();
assertEquals("collapser: 1", f1.get());
assertEquals("collapser: 2", f2.get());
assertEquals("collapser: 3", f3.get());
assertEquals("collapser: 4", f4.get());
// 當前的請求數 自動合並請求 總共發送一次請求
assertEquals(1, HystrixRequestLog.getCurrentRequest().getExecutedCommands().size());
HystrixCommand<?> command = HystrixRequestLog.getCurrentRequest().getExecutedCommands().toArray(new HystrixCommand<?>[1])[0];
// assert the command is the one we're expecting
assertEquals("GetValueForKey", command.getCommandKey().name());
// confirm that it was a COLLAPSED command execution
assertTrue(command.getExecutionEvents().contains(HystrixEventType.COLLAPSED));
// and that it was successful
assertTrue(command.getExecutionEvents().contains(HystrixEventType.SUCCESS));
} finally {
context.shutdown();
}
}
}
