This is an automated email from the ASF dual-hosted git repository. git-site-role pushed a commit to branch asf-site in repository https://gitbox.apache.org/repos/asf/dubbo-website.git
The following commit(s) were added to refs/heads/asf-site by this push: new c849e88 Website updated with 3078d28eb0e1b6b8f2523cbd90a619062396670c c849e88 is described below commit c849e88e411f2ae271e46fdf6de935a186e31c34 Author: jenkins <us...@infra.apache.org> AuthorDate: Fri Sep 6 09:18:17 2019 +0000 Website updated with 3078d28eb0e1b6b8f2523cbd90a619062396670c --- COMMIT_ID | 2 +- en-us/blog/dubboAsync_client.html | 102 +++++++++++++++++++++++++++++++++++++ en-us/blog/dubboAsync_client.json | 10 ++++ img/blog/dubboasyn_client/1_en.png | Bin 0 -> 17755 bytes md_json/blog.json | 9 ++++ zh-cn/blog/dubboAsync_client.html | 2 +- zh-cn/blog/dubboAsync_client.json | 2 +- 7 files changed, 124 insertions(+), 3 deletions(-) diff --git a/COMMIT_ID b/COMMIT_ID index 6563b9b..66d5d4c 100644 --- a/COMMIT_ID +++ b/COMMIT_ID @@ -1 +1 @@ -54aa1ad736ce575d5ae6cfe37f0b12fee43be1fc +3078d28eb0e1b6b8f2523cbd90a619062396670c diff --git a/en-us/blog/dubboAsync_client.html b/en-us/blog/dubboAsync_client.html new file mode 100644 index 0000000..7ad1786 --- /dev/null +++ b/en-us/blog/dubboAsync_client.html @@ -0,0 +1,102 @@ +<!DOCTYPE html> +<html lang="en"> + +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> + <meta name="keywords" content="Dubbo, Asynchronous, Reactive" /> + <meta name="description" content="Implementation background and practice of Dubbo client asynchronous interface" /> + <!-- 网页标签标题 --> + <title>Implementation background and practice of Dubbo client asynchronous interface</title> + <link rel="shortcut icon" href="/img/dubbo.ico"/> + <link rel="stylesheet" href="/build/blogDetail.css" /> +</head> +<body> + <div id="root"><div class="blog-detail-page" data-reactroot=""><header class="header-container header-container-normal"><div class="header-body"><a href="/en-us/index.html"><img class="logo" src="/img/dubbo_colorful.png"/></a><div class="search search-normal"><span class="icon-search"></span></div><span class="language-switch language-switch-normal">中</span><div class="header-menu"><img class="header-menu-toggle" src="/img/menu_gray.png"/><ul><li class="menu-item menu-item-normal"><a hr [...] +<h2>Preface</h2> +<p><img src="../../img/blog/dubboasyn_client/1_en.png" alt="image | left"></p> +<p>Let's start with a brief introduction about the stages of a complete Dubbo invocation.</p> +<ol> +<li> +<p>Biz~ represents business thread, that is, the thread where the business logic is located. Biz~ thread pool may be created and maintained by business itself, most of which may be managed by system framework itself (for example, a web system runs under Tomcat container, Biz~ thread is maintained by Tomcat); IO~ stands for network data processing thread, which is created and maintained by IO framework (such as Netty, Grizzly). Dubbo Remoting's default Netty implementation is NioEventloop [...] +</li> +<li> +<p>As we all know, the way of data communication between threads is shared variables. The data communication between Biz and IO is Queue. Specifically to Dubbo, Biz put a task in EventLoop's LinkedBlockingQueue in the client side implementation (i.e. the steps labeled in Figure 1 above), and the corresponding Thread in the EventLoop will keep iteration the Queue to keep on executing the information the task contains. Specific code can refer to SingleThreadEventExecutor (by the way, the d [...] +</li> +<li> +<p>As shown in the figure above, a standard RPC call passes through four message (event) transfers of 1,2,3,4, respectively are the client business thread sending requests to the client IO thread, the server business logic thread receiving the server IO thread requests, the server logic thread responding to the server IO thread after processing, and the client IO thread receiving the results feedback to the business logic thread.</p> +</li> +</ol> +<h2>Client Asynchronization</h2> +<h3>Background</h3> +<p>In the Java language (other languages are not clear), a call of the local interface can be transparently converted into the call of remote RPC through the proxy mechanism. Most business parties prefer this programming method similar to the local interface to do remote service invocation. Therefore, although RPC is naturally asynchronous internally, users using Dubbo mostly use synchronization, while asynchrony becomes a minority use scenario. The advantage of synchronization is that t [...] +<p>Therefore, the motivation of client asynchronization is to save thread resource overhead at the cost of understanding how asynchronization is used. In the synchronous mode, the return type of API interface represents a certain business class, while in the asynchronous case, the response and the request are completely independent events, so it is most suitable for the return type of API interface to be CompletionStage mentioned above, which is the inevitable asynchronization supported [...] +<p>The example blow is to illustrate it.</p> +<h3>The sample</h3> +<p>Refer to the example code for event notification: <a href="https://github.com/dubbo/dubbo-samples/tree/master/dubbo-samples-notify">https://github.com/dubbo/dubbo-samples/tree/master/dubbo-samples-notify</a></p> +<p>Event notification allows the Consumer to trigger 'oninvoke', 'onreturn' and 'onthrow' events, which respectively represent before the call, after the call returns normally, or when an exception occurs.</p> +<p>You can specify a method for notifying events when configuring the Consumer, such as:</p> +<pre><code class="language-xml"><span class="hljs-tag"><<span class="hljs-name">bean</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"demoCallback"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"com.alibaba.dubbo.samples.notify.impl.NotifyImpl"</span> /></span> + +<span class="hljs-tag"><<span class="hljs-name">dubbo:reference</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"demoService"</span> <span class="hljs-attr">check</span>=<span class="hljs-string">"false"</span> <span class="hljs-attr">interface</span>=<span class="hljs-string">"com.alibaba.dubbo.samples.notify.api.DemoService"</span> <span class="hljs-attr">version</span>=<span class="hljs-string">"1.0.0"</span> <span class="hljs-attr">group</span>=<span class="hljs [...] + <span class="hljs-tag"><<span class="hljs-name">dubbo:method</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"sayHello"</span> <span class="hljs-attr">onreturn</span>=<span class="hljs-string">"demoCallback.onreturn"</span> <span class="hljs-attr">onthrow</span>=<span class="hljs-string">"demoCallback.onthrow"</span>/></span> +<span class="hljs-tag"></<span class="hljs-name">dubbo:reference</span>></span> +</code></pre> +<p>The code for NotifyImpl is as follows:</p> +<pre><code class="language-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NotifyImpl</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Notify</span></span>{ + + <span class="hljs-keyword">public</span> Map<Integer, String> ret = <span class="hljs-keyword">new</span> HashMap<Integer, String>(); + + <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onreturn</span><span class="hljs-params">(String name, <span class="hljs-keyword">int</span> id)</span> </span>{ + ret.put(id, name); + System.out.println(<span class="hljs-string">"onreturn: "</span> + name); + } + + <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onthrow</span><span class="hljs-params">(Throwable ex, String name, <span class="hljs-keyword">int</span> id)</span> </span>{ + System.out.println(<span class="hljs-string">"onthrow: "</span> + name); + } +} +</code></pre> +<p>It is important to note that the parameters for the three methods in the custom Notify interface are as follows:</p> +<ul> +<li><code>oninvoke</code> The parameters of the method are the same as those of the calling method.</li> +<li><code>onreturn</code> The first parameter of the method is the return value of the calling method, and the rest is the parameters of the calling method.</li> +<li><code>onthrow</code> The first parameter to the method is the call exception, and the rest is the parameter to the calling method.</li> +</ul> +<p>In the above configuration, the <code>sayHello</code> method is called synchronously, so the execution of the event notification method is also synchronously executed. <code>async=true</code> can be configured to make the method call asynchronous, and the notification event method is also executed asynchronously. In particular, the <code>oninvoke</code> method executes synchronously, regardless of whether it is invoked asynchronously or not.</p> +<h3>Practical advice</h3> +<ul> +<li> +<div data-type="alignment" data-value="justify" style="text-align:justify"> +<div data-type="p">Logical Non-Strongly dependent results after RPC invocation: Asynchronous callbacks are suitable for client-side asynchronous invocation when the client <strong>is not strongly dependent on the server response</strong>.</div> +</div> +</li> +<li> +<div data-type="alignment" data-value="justify" style="text-align:justify"> +<div data-type="p">RX scenario: after learning about reactive programming model, I believe that as long as the programming thinking can embrace reactive and the state machine design of business model can be adjusted appropriately, asynchronous solutions can be applied in all scenarios, so as to achieve better terminal response experience. For Dubbo, the current asynchronous interface model needs to be improved like the reactive model interface in order to make the user more naturally app [...] +</div> +</li> +</ul> +<h3>Conclusions</h3> +<ul> +<li>The motivation of client asynchronization is that the request sending and response processing are two different independent events, how the response is handled and in which thread is handled are not required to be coupled with the business logic thread of the request sending event.</li> +<li>The processing logic of response event callbacks in which thread to process is to be selected according to the situation. It is recommended that if the callback logic is relatively simple, it should be directly in the IO thread; if it contains IO type synchronization operations such as remote access or DB access, it is recommended that it be processed in a separate thread pool.</li> +</ul> +</section><footer class="footer-container"><div class="footer-body"><img src="/img/dubbo_gray.png"/><img class="apache" src="/img/apache_logo.png"/><div class="cols-container"><div class="col col-12"><h3></h3><p></p></div><div class="col col-4"><dl><dt>ASF</dt><dd><a href="http://www.apache.org" target="_self">Foundation</a></dd><dd><a href="http://www.apache.org/licenses/" target="_self">License</a></dd><dd><a href="http://www.apache.org/events/current-event" target="_self">Events</a></ [...] + <script src="https://f.alicdn.com/react/15.4.1/react-with-addons.min.js"></script> + <script src="https://f.alicdn.com/react/15.4.1/react-dom.min.js"></script> + <script> + window.rootPath = ''; + </script> + <script src="/build/blogDetail.js"></script> + <!-- Global site tag (gtag.js) - Google Analytics --> + <script async src="https://www.googletagmanager.com/gtag/js?id=UA-112489517-1"></script> + <script> + window.dataLayer = window.dataLayer || []; + function gtag(){dataLayer.push(arguments);} + gtag('js', new Date()); + + gtag('config', 'UA-112489517-1'); + </script> +</body> +</html> \ No newline at end of file diff --git a/en-us/blog/dubboAsync_client.json b/en-us/blog/dubboAsync_client.json new file mode 100644 index 0000000..dcad29e --- /dev/null +++ b/en-us/blog/dubboAsync_client.json @@ -0,0 +1,10 @@ +{ + "filename": "dubboAsync_client.md", + "__html": "<h1>Implementation background and practice of Dubbo client asynchronous interface</h1>\n<h2>Preface</h2>\n<p><img src=\"../../img/blog/dubboasyn_client/1_en.png\" alt=\"image | left\"></p>\n<p>Let's start with a brief introduction about the stages of a complete Dubbo invocation.</p>\n<ol>\n<li>\n<p>Biz~ represents business thread, that is, the thread where the business logic is located. Biz~ thread pool may be created and maintained by business itself, most of which may be m [...] + "link": "/en-us/blog/dubboAsync_client.html", + "meta": { + "title": "Implementation background and practice of Dubbo client asynchronous interface", + "keywords": "Dubbo, Asynchronous, Reactive", + "description": "Implementation background and practice of Dubbo client asynchronous interface" + } +} \ No newline at end of file diff --git a/img/blog/dubboasyn_client/1_en.png b/img/blog/dubboasyn_client/1_en.png new file mode 100644 index 0000000..6e12e51 Binary files /dev/null and b/img/blog/dubboasyn_client/1_en.png differ diff --git a/md_json/blog.json b/md_json/blog.json index 1b92cd4..3fb6727 100644 --- a/md_json/blog.json +++ b/md_json/blog.json @@ -163,6 +163,15 @@ } }, { + "filename": "dubboAsync_client.md", + "link": "/en-us/blog/dubboAsync_client.html", + "meta": { + "title": "Implementation background and practice of Dubbo client asynchronous interface", + "keywords": "Dubbo, Asynchronous, Reactive", + "description": "Implementation background and practice of Dubbo client asynchronous interface" + } + }, + { "filename": "gsoc-2018.md", "link": "/en-us/blog/gsoc-2018.html", "meta": { diff --git a/zh-cn/blog/dubboAsync_client.html b/zh-cn/blog/dubboAsync_client.html index 436abd2..958acfa 100644 --- a/zh-cn/blog/dubboAsync_client.html +++ b/zh-cn/blog/dubboAsync_client.html @@ -29,7 +29,7 @@ </ol> <h2>客户端异步</h2> <h3>实现背景</h3> -<p>在Java语言(其他语言不清楚)下一次本地接口的调用可以透明地通过代理机制转为远程RPC的调用,大多数业务方也比较喜欢这种与本地接口类似的编程方式做远程服务集成,所以虽然RPC内部天然是异步的,但使用Dubbo的用户使用最广泛的还是同步,而异步反而成为小众的使用场景。同步的优点是编程模型更加符合业务方的“传统”习惯,代价是在图中的1代表的请求发出事件后需要阻塞当前的Biz~线程,一直等到4代表的响应处理后才能唤醒。在这个短则微妙级别,长则秒级的1,2,3,4处理过程中都要阻塞Biz~线程,就会消耗线程资源,增加系统资源的开销。</p> +<p>在Java语言(其他语言不清楚)下一次本地接口的调用可以透明地通过代理机制转为远程RPC的调用,大多数业务方也比较喜欢这种与本地接口类似的编程方式做远程服务集成,所以虽然RPC内部天然是异步的,但使用Dubbo的用户使用最广泛的还是同步,而异步反而成为小众的使用场景。同步的优点是编程模型更加符合业务方的“传统”习惯,代价是在图中的1代表的请求发出事件后需要阻塞当前的Biz~线程,一直等到4代表的响应处理后才能唤醒。在这个短则微秒级别,长则秒级的1,2,3,4处理过程中都要阻塞Biz~线程,就会消耗线程资源,增加系统资源的开销。</p> <p>所以,客户端异步的出发点是节省线程资源开销,代价是需要了解下异步的使用方式:)。在同步方式下API接口的返回类型是代表着某个业务类,而当异步情况下,响应返回与请求发出是完全独立的两个事件,需要API接口的返回类型变为上述中说的CompletionStage才是最贴合的,这是Dubbo在异步上支持的必然异步。回到最近的Dubbo发布版,是不改变接口的情况下,需要在服务创建时注册一个回调接口来处理响应返回事件。</p> <p>下面以示例来说。</p> <h3>示例</h3> diff --git a/zh-cn/blog/dubboAsync_client.json b/zh-cn/blog/dubboAsync_client.json index d4159f3..6367a61 100644 --- a/zh-cn/blog/dubboAsync_client.json +++ b/zh-cn/blog/dubboAsync_client.json @@ -1,6 +1,6 @@ { "filename": "dubboAsync_client.md", - "__html": "<h1>Dubbo客户端异步接口的实现背景和实践</h1>\n<h2>铺垫</h2>\n<p><img src=\"../../img/blog/dubboasyn_client/1.png\" alt=\"image | left\"></p>\n<p>先简单介绍下一次完整的Dubbo调用所经历的线程阶段。几个信息这里罗列下</p>\n<ol>\n<li>\n<p>Biz~代表业务线程,即便是业务逻辑处理所处的线程,Biz~线程池可能是业务自己创建维护,大多数的可能是系统框架自身管理的(比如web型的业务系统跑在Tomcat容器下,Biz~线程就是Tomcat维护);IO~代表网络数据处理线程,是IO框架(比如Netty,Grizzly)创建维护,Dubbo Remoting所默认Netty实现是NioEventloopLoopGroup;另外按照Channel与IO线程的绑定关系,也可以直接把IO~看成一个可接受事件消息的Channel。像Biz和IO这样的异步处理阶段在JDK8中有个很精确地抽象描述,叫CompletionStage。</ [...] + "__html": "<h1>Dubbo客户端异步接口的实现背景和实践</h1>\n<h2>铺垫</h2>\n<p><img src=\"../../img/blog/dubboasyn_client/1.png\" alt=\"image | left\"></p>\n<p>先简单介绍下一次完整的Dubbo调用所经历的线程阶段。几个信息这里罗列下</p>\n<ol>\n<li>\n<p>Biz~代表业务线程,即便是业务逻辑处理所处的线程,Biz~线程池可能是业务自己创建维护,大多数的可能是系统框架自身管理的(比如web型的业务系统跑在Tomcat容器下,Biz~线程就是Tomcat维护);IO~代表网络数据处理线程,是IO框架(比如Netty,Grizzly)创建维护,Dubbo Remoting所默认Netty实现是NioEventloopLoopGroup;另外按照Channel与IO线程的绑定关系,也可以直接把IO~看成一个可接受事件消息的Channel。像Biz和IO这样的异步处理阶段在JDK8中有个很精确地抽象描述,叫CompletionStage。</ [...] "link": "/zh-cn/blog/dubboAsync_client.html", "meta": { "title": "Dubbo客户端异步接口的实现背景和实践",