轉載請註明出處哈:http://hot66hot.iteye.com/admin/blogs/2155036
一:爲何須要Hystrix?
在大中型分佈式系統中,一般系統不少依賴(HTTP,hession,Netty,Dubbo等),以下圖:git

在高併發訪問下,這些依賴的穩定性與否對系統的影響很是大,可是依賴有不少不可控問題:如網絡鏈接緩慢,資源繁忙,暫時不可用,服務脫機等.github
以下圖:QPS爲50的依賴 I 出現不可用,可是其餘依賴仍然可用.redis

當依賴I 阻塞時,大多數服務器的線程池就出現阻塞(BLOCK),影響整個線上服務的穩定性.以下圖:編程

在複雜的分佈式架構的應用程序有不少的依賴,都會不可避免地在某些時候失敗。高併發的依賴失敗時若是沒有隔離措施,當前應用服務就有被拖垮的風險。緩存
- 例如:一個依賴30個SOA服務的系統,每一個服務99.99%可用。
- 99.99%的30次方 ≈ 99.7%
- 0.3% 意味着一億次請求 會有 3,000,00次失敗
- 換算成時間大約每個月有2個小時服務不穩定.
- 隨着服務依賴數量的變多,服務不穩定的機率會成指數性提升.
解決問題方案:對依賴作隔離,Hystrix就是處理依賴隔離的框架,同時也是能夠幫咱們作依賴服務的治理和監控.服務器
Netflix 公司開發併成功使用Hystrix,使用規模以下:網絡
- The Netflix API processes 10+ billion HystrixCommand executions per day using thread isolation.
- Each API instance has 40+ thread-pools with 5-20 threads in each (most are set to 10).
二:Hystrix如何解決依賴隔離
1:Hystrix使用命令模式HystrixCommand(Command)包裝依賴調用邏輯,每一個命令在單獨線程中/信號受權下執行。架構
2:可配置依賴調用超時時間,超時時間通常設爲比99.5%平均時間略高便可.當調用超時時,直接返回或執行fallback邏輯。併發
3:爲每一個依賴提供一個小的線程池(或信號),若是線程池已滿調用將被當即拒絕,默認不採用排隊.加速失敗斷定時間。app
4:依賴調用結果分:成功,失敗(拋出異常),超時,線程拒絕,短路。 請求失敗(異常,拒絕,超時,短路)時執行fallback(降級)邏輯。
5:提供熔斷器組件,能夠自動運行或手動調用,中止當前依賴一段時間(10秒),熔斷器默認錯誤率閾值爲50%,超過將自動運行。
6:提供近實時依賴的統計和監控
Hystrix依賴的隔離架構,以下圖:

三:如何使用Hystrix
1:使用maven引入Hystrix依賴
-
- <hystrix.version>1.3.16</hystrix.version>
- <hystrix-metrics-event-stream.version>1.1.2</hystrix-metrics-event-stream.version>
-
- <dependency>
- <groupId>com.netflix.hystrix</groupId>
- <artifactId>hystrix-core</artifactId>
- <version>${hystrix.version}</version>
- </dependency>
- <dependency>
- <groupId>com.netflix.hystrix</groupId>
- <artifactId>hystrix-metrics-event-stream</artifactId>
- <version>${hystrix-metrics-event-stream.version}</version>
- </dependency>
-
- <repository>
- <id>nexus</id>
- <name>local private nexus</name>
- <url>http://maven.oschina.net/content/groups/public/</url>
- <releases>
- <enabled>true</enabled>
- </releases>
- <snapshots>
- <enabled>false</enabled>
- </snapshots>
- </repository>
2:使用命令模式封裝依賴邏輯
- public class HelloWorldCommand extends HystrixCommand<String> {
- private final String name;
- public HelloWorldCommand(String name) {
-
- super(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"));
- this.name = name;
- }
- @Override
- protected String run() {
-
- return "Hello " + name +" thread:" + Thread.currentThread().getName();
- }
-
- public static void main(String[] args) throws Exception{
-
-
- HelloWorldCommand helloWorldCommand = new HelloWorldCommand("Synchronous-hystrix");
-
- String result = helloWorldCommand.execute();
- System.out.println("result=" + result);
-
- helloWorldCommand = new HelloWorldCommand("Asynchronous-hystrix");
-
- Future<String> future = helloWorldCommand.queue();
-
- result = future.get(100, TimeUnit.MILLISECONDS);
- System.out.println("result=" + result);
- System.out.println("mainThread=" + Thread.currentThread().getName());
- }
-
- }
-
-
-
-
note:異步調用使用 command.queue()get(timeout, TimeUnit.MILLISECONDS);同步調用使用command.execute() 等同於 command.queue().get();
3:註冊異步事件回調執行
-
- Observable<String> fs = new HelloWorldCommand("World").observe();
-
- fs.subscribe(new Action1<String>() {
- @Override
- public void call(String result) {
-
-
- }
- });
-
- fs.subscribe(new Observer<String>() {
- @Override
- public void onCompleted() {
-
- System.out.println("execute onCompleted");
- }
- @Override
- public void onError(Throwable e) {
-
- System.out.println("onError " + e.getMessage());
- e.printStackTrace();
- }
- @Override
- public void onNext(String v) {
-
- System.out.println("onNext: " + v);
- }
- });
-
-
-
-
-
4:使用Fallback() 提供降級策略

-
- public class HelloWorldCommand extends HystrixCommand<String> {
- private final String name;
- public HelloWorldCommand(String name) {
- super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("HelloWorldGroup"))
-
- .andCommandPropertiesDefaults(HystrixCommandProperties.Setter().withExecutionIsolationThreadTimeoutInMilliseconds(500)));
- this.name = name;
- }
- @Override
- protected String getFallback() {
- return "exeucute Falled";
- }
- @Override
- protected String run() throws Exception {
-
- TimeUnit.MILLISECONDS.sleep(1000);
- return "Hello " + name +" thread:" + Thread.currentThread().getName();
- }
- public static void main(String[] args) throws Exception{
- HelloWorldCommand command = new HelloWorldCommand("test-Fallback");
- String result = command.execute();
- }
- }
-
-
-
NOTE: 除了HystrixBadRequestException異常以外,全部從run()方法拋出的異常都算做失敗,並觸發降級getFallback()和斷路器邏輯。
HystrixBadRequestException用在非法參數或非系統故障異常等不該觸發回退邏輯的場景。
5:依賴命名:CommandKey
- public HelloWorldCommand(String name) {
- super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"))
-
- .andCommandKey(HystrixCommandKey.Factory.asKey("HelloWorld")));
- this.name = name;
- }
NOTE: 每一個CommandKey表明一個依賴抽象,相同的依賴要使用相同的CommandKey名稱。依賴隔離的根本就是對相同CommandKey的依賴作隔離.
6:依賴分組:CommandGroup
命令分組用於對依賴操做分組,便於統計,彙總等.
-
- public HelloWorldCommand(String name) {
- Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("HelloWorldGroup"))
- }
NOTE: CommandGroup是每一個命令最少配置的必選參數,在不指定ThreadPoolKey的狀況下,字面值用於對不一樣依賴的線程池/信號區分.
7:線程池/信號:ThreadPoolKey
- public HelloWorldCommand(String name) {
- super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"))
- .andCommandKey(HystrixCommandKey.Factory.asKey("HelloWorld"))
-
- .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("HelloWorldPool")));
- this.name = name;
- }
NOTE: 當對同一業務依賴作隔離時使用CommandGroup作區分,可是對同一依賴的不一樣遠程調用如(一個是redis 一個是http),可使用HystrixThreadPoolKey作隔離區分.
最然在業務上都是相同的組,可是須要在資源上作隔離時,可使用HystrixThreadPoolKey區分.
8:請求緩存 Request-Cache
- public class RequestCacheCommand extends HystrixCommand<String> {
- private final int id;
- public RequestCacheCommand( int id) {
- super(HystrixCommandGroupKey.Factory.asKey("RequestCacheCommand"));
- this.id = id;
- }
- @Override
- protected String run() throws Exception {
- System.out.println(Thread.currentThread().getName() + " execute id=" + id);
- return "executed=" + id;
- }
-
- @Override
- protected String getCacheKey() {
- return String.valueOf(id);
- }
-
- public static void main(String[] args){
- HystrixRequestContext context = HystrixRequestContext.initializeContext();
- try {
- RequestCacheCommand command2a = new RequestCacheCommand(2);
- RequestCacheCommand command2b = new RequestCacheCommand(2);
- Assert.assertTrue(command2a.execute());
-
- Assert.assertFalse(command2a.isResponseFromCache());
- Assert.assertTrue(command2b.execute());
- Assert.assertTrue(command2b.isResponseFromCache());
- } finally {
- context.shutdown();
- }
- context = HystrixRequestContext.initializeContext();
- try {
- RequestCacheCommand command3b = new RequestCacheCommand(2);
- Assert.assertTrue(command3b.execute());
- Assert.assertFalse(command3b.isResponseFromCache());
- } finally {
- context.shutdown();
- }
- }
- }
NOTE:請求緩存可讓(CommandKey/CommandGroup)相同的狀況下,直接共享結果,下降依賴調用次數,在高併發和CacheKey碰撞率高場景下能夠提高性能.
Servlet容器中,能夠直接實用Filter機制Hystrix請求上下文
- 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();
- }
- }
- }
- <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>
9:信號量隔離:SEMAPHORE
隔離本地代碼或可快速返回遠程調用(如memcached,redis)能夠直接使用信號量隔離,下降線程隔離開銷.
- public class HelloWorldCommand extends HystrixCommand<String> {
- private final String name;
- public HelloWorldCommand(String name) {
- super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("HelloWorldGroup"))
-
- .andCommandPropertiesDefaults(HystrixCommandProperties.Setter().withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE)));
- this.name = name;
- }
- @Override
- protected String run() throws Exception {
- return "HystrixThread:" + Thread.currentThread().getName();
- }
- public static void main(String[] args) throws Exception{
- HelloWorldCommand command = new HelloWorldCommand("semaphore");
- String result = command.execute();
- System.out.println(result);
- System.out.println("MainThread:" + Thread.currentThread().getName());
- }
- }
-
-
-
-
10:fallback降級邏輯命令嵌套

適用場景:用於fallback邏輯涉及網絡訪問的狀況,如緩存訪問。
- public class CommandWithFallbackViaNetwork extends HystrixCommand<String> {
- private final int id;
-
- protected CommandWithFallbackViaNetwork(int id) {
- super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("RemoteServiceX"))
- .andCommandKey(HystrixCommandKey.Factory.asKey("GetValueCommand")));
- this.id = id;
- }
-
- @Override
- protected String run() {
-
- throw new RuntimeException("force failure for example");
- }
-
- @Override
- protected String getFallback() {
- return new FallbackViaNetwork(id).execute();
- }
-
- private static class FallbackViaNetwork extends HystrixCommand<String> {
- private final int id;
- public FallbackViaNetwork(int id) {
- super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("RemoteServiceX"))
- .andCommandKey(HystrixCommandKey.Factory.asKey("GetValueFallbackCommand"))
-
- .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("RemoteServiceXFallback")));
- this.id = id;
- }
- @Override
- protected String run() {
- MemCacheClient.getValue(id);
- }
-
- @Override
- protected String getFallback() {
- return null;
- }
- }
- }
NOTE:依賴調用和降級調用使用不一樣的線程池作隔離,防止上層線程池跑滿,影響二級降級邏輯調用.
11:顯示調用fallback邏輯,用於特殊業務處理

- public class CommandFacadeWithPrimarySecondary extends HystrixCommand<String> {
- private final static DynamicBooleanProperty usePrimary = DynamicPropertyFactory.getInstance().getBooleanProperty("primarySecondary.usePrimary", true);
- private final int id;
- public CommandFacadeWithPrimarySecondary(int id) {
- super(Setter
- .withGroupKey(HystrixCommandGroupKey.Factory.asKey("SystemX"))
- .andCommandKey(HystrixCommandKey.Factory.asKey("PrimarySecondaryCommand"))
- .andCommandPropertiesDefaults(
- HystrixCommandProperties.Setter()
- .withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE)));
- this.id = id;
- }
- @Override
- protected String run() {
- if (usePrimary.get()) {
- return new PrimaryCommand(id).execute();
- } else {
- return new SecondaryCommand(id).execute();
- }
- }
- @Override
- protected String getFallback() {
- return "static-fallback-" + id;
- }
- @Override
- protected String getCacheKey() {
- return String.valueOf(id);
- }
- private static class PrimaryCommand extends HystrixCommand<String> {
- private final int id;
- private PrimaryCommand(int id) {
- super(Setter
- .withGroupKey(HystrixCommandGroupKey.Factory.asKey("SystemX"))
- .andCommandKey(HystrixCommandKey.Factory.asKey("PrimaryCommand"))
- .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("PrimaryCommand"))
- .andCommandPropertiesDefaults(
-
- HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds(600)));
- this.id = id;
- }
- @Override
- protected String run() {
-
- return "responseFromPrimary-" + id;
- }
- }
- private static class SecondaryCommand extends HystrixCommand<String> {
- private final int id;
- private SecondaryCommand(int id) {
- super(Setter
- .withGroupKey(HystrixCommandGroupKey.Factory.asKey("SystemX"))
- .andCommandKey(HystrixCommandKey.Factory.asKey("SecondaryCommand"))
- .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("SecondaryCommand"))
- .andCommandPropertiesDefaults(
-
- HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds(100)));
- this.id = id;
- }
- @Override
- protected String run() {
-
- return "responseFromSecondary-" + id;
- }
- }
- public static class UnitTest {
- @Test
- public void testPrimary() {
- HystrixRequestContext context = HystrixRequestContext.initializeContext();
- try {
- ConfigurationManager.getConfigInstance().setProperty("primarySecondary.usePrimary", true);
- assertEquals("responseFromPrimary-20", new CommandFacadeWithPrimarySecondary(20).execute());
- } finally {
- context.shutdown();
- ConfigurationManager.getConfigInstance().clear();
- }
- }
- @Test
- public void testSecondary() {
- HystrixRequestContext context = HystrixRequestContext.initializeContext();
- try {
- ConfigurationManager.getConfigInstance().setProperty("primarySecondary.usePrimary", false);
- assertEquals("responseFromSecondary-20", new CommandFacadeWithPrimarySecondary(20).execute());
- } finally {
- context.shutdown();
- ConfigurationManager.getConfigInstance().clear();
- }
- }
- }
- }
NOTE:顯示調用降級適用於特殊需求的場景,fallback用於業務處理,fallback再也不承擔降級職責,建議慎重使用,會形成監控統計換亂等問題.
12:命令調用合併:HystrixCollapser
命令調用合併容許多個請求合併到一個線程/信號下批量執行。
執行流程圖以下:

- public class CommandCollapserGetValueForKey extends HystrixCollapser<List<String>, String, Integer> {
- private final Integer key;
- public CommandCollapserGetValueForKey(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("ValueForKey: " + request.getArgument());
- }
- return response;
- }
- }
- public static class UnitTest {
- HystrixRequestContext context = HystrixRequestContext.initializeContext();
- try {
- Future<String> f1 = new CommandCollapserGetValueForKey(1).queue();
- Future<String> f2 = new CommandCollapserGetValueForKey(2).queue();
- Future<String> f3 = new CommandCollapserGetValueForKey(3).queue();
- Future<String> f4 = new CommandCollapserGetValueForKey(4).queue();
- assertEquals("ValueForKey: 1", f1.get());
- assertEquals("ValueForKey: 2", f2.get());
- assertEquals("ValueForKey: 3", f3.get());
- assertEquals("ValueForKey: 4", f4.get());
- assertEquals(1, HystrixRequestLog.getCurrentRequest().getExecutedCommands().size());
- HystrixCommand<?> command = HystrixRequestLog.getCurrentRequest().getExecutedCommands().toArray(new HystrixCommand<?>[1])[0];
- assertEquals("GetValueForKey", command.getCommandKey().name());
- assertTrue(command.getExecutionEvents().contains(HystrixEventType.COLLAPSED));
- assertTrue(command.getExecutionEvents().contains(HystrixEventType.SUCCESS));
- } finally {
- context.shutdown();
- }
- }
- }
NOTE:使用場景:HystrixCollapser用於對多個相同業務的請求合併到一個線程甚至能夠合併到一個鏈接中執行,下降線程交互次和IO數,但必須保證他們屬於同一依賴.
四:監控平臺搭建Hystrix-dashboard
1:監控dashboard介紹
dashboard面板能夠對依賴關鍵指標提供實時監控,以下圖:

2:實例暴露command統計數據
Hystrix使用Servlet對當前JVM下全部command調用狀況做數據流輸出
配置以下:
- <servlet>
- <display-name>HystrixMetricsStreamServlet</display-name>
- <servlet-name>HystrixMetricsStreamServlet</servlet-name>
- <servlet-class>com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsStreamServlet</servlet-class>
- </servlet>
- <servlet-mapping>
- <servlet-name>HystrixMetricsStreamServlet</servlet-name>
- <url-pattern>/hystrix.stream</url-pattern>
- </servlet-mapping>
-
-
-
3:集羣模式監控統計搭建
1)使用Turbine組件作集羣數據彙總
結構圖以下;

2)內嵌jetty提供Servlet容器,暴露HystrixMetrics
- public class JettyServer {
- private final Logger logger = LoggerFactory.getLogger(this.getClass());
- private int port;
- private ExecutorService executorService = Executors.newFixedThreadPool(1);
- private Server server = null;
- public void init() {
- try {
- executorService.execute(new Runnable() {
- @Override
- public void run() {
- try {
-
- server = new Server(8080);
- WebAppContext context = new WebAppContext();
- context.setContextPath("/");
- context.addServlet(HystrixMetricsStreamServlet.class, "/hystrix.stream");
- context.setResourceBase(".");
- server.setHandler(context);
- server.start();
- server.join();
- } catch (Exception e) {
- logger.error(e.getMessage(), e);
- }
- }
- });
- } catch (Exception e) {
- logger.error(e.getMessage(), e);
- }
- }
- public void destory() {
- if (server != null) {
- try {
- server.stop();
- server.destroy();
- logger.warn("jettyServer stop and destroy!");
- } catch (Exception e) {
- logger.error(e.getMessage(), e);
- }
- }
- }
- }
3)Turbine搭建和配置
a:配置Turbine Servlet收集器
- <servlet>
- <description></description>
- <display-name>TurbineStreamServlet</display-name>
- <servlet-name>TurbineStreamServlet</servlet-name>
- <servlet-class>com.netflix.turbine.streaming.servlet.TurbineStreamServlet</servlet-class>
- </servlet>
- <servlet-mapping>
- <servlet-name>TurbineStreamServlet</servlet-name>
- <url-pattern>/turbine.stream</url-pattern>
- </servlet-mapping>
b:編寫config.properties配置集羣實例
- #配置兩個集羣:mobil-online,ugc-online
- turbine.aggregator.clusterConfig=mobil-online,ugc-online
- #配置mobil-online集羣實例
- turbine.ConfigPropertyBasedDiscovery.mobil-online.instances=10.10.*.*,10.10.*.*,10.10.*.*,10.10.*.*,10.10.*.*,10.10.*.*,10.16.*.*,10.16.*.*,10.16.*.*,10.16.*.*
- #配置mobil-online數據流servlet
- turbine.instanceUrlSuffix.mobil-online=:8080/hystrix.stream
- #配置ugc-online集羣實例
- turbine.ConfigPropertyBasedDiscovery.ugc-online.instances=10.10.*.*,10.10.*.*,10.10.*.*,10.10.*.*#配置ugc-online數據流servlet
- turbine.instanceUrlSuffix.ugc-online=:8080/hystrix.stream
c:使用Dashboard配置鏈接Turbine
以下圖 :

五:Hystrix配置與分析
1:Hystrix 配置
1):Command 配置
Command配置源碼在HystrixCommandProperties,構造Command時經過Setter進行配置
具體配置解釋和默認值以下
-
- private final HystrixProperty<ExecutionIsolationStrategy> executionIsolationStrategy;
-
- private final HystrixProperty<Integer> executionIsolationThreadTimeoutInMilliseconds;
-
- private final HystrixProperty<String> executionIsolationThreadPoolKeyOverride;
-
- private final HystrixProperty<Integer> executionIsolationSemaphoreMaxConcurrentRequests;
-
- private final HystrixProperty<Integer> fallbackIsolationSemaphoreMaxConcurrentRequests;
-
- private final HystrixProperty<Boolean> fallbackEnabled;
-
- private final HystrixProperty<Boolean> executionIsolationThreadInterruptOnTimeout;
-
- private final HystrixProperty<Integer> metricsRollingStatisticalWindowInMilliseconds;
-
- private final HystrixProperty<Integer> metricsRollingStatisticalWindowBuckets;
-
- private final HystrixProperty<Boolean> metricsRollingPercentileEnabled;
-
- private final HystrixProperty<Boolean> requestLogEnabled;
-
- private final HystrixProperty<Boolean> requestCacheEnabled;
2):熔斷器(Circuit Breaker)配置
Circuit Breaker配置源碼在HystrixCommandProperties,構造Command時經過Setter進行配置,每種依賴使用一個Circuit Breaker
-
- private final HystrixProperty<Integer> circuitBreakerRequestVolumeThreshold;
-
- private final HystrixProperty<Integer> circuitBreakerSleepWindowInMilliseconds;
-
- private final HystrixProperty<Boolean> circuitBreakerEnabled;
-
- private final HystrixProperty<Integer> circuitBreakerErrorThresholdPercentage;
-
- private final HystrixProperty<Boolean> circuitBreakerForceOpen;
-
- private final HystrixProperty<Boolean> circuitBreakerForceClosed;
3):命令合併(Collapser)配置
Command配置源碼在HystrixCollapserProperties,構造Collapser時經過Setter進行配置
-
- private final HystrixProperty<Integer> maxRequestsInBatch;
-
- private final HystrixProperty<Integer> timerDelayInMilliseconds;
-
- private final HystrixProperty<Boolean> requestCacheEnabled;
4):線程池(ThreadPool)配置
-
-
-
-
- HystrixThreadPoolProperties.Setter().withCoreSize(int value)
-
-
-
-
-
- HystrixThreadPoolProperties.Setter().withMaxQueueSize(int value)
2:Hystrix關鍵組件分析
1):Hystrix流程結構解析

流程說明:
1:每次調用建立一個新的HystrixCommand,把依賴調用封裝在run()方法中.
2:執行execute()/queue作同步或異步調用.
3:判斷熔斷器(circuit-breaker)是否打開,若是打開跳到步驟8,進行降級策略,若是關閉進入步驟.
4:判斷線程池/隊列/信號量是否跑滿,若是跑滿進入降級步驟8,不然繼續後續步驟.
5:調用HystrixCommand的run方法.運行依賴邏輯
5a:依賴邏輯調用超時,進入步驟8.
6:判斷邏輯是否調用成功
6a:返回成功調用結果
6b:調用出錯,進入步驟8.
7:計算熔斷器狀態,全部的運行狀態(成功, 失敗, 拒絕,超時)上報給熔斷器,用於統計從而判斷熔斷器狀態.
8:getFallback()降級邏輯.
如下四種狀況將觸發getFallback調用:
(1):run()方法拋出非HystrixBadRequestException異常。
(2):run()方法調用超時
(3):熔斷器開啓攔截調用
(4):線程池/隊列/信號量是否跑滿
8a:沒有實現getFallback的Command將直接拋出異常
8b:fallback降級邏輯調用成功直接返回
8c:降級邏輯調用失敗拋出異常
9:返回執行成功結果
2):熔斷器:Circuit Breaker
Circuit Breaker 流程架構和統計

每一個熔斷器默認維護10個bucket,每秒一個bucket,每一個blucket記錄成功,失敗,超時,拒絕的狀態,
默認錯誤超過50%且10秒內超過20個請求進行中斷攔截.
3)隔離(Isolation)分析
Hystrix隔離方式採用線程/信號的方式,經過隔離限制依賴的併發量和阻塞擴散.
(1):線程隔離
把執行依賴代碼的線程與請求線程(如:jetty線程)分離,請求線程能夠自由控制離開的時間(異步過程)。
經過線程池大小能夠控制併發量,當線程池飽和時能夠提早拒絕服務,防止依賴問題擴散。
線上建議線程池不要設置過大,不然大量堵塞線程有可能會拖慢服務器。

(2):線程隔離的優缺點
線程隔離的優勢:
[1]:使用線程能夠徹底隔離第三方代碼,請求線程能夠快速放回。
[2]:當一個失敗的依賴再次變成可用時,線程池將清理,並當即恢復可用,而不是一個長時間的恢復。
[3]:能夠徹底模擬異步調用,方便異步編程。
線程隔離的缺點:
[1]:線程池的主要缺點是它增長了cpu,由於每一個命令的執行涉及到排隊(默認使用SynchronousQueue避免排隊),調度和上下文切換。
[2]:對使用ThreadLocal等依賴線程狀態的代碼增長複雜性,須要手動傳遞和清理線程狀態。
NOTE: Netflix公司內部認爲線程隔離開銷足夠小,不會形成重大的成本或性能的影響。
Netflix 內部API 天天100億的HystrixCommand依賴請求使用線程隔,每一個應用大約40多個線程池,每一個線程池大約5-20個線程。
(3):信號隔離
信號隔離也能夠用於限制併發訪問,防止阻塞擴散, 與線程隔離最大不一樣在於執行依賴代碼的線程依然是請求線程(該線程須要經過信號申請),
若是客戶端是可信的且能夠快速返回,可使用信號隔離替換線程隔離,下降開銷.
信號量的大小能夠動態調整, 線程池大小不能夠.
線程隔離與信號隔離區別以下圖:

解析圖片出自官網wiki , 更多內容請見官網: https://github.com/Netflix/Hystrix