You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dubbo.apache.org by je...@apache.org on 2018/08/10 08:40:15 UTC

[incubator-dubbo-website] branch asf-site updated: add blog

This is an automated email from the ASF dual-hosted git repository.

jerrick pushed a commit to branch asf-site
in repository https://gitbox.apache.org/repos/asf/incubator-dubbo-website.git


The following commit(s) were added to refs/heads/asf-site by this push:
     new 7e0e10f  add blog
7e0e10f is described below

commit 7e0e10fffb435624bead7df865c8ff5e1eb28483
Author: zhuyong <yo...@alibaba-inc.com>
AuthorDate: Fri Aug 10 16:39:53 2018 +0800

    add blog
---
 blog/zh-cn/dubbo-integrate-with-hystrix.md         | 201 +++++++++++++++++++++
 ...c3831ea1057a5367.js => 4828dc59b19c927e111e.js} |   4 +-
 build/654055e491fb5dea7da2.js                      |   6 +
 build/fca877d6ab8a5dbba7ca.js                      |   6 -
 build/page.js                                      |   2 +-
 md_json/blog.json                                  |   4 +
 site_config/blog.js                                |   7 +
 7 files changed, 221 insertions(+), 9 deletions(-)

diff --git a/blog/zh-cn/dubbo-integrate-with-hystrix.md b/blog/zh-cn/dubbo-integrate-with-hystrix.md
new file mode 100644
index 0000000..34d9a2b
--- /dev/null
+++ b/blog/zh-cn/dubbo-integrate-with-hystrix.md
@@ -0,0 +1,201 @@
+# Spring应用快速集成Dubbo + Hystrix
+
+## 背景
+
+Hystrix 旨在通过控制那些访问远程系统、服务和第三方库的节点,从而对延迟和故障提供更强大的容错能力。Hystrix具备拥有回退机制和断路器功能的线程和信号隔离,请求缓存和请求打包,以及监控和配置等功能。
+
+Dubbo是Alibaba开源的,目前国内最流行的java rpc框架。
+
+本文介绍在spring应用里,怎么把Dubbo和Hystrix结合起来使用。
+
+- <https://github.com/Netflix/Hystrix>
+- <https://github.com/apache/incubator-dubbo>
+
+## Spring Boot应用
+
+Demo地址: <https://github.com/dubbo/dubbo-samples/tree/master/dubbo-samples-spring-boot-hystrix>
+
+### 生成dubbo集成spring boot的应用
+
+对于不熟悉dubbo 集成spring boot应用的同学,可以在这里直接生成dubbo + spring boot的工程: <http://start.dubbo.io/>
+
+### 配置spring-cloud-starter-netflix-hystrix
+
+spring boot官方提供了对hystrix的集成,直接在pom.xml里加入依赖:
+
+```
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
+            <version>1.4.4.RELEASE</version>
+        </dependency>
+```
+
+然后在Application类上增加`@EnableHystrix`来启用hystrix starter:
+
+```
+@SpringBootApplication
+@EnableHystrix
+public class ProviderApplication {
+```
+
+### 配置Provider端
+
+在Dubbo的Provider上增加`@HystrixCommand`配置,这样子调用就会经过Hystrix代理。
+
+```
+@Service(version = "1.0.0")
+public class HelloServiceImpl implements HelloService {
+    @HystrixCommand(commandProperties = {
+                    @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"),
+                    @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "2000") })
+    @Override
+    public String sayHello(String name) {
+        // System.out.println("async provider received: " + name);
+        // return "annotation: hello, " + name;
+        throw new RuntimeException("Exception to show hystrix enabled.");
+    }
+}
+```
+
+### 配置Consumer端
+
+对于Consumer端,则可以增加一层method调用,并在method上配置`@HystrixCommand`。当调用出错时,会走到`fallbackMethod = "reliable"`的调用里。
+
+```
+    @Reference(version = "1.0.0")
+    private HelloService demoService;
+
+    @HystrixCommand(fallbackMethod = "reliable")
+    public String doSayHello(String name) {
+        return demoService.sayHello(name);
+    }
+    public String reliable(String name) {
+        return "hystrix fallback value";
+    }
+```
+
+通过上面的配置,很简单地就完成了Spring Boot里Dubbo + Hystrix的集成。
+
+## 传统Spring Annotation应用
+
+Demo地址: <https://github.com/dubbo/dubbo-samples/tree/master/dubbo-samples-spring-hystrix>
+
+传统spring annotation应用的配置其实也很简单,和spring boot应用不同的是:
+
+1. 显式配置Spring AOP支持:`@EnableAspectJAutoProxy`
+2. 显式通过`@Configuration`配置`HystrixCommandAspect` Bean。
+
+```
+    @Configuration
+    @EnableDubbo(scanBasePackages = "com.alibaba.dubbo.samples.annotation.action")
+    @PropertySource("classpath:/spring/dubbo-consumer.properties")
+    @ComponentScan(value = {"com.alibaba.dubbo.samples.annotation.action"})
+    @EnableAspectJAutoProxy
+    static public class ConsumerConfiguration {
+
+        @Bean
+        public HystrixCommandAspect hystrixCommandAspect() {
+            return new HystrixCommandAspect();
+        }
+    }
+```
+
+## Hystrix集成Spring AOP原理
+
+在上面的例子里可以看到,Hystrix对Spring的集成是通过Spring AOP来实现的。下面简单分析下实现。
+
+```
+@Aspect
+public class HystrixCommandAspect {
+    @Pointcut("@annotation(com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand)")
+    public void hystrixCommandAnnotationPointcut() {
+    }
+    @Pointcut("@annotation(com.netflix.hystrix.contrib.javanica.annotation.HystrixCollapser)")
+    public void hystrixCollapserAnnotationPointcut() {
+    }
+
+    @Around("hystrixCommandAnnotationPointcut() || hystrixCollapserAnnotationPointcut()")
+    public Object methodsAnnotatedWithHystrixCommand(final ProceedingJoinPoint joinPoint) throws Throwable {
+        Method method = getMethodFromTarget(joinPoint);
+        Validate.notNull(method, "failed to get method from joinPoint: %s", joinPoint);
+        if (method.isAnnotationPresent(HystrixCommand.class) && method.isAnnotationPresent(HystrixCollapser.class)) {
+            throw new IllegalStateException("method cannot be annotated with HystrixCommand and HystrixCollapser " +
+                    "annotations at the same time");
+        }
+        MetaHolderFactory metaHolderFactory = META_HOLDER_FACTORY_MAP.get(HystrixPointcutType.of(method));
+        MetaHolder metaHolder = metaHolderFactory.create(joinPoint);
+        HystrixInvokable invokable = HystrixCommandFactory.getInstance().create(metaHolder);
+        ExecutionType executionType = metaHolder.isCollapserAnnotationPresent() ?
+                metaHolder.getCollapserExecutionType() : metaHolder.getExecutionType();
+
+        Object result;
+        try {
+            if (!metaHolder.isObservable()) {
+                result = CommandExecutor.execute(invokable, executionType, metaHolder);
+            } else {
+                result = executeObservable(invokable, executionType, metaHolder);
+            }
+        } catch (HystrixBadRequestException e) {
+            throw e.getCause() != null ? e.getCause() : e;
+        } catch (HystrixRuntimeException e) {
+            throw hystrixRuntimeExceptionToThrowable(metaHolder, e);
+        }
+        return result;
+    }
+```
+
+1. `HystrixCommandAspect`里定义了两个注解的AspectJ Pointcut:`@HystrixCommand`, `@HystrixCollapser`。所有带这两个注解的spring bean都会经过AOP处理
+2. 在`@Around` AOP处理函数里,可以看到Hystrix会创建出`HystrixInvokable`,再通过`CommandExecutor`来执行
+
+## spring-cloud-starter-netflix-hystrix的代码分析
+
+1. `@EnableHystrix` 引入了`@EnableCircuitBreaker`,`@EnableCircuitBreaker`引入了`EnableCircuitBreakerImportSelector`
+
+   ```
+   @EnableCircuitBreaker
+   public @interface EnableHystrix {
+   }
+   
+   @Import(EnableCircuitBreakerImportSelector.class)
+   public @interface EnableCircuitBreaker {
+   }
+   ```
+
+2. `EnableCircuitBreakerImportSelector`继承了`SpringFactoryImportSelector<EnableCircuitBreaker>`,使spring加载`META-INF/spring.factories`里的`EnableCircuitBreaker`声明的配置
+
+   在`META-INF/spring.factories`里可以找到下面的配置,也就是引入了`HystrixCircuitBreakerConfiguration`。
+
+   ```
+   org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker=\
+   org.springframework.cloud.netflix.hystrix.HystrixCircuitBreakerConfiguration
+   ```
+
+3. 在`HystrixCircuitBreakerConfiguration`里可以发现创建了`HystrixCommandAspect`
+
+   ```
+   @Configuration
+   public class HystrixCircuitBreakerConfiguration {
+   
+       @Bean
+       public HystrixCommandAspect hystrixCommandAspect() {
+           return new HystrixCommandAspect();
+       }
+   ```
+
+可见`spring-cloud-starter-netflix-hystrix`实际上也是创建了`HystrixCommandAspect`来集成Hystrix。
+
+另外`spring-cloud-starter-netflix-hystrix`里还有metrics, health, dashboard等集成。
+
+## 总结
+
+- 对于dubbo provider的`@Service`是一个spring bean,直接在上面配置`@HystrixCommand`即可
+- 对于dubbo consumer的`@Reference`,可以通过加一层简单的spring method包装,配置`@HystrixCommand`即可
+- Hystrix本身提供`HystrixCommandAspect`来集成Spring AOP,配置了`@HystrixCommand`和`@HystrixCollapser`的spring method都会被Hystrix处理
+
+## 链接
+
+- <https://github.com/Netflix/Hystrix>
+- <https://github.com/apache/incubator-dubbo>
+- <http://start.dubbo.io/>
+- <https://cloud.spring.io/spring-cloud-netflix/single/spring-cloud-netflix.html#_circuit_breaker_hystrix_clients>
\ No newline at end of file
diff --git a/build/5dfcc3831ea1057a5367.js b/build/4828dc59b19c927e111e.js
similarity index 76%
rename from build/5dfcc3831ea1057a5367.js
rename to build/4828dc59b19c927e111e.js
index b382589..138f84b 100644
--- a/build/5dfcc3831ea1057a5367.js
+++ b/build/4828dc59b19c927e111e.js
@@ -1,6 +1,6 @@
-webpackJsonp([4],[,,,,,,,function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function o(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function i(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+t [...]
+webpackJsonp([4],[,,,,,,,function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function o(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function i(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+t [...]
   Copyright (c) 2017 Jed Watson.
   Licensed under the MIT License (MIT), see
   http://jedwatson.github.io/classnames
 */
-!function(){"use strict";function n(){for(var e=[],t=0;t<arguments.length;t++){var r=arguments[t];if(r){var o=typeof r;if("string"===o||"number"===o)e.push(r);else if(Array.isArray(r)&&r.length){var a=n.apply(null,r);a&&e.push(a)}else if("object"===o)for(var l in r)i.call(r,l)&&r[l]&&e.push(l)}}return e.join(" ")}var i={}.hasOwnProperty;void 0!==e&&e.exports?(n.default=n,e.exports=n):(r=[],void 0!==(o=function(){return n}.apply(t,r))&&(e.exports=o))}()},function(e,t,n){"use strict";funct [...]
\ No newline at end of file
+!function(){"use strict";function n(){for(var e=[],t=0;t<arguments.length;t++){var r=arguments[t];if(r){var o=typeof r;if("string"===o||"number"===o)e.push(r);else if(Array.isArray(r)&&r.length){var a=n.apply(null,r);a&&e.push(a)}else if("object"===o)for(var l in r)i.call(r,l)&&r[l]&&e.push(l)}}return e.join(" ")}var i={}.hasOwnProperty;void 0!==e&&e.exports?(n.default=n,e.exports=n):(r=[],void 0!==(o=function(){return n}.apply(t,r))&&(e.exports=o))}()},function(e,t,n){"use strict";funct [...]
\ No newline at end of file
diff --git a/build/654055e491fb5dea7da2.js b/build/654055e491fb5dea7da2.js
new file mode 100644
index 0000000..25bae80
--- /dev/null
+++ b/build/654055e491fb5dea7da2.js
@@ -0,0 +1,6 @@
+webpackJsonp([1],[,,,,,,,,function(n,s,e){"use strict";function a(n){return n&&n.__esModule?n:{default:n}}function t(n,s){if(!(n instanceof s))throw new TypeError("Cannot call a class as a function")}function o(n,s){if(!n)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!s||"object"!=typeof s&&"function"!=typeof s?n:s}function l(n,s){if("function"!=typeof s&&null!==s)throw new TypeError("Super expression must either be null or a function, not "+ [...]
+  Copyright (c) 2017 Jed Watson.
+  Licensed under the MIT License (MIT), see
+  http://jedwatson.github.io/classnames
+*/
+!function(){"use strict";function e(){for(var n=[],s=0;s<arguments.length;s++){var a=arguments[s];if(a){var t=typeof a;if("string"===t||"number"===t)n.push(a);else if(Array.isArray(a)&&a.length){var l=e.apply(null,a);l&&n.push(l)}else if("object"===t)for(var r in a)o.call(a,r)&&a[r]&&n.push(r)}}return n.join(" ")}var o={}.hasOwnProperty;void 0!==n&&n.exports?(e.default=e,n.exports=e):(a=[],void 0!==(t=function(){return e}.apply(s,a))&&(n.exports=t))}()},function(n,s,e){"use strict";funct [...]
\ No newline at end of file
diff --git a/build/fca877d6ab8a5dbba7ca.js b/build/fca877d6ab8a5dbba7ca.js
deleted file mode 100644
index e3172aa..0000000
--- a/build/fca877d6ab8a5dbba7ca.js
+++ /dev/null
@@ -1,6 +0,0 @@
-webpackJsonp([1],[,,,,,,,,function(n,s,e){"use strict";function a(n){return n&&n.__esModule?n:{default:n}}function t(n,s){if(!(n instanceof s))throw new TypeError("Cannot call a class as a function")}function o(n,s){if(!n)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!s||"object"!=typeof s&&"function"!=typeof s?n:s}function l(n,s){if("function"!=typeof s&&null!==s)throw new TypeError("Super expression must either be null or a function, not "+ [...]
-  Copyright (c) 2017 Jed Watson.
-  Licensed under the MIT License (MIT), see
-  http://jedwatson.github.io/classnames
-*/
-!function(){"use strict";function e(){for(var n=[],s=0;s<arguments.length;s++){var a=arguments[s];if(a){var t=typeof a;if("string"===t||"number"===t)n.push(a);else if(Array.isArray(a)&&a.length){var l=e.apply(null,a);l&&n.push(l)}else if("object"===t)for(var r in a)o.call(a,r)&&a[r]&&n.push(r)}}return n.join(" ")}var o={}.hasOwnProperty;void 0!==n&&n.exports?(e.default=e,n.exports=e):(a=[],void 0!==(t=function(){return e}.apply(s,a))&&(n.exports=t))}()},function(n,s,e){"use strict";funct [...]
\ No newline at end of file
diff --git a/build/page.js b/build/page.js
index 0bb1b81..5d5b97c 100644
--- a/build/page.js
+++ b/build/page.js
@@ -1 +1 @@
-!function(n){function o(t){if(e[t])return e[t].exports;var r=e[t]={i:t,l:!1,exports:{}};return n[t].call(r.exports,r,r.exports,o),r.l=!0,r.exports}var t=window.webpackJsonp;window.webpackJsonp=function(o,e,a){for(var i,d,l=0,c=[];l<o.length;l++)d=o[l],r[d]&&c.push(r[d][0]),r[d]=0;for(i in e)Object.prototype.hasOwnProperty.call(e,i)&&(n[i]=e[i]);for(t&&t(o,e,a);c.length;)c.shift()()};var e={},r={5:0};o.e=function(n){function t(){d.onerror=d.onload=null,clearTimeout(l);var o=r[n];0!==o&&(o [...]
\ No newline at end of file
+!function(n){function o(t){if(e[t])return e[t].exports;var r=e[t]={i:t,l:!1,exports:{}};return n[t].call(r.exports,r,r.exports,o),r.l=!0,r.exports}var t=window.webpackJsonp;window.webpackJsonp=function(o,e,a){for(var i,d,l=0,c=[];l<o.length;l++)d=o[l],r[d]&&c.push(r[d][0]),r[d]=0;for(i in e)Object.prototype.hasOwnProperty.call(e,i)&&(n[i]=e[i]);for(t&&t(o,e,a);c.length;)c.shift()()};var e={},r={5:0};o.e=function(n){function t(){d.onerror=d.onload=null,clearTimeout(l);var o=r[n];0!==o&&(o [...]
\ No newline at end of file
diff --git a/md_json/blog.json b/md_json/blog.json
index 40ba1b7..3808afd 100644
--- a/md_json/blog.json
+++ b/md_json/blog.json
@@ -21,6 +21,10 @@
       "__html": "<h1>Dubbo的泛化调用</h1>\n<p>以下几种场景可以考虑使用泛化调用:</p>\n<ul>\n<li>服务测试平台</li>\n<li>API 服务网关</li>\n</ul>\n<p>泛化调用主要用于消费端没有 API 接口的情况;不需要引入接口 jar 包,而是直接通过 GenericService 接口来发起服务调用,参数及返回值中的所有 POJO 均用 <code>Map</code> 表示。泛化调用对于服务端无需关注,按正常服务进行暴露即可。</p>\n<p>下面来看看消费端如何使用泛化调用进行服务调用。</p>\n<h4>通过 Spring XML 配置进行泛化调用</h4>\n<p>在 Spring 配置申明 <code>generic=&quot;true&quot;</code>,如:</p>\n<pre><code class=\"language-xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">dubbo:reference</s [...]
     },
     {
+      "filename": "dubbo-integrate-with-hystrix.md",
+      "__html": "<h1>Spring应用快速集成Dubbo + Hystrix</h1>\n<h2>背景</h2>\n<p>Hystrix 旨在通过控制那些访问远程系统、服务和第三方库的节点,从而对延迟和故障提供更强大的容错能力。Hystrix具备拥有回退机制和断路器功能的线程和信号隔离,请求缓存和请求打包,以及监控和配置等功能。</p>\n<p>Dubbo是Alibaba开源的,目前国内最流行的java rpc框架。</p>\n<p>本文介绍在spring应用里,怎么把Dubbo和Hystrix结合起来使用。</p>\n<ul>\n<li><a href=\"https://github.com/Netflix/Hystrix\">https://github.com/Netflix/Hystrix</a></li>\n<li><a href=\"https://github.com/apache/incubator-dubbo\">https://github.com/apache/incubator-dubbo</a></li>\n</ul>\n [...]
+    },
+    {
       "filename": "dubbo-invoke.md",
       "__html": "<h1>Dubbo 关于同步/异步调用的几种方式</h1>\n<p>我们知道,Dubbo 缺省协议采用单一长连接,底层实现是 Netty 的 NIO 异步通讯机制;基于这种机制,Dubbo 实现了以下几种调用方式:</p>\n<ul>\n<li>同步调用</li>\n<li>异步调用</li>\n<li>参数回调</li>\n<li>事件通知</li>\n</ul>\n<h3>同步调用</h3>\n<p>同步调用是一种阻塞式的调用方式,即 Consumer 端代码一直阻塞等待,直到 Provider 端返回为止;</p>\n<p>通常,一个典型的同步调用过程如下:</p>\n<ol>\n<li>Consumer 业务线程调用远程接口,向 Provider 发送请求,同时当前线程处于<code>阻塞</code>状态;</li>\n<li>Provider 接到 Consumer 的请求后,开始处理请求,将结果返回给 Consumer;</li>\n<li>Consumer 收到结果后,当前线程继续往后执行。</li>\n</ol>\n< [...]
     },
diff --git a/site_config/blog.js b/site_config/blog.js
index 9ee1931..04e5a97 100644
--- a/site_config/blog.js
+++ b/site_config/blog.js
@@ -80,6 +80,13 @@ export default {
     postsTitle: '所有文章',
     list: [
         {
+            title: 'Spring应用快速集成Dubbo + Hystrix',
+            author: '@hengyunabc',
+            dateStr: 'August 10th, 2018',
+            desc: '本文介绍在spring应用里,怎么把Dubbo和Hystrix结合起来使用',
+            link: '/blog/dubbo-integrate-with-hystrix.md',
+        },
+        {
             title: '如何基于Dubbo实现全异步调用链',
             author: '@chickenlj',
             dateStr: 'August 10th, 2018',