教程:一塊兒學習Hystrix--Hystrix請求處理

目錄

  • Hystrix本系列博文
  • 請求緩存
  • 請求合併
  • 請求上下文設置
  • 聲明

Hystrix本系列博文

    如下爲博主寫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

因爲依賴請求上下文,因此必須初始化 HystrixRequestContextide

在一個簡單單元測試中使用,以下:函數

@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

相關文章
相關標籤/搜索