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/15 03:52:58 UTC

[incubator-dubbo-website] branch asf-site updated: add dubbo-invoke (#91)

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 8142ed0  add dubbo-invoke (#91)
8142ed0 is described below

commit 8142ed0abdc00b7f1a67e66bc09b2d4ecf211405
Author: Zoe-Hou <13...@qq.com>
AuthorDate: Wed Aug 15 11:52:56 2018 +0800

    add dubbo-invoke (#91)
---
 blog/en-us/dubbo-invoke.md               | 216 +++++++++++++++++++++++++++++++
 blog/zh-cn/dubbo-invoke.md               |  12 +-
 docs/zh-cn/user/demos/logger-strategy.md |  16 +--
 docs/zh-cn/user/demos/static-service.md  |   2 +-
 4 files changed, 231 insertions(+), 15 deletions(-)

diff --git a/blog/en-us/dubbo-invoke.md b/blog/en-us/dubbo-invoke.md
new file mode 100644
index 0000000..ab51e2d
--- /dev/null
+++ b/blog/en-us/dubbo-invoke.md
@@ -0,0 +1,216 @@
+
+# Dubbo: Several ways about synchronous/asynchronous invoke
+
+As we all know,Dubbo adopts a single large join protocol by default and takes the NIO asynchronous communication mechanism of Netty as the low-level implementation. Based on this mechanism, Dubbo implements several invocation modes as follows:
+
+* synchronous invoke
+* asynchronous invoke
+* parameters callback
+* event notification
+
+### Synchronous invoke
+
+Synchronous invoke is a kind of blocking invocation mode, that is the Consumer keeps blocking and waiting, until the Provider returns.
+
+Generally, a typical synchronous invocation process is as follows:
+
+1. Consumer service thread invokes the remote API and sends requests to the Provider. Meanwhile, the current service thread stays in blocking state;
+2. Provider process relative request after receiving it from Consumer. Then returns the results to Consumer;
+3. After Consumer receiving results, the current thread continues to execute.
+
+Here are two problems:
+
+1. How does Consumer service thread turn into `blocking` state?
+2. How does the service thread be awaked to execute after Consumer receiving results?
+
+In fact, the low-level I/O operations of Dubbo are all asynchronous. The Consumer gets a Future object after invoking the Provider. For synchronous invoke, the service thread takes advantage of `Future#get(timeout)` to block and wait for Provider returning results, with the 'timeout' indicating the timeout defined by Consumer. When the result returns, the Future will be set and the blocked service thread will be awaked. The service thread will return an exception if there is no result af [...]
+
+### Asynchronous invoke
+
+For scenarios that Provider has a long response time, it's necessary to implement asynchronous invoke based on Dubbo's underlying asynchronous NIO. It could utilize the resource of Consumer effectively, and costs less than using multi-thread for Consumer.
+
+Asynchronous invoke does not need specific configuration for Provider. In the example,the API of Provider is defined as follow:
+
+```java
+public interface AsyncService {
+    String goodbye(String name);
+}
+```
+
+##### Consumer configuration
+
+```xml
+<dubbo:reference id="asyncService" interface="com.alibaba.dubbo.samples.async.api.AsyncService">
+    <dubbo:method name="goodbye" async="true"/>
+</dubbo:reference>
+```
+
+Notice that if we need an asynchronous revoke method, we must use `<dubbo:method/>` label to describe it.
+
+##### Consumer triggers invocation
+
+```java
+AsyncService service = ...;
+String result = service.goodbye("samples");// returns NULL and DO NOT use!
+Future<String> future = RpcContext.getContext().getFuture();
+... // other service thread logic
+result = future.get(); // could use get(timeout, unit) to configure timeout, when it needs to get the asynchronous result
+```
+
+After Dubbo Consumer triggers invocation, it uses `RpcContext.getContext().getFuture()` to get the relative `Future` object, and then it could start executing other tasks. Anytime when we need results, `future.get(timeout)` is supposed to be called.
+
+Under several special conditions, it could be set whether to wait for sending the request, to accelerate the return of invocation:
+
+* `sent="true"` Waiting for sending the request, and return an exception if it fails;
+* `sent="false"` Do not wait for the request, and returns immediately after putting the request to the I/O queue.
+
+We set it to `false` by default. And detailed configuration is as follows:
+
+```xml
+<dubbo:method name="goodbye" async="true" sent="true" />
+```
+
+If you only want to be asynchronous, then omit the result thoroughly, `return="false"` could be set to reduce the creation and management cost of Future:
+
+```xml
+<dubbo:method name="goodbye" async="true" return="false"/>
+```
+
+At this time,`RpcContext.getContext().getFuture()` will return `null`。
+
+The complete sequence diagram of asynchronous invoke is as follow:
+
+![Asynchronous invoke](../../img/blog/dubbo-async.svg)
+
+The sample locates at:https://github.com/dubbo/dubbo-samples/tree/master/dubbo-samples-async
+
+### Parameters callback
+
+The parameter Callback is somewhat similar to the local Callback mechanism, but Callback is not an inner class or interface of Dubbo. Instead, it is defined by the Provider. Dubbo will generate a reverse proxy based on the long connection, so as to implement the logic of calling the Consumer from the Provider.
+
+##### Service and Callback definition of Provider
+
+```java
+public interface CallbackService {
+    void addListener(String key, CallbackListener listener);
+}
+
+public interface CallbackListener {
+    void changed(String msg);
+}
+```
+
+##### Service implementation of Provider
+
+```java
+public class CallbackServiceImpl implements CallbackService {
+
+    private final Map<String, CallbackListener> listeners = new ConcurrentHashMap<String, CallbackListener>();
+
+    public CallbackServiceImpl() {
+        Thread t = new Thread(new Runnable() {
+            public void run() {
+                while (true) {
+                    try {
+                        for (Map.Entry<String, CallbackListener> entry : listeners.entrySet()) {
+                            try {
+                                entry.getValue().changed(getChanged(entry.getKey()));
+                            } catch (Throwable t) {
+                                listeners.remove(entry.getKey());
+                            }
+                        }
+                        Thread.sleep(5000); // timely trigger change event
+                    } catch (Throwable t) {
+                        t.printStackTrace();
+                    }
+                }
+            }
+        });
+        t.setDaemon(true);
+        t.start();
+    }
+
+    public void addListener(String key, CallbackListener listener) {
+        listeners.put(key, listener);
+        listener.changed(getChanged(key)); // send notification for change
+    }
+
+    private String getChanged(String key) {
+        return "Changed: " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
+    }
+}
+```
+
+##### Service exposure of Provider
+
+```xml
+<bean id="callbackService" class="com.alibaba.dubbo.samples.callback.impl.CallbackServiceImpl"/>
+
+<dubbo:service interface="com.alibaba.dubbo.samples.callback.api.CallbackService" ref="callbackService" connections="1" callbacks="1000">
+    <dubbo:method name="addListener">
+        <dubbo:argument index="1" callback="true"/>
+        <!--<dubbo:argument type="com.demo.CallbackListener" callback="true" />-->
+    </dubbo:method>
+</dubbo:service>
+```
+
+Here,Provider needs to declare which parameter is the Callback parameter in the method.
+
+##### Callback interface implementation of Consumer
+
+```java
+CallbackService callbackService = ...;
+callbackService.addListener("foo.bar", new CallbackListener() {
+        public void changed(String msg) {
+            System.out.println("callback1:" + msg);
+        }
+});
+```
+
+The implementation class of the Callback interface is on the Consumer, which automatically exports a Callback service when the method is called. Thus during Provider processing the call, if the parameter is determined as Callback, it will generate a proxy. Therefore, when the service implementation class calling the Callback method, it will be passed to the Consumer to execute the code.
+
+The sample code above is located at:https://github.com/dubbo/dubbo-samples/tree/master/dubbo-samples-callback
+
+This invocation mode is somewhat like message publishing and subscribing, but there is a little difference. For example, when the Consumer completes the export of Callback service, if it restarts later, then the Provider will fail to adjust. Meanwhile it is also a problem for the Provider to clean up the proxy.
+
+### Event notification
+
+Event notification allows the Consumer triggering three events,particularly `oninvoke`, `onreturn`, `onthrow` before calling, after calling or occurring exceptions.
+
+You can specify which events need to be notified during configuring Consumer, such as:
+
+```xml
+<bean id="demoCallback" class="com.alibaba.dubbo.samples.notify.impl.NotifyImpl" />
+
+<dubbo:reference id="demoService" check="false" interface="com.alibaba.dubbo.samples.notify.api.DemoService" version="1.0.0" group="cn">
+    <dubbo:method name="sayHello" onreturn="demoCallback.onreturn" onthrow="demoCallback.onthrow"/>
+</dubbo:reference>
+```
+
+Among them,the code of NotifyImpl is as follow:
+
+```java
+public class NotifyImpl implements Notify{
+
+    public Map<Integer, String> ret = new HashMap<Integer, String>();
+
+    public void onreturn(String name, int id) {
+        ret.put(id, name);
+        System.out.println("onreturn: " + name);
+    }
+
+    public void onthrow(Throwable ex, String name, int id) {
+        System.out.println("onthrow: " + name);
+    }
+}
+```
+
+Here we address that the parameter rules of three methods in the custom Notify interface are as follows:
+
+* `oninvoke` method's parameters are the same as the calling method parameters;
+* `onreturn` method's first parameter is the returned value of calling method,and the others are the same as the calling method;
+* `onthrow` method's first parameter is an invoked exception,and the others are the same as the calling method.
+
+In the above configuration, `sayHello` method is an asynchronous invocation, so the execution of event notification method is also synchronous. You can configure the `async = true` to make method invocation asynchronous, at this moment, event notification method is executed asynchronously. Especially emphasize that `oninvoke` method is executed synchronously, whether is an asynchronous call or not.
+
+Please refer to the sample code for event notification:https://github.com/dubbo/dubbo-samples/tree/master/dubbo-samples-notify
\ No newline at end of file
diff --git a/blog/zh-cn/dubbo-invoke.md b/blog/zh-cn/dubbo-invoke.md
index 16aa78e..01568f3 100644
--- a/blog/zh-cn/dubbo-invoke.md
+++ b/blog/zh-cn/dubbo-invoke.md
@@ -20,7 +20,7 @@
 这里有 2 个问题:
 
 1. Consumer 业务线程是怎么进入`阻塞`状态的?
-2. Consumer 收到结果后,如果唤醒业务线程往后执行的?
+2. Consumer 收到结果后,如何唤醒业务线程往后执行的?
 
 其实,Dubbo 的底层 IO 操作都是异步的。Consumer 端发起调用后,得到一个 Future 对象。对于同步调用,业务线程通过`Future#get(timeout)`,阻塞等待 Provider 端将结果返回;`timeout`则是 Consumer 端定义的超时时间。当结果返回后,会设置到此 Future,并唤醒阻塞的业务线程;当超时时间到结果还未返回时,业务线程将会异常返回。
 
@@ -63,13 +63,13 @@ Dubbo Consumer 端发起调用后,同时通过`RpcContext.getContext().getFutu
 * `sent="true"` 等待消息发出,消息发送失败将抛出异常;
 * `sent="false"` 不等待消息发出,将消息放入 IO 队列,即刻返回。
 
-默认为`fase`。配置方式如下:
+默认为`false`。配置方式如下:
 
 ```xml
 <dubbo:method name="goodbye" async="true" sent="true" />
 ```
 
-如果你只是想异步,完全忽略返回值,可以配置 `return="false"`,以减少 Future 对象的创建和管理成本:
+如果你只是想异步,完全忽略返回值,可以配置 `return="false"`,以减少 Future 对象的创建和管理成本:
 
 ```xml
 <dubbo:method name="goodbye" async="true" return="false"/>
@@ -168,13 +168,13 @@ callbackService.addListener("foo.bar", new CallbackListener() {
 
 Callback 接口的实现类在 Consumer 端,当方法发生调用时,Consumer 端会自动 export 一个 Callback 服务。而 Provider 端在处理调用时,判断如果参数是 Callback,则生成了一个 proxy,因此服务实现类里在调用 Callback 方法的时候,会被传递到 Consumer 端执行 Callback 实现类的代码。
 
-上述示例代码位于:此示例代码位于:https://github.com/dubbo/dubbo-samples/tree/master/dubbo-samples-callback
+上述示例代码位于:https://github.com/dubbo/dubbo-samples/tree/master/dubbo-samples-callback
 
 这种调用方式有点像消息的发布和订阅,但又有区别。比如当 Consumer 端 完成了Callback 服务的 export 后,如果后续重启了,这时 Provider 端就会调不通;同时 Provider 端如何清理掉这个 proxy 也是一个问题。
 
 ### 事件通知
 
-事件通知允许 Consumer 端在调用之前、调用正常返回之后或调用出现异常时,触发 `oninvoke`、`onreturn`、`onthrow` 三个事件。
+事件通知允许 Consumer 端在调用之前、调用之后或出现异常时,触发 `oninvoke`、`onreturn`、`onthrow` 三个事件。
 
 可以通过在配置 Consumer 时,指定事件需要通知的方法,如:
 
@@ -212,4 +212,4 @@ public class NotifyImpl implements Notify{
 
 上述配置中,`sayHello`方法为同步调用,因此事件通知方法的执行也是同步执行。可以配置 `async=true`让方法调用为异步,这时事件通知的方法也是异步执行的。特别强调一下,`oninvoke`方法不管是否异步调用,都是同步执行的。
 
-事件通知的示例代码请参考:https://github.com/dubbo/dubbo-samples/tree/master/dubbo-samples-notify
+事件通知的示例代码请参考:https://github.com/dubbo/dubbo-samples/tree/master/dubbo-samples-notify
\ No newline at end of file
diff --git a/docs/zh-cn/user/demos/logger-strategy.md b/docs/zh-cn/user/demos/logger-strategy.md
index ccc6111..f3050b9 100644
--- a/docs/zh-cn/user/demos/logger-strategy.md
+++ b/docs/zh-cn/user/demos/logger-strategy.md
@@ -1,23 +1,23 @@
 # 日志适配
 
-自 `2.2.1` 开始,dubbo 开始内置 log4j、slf4j、jcl、jdk 这些日志框架的适配 [^1],也可以通过以下方式显示配置日志输出策略:
+自 `2.2.1` 开始,dubbo 开始内置 log4j、slf4j、jcl、jdk 这些日志框架的适配[1],也可以通过以下方式显示配置日志输出策略:
 
 0. 命令行
 
     ```sh
-java -Ddubbo.application.logger=log4j
-```
+      java -Ddubbo.application.logger=log4j
+    ```
 
 0. 在 `dubbo.properties` 中指定
 
     ```
-dubbo.application.logger=log4j
-```
+      dubbo.application.logger=log4j
+    ```
 
 0. 在 `dubbo.xml` 中配置
 
     ```xml
-<dubbo:application logger="log4j" />
-```
+      <dubbo:application logger="log4j" />
+    ```
 
-[^1]: 自定义扩展可以参考[日志适配扩展](http://dubbo.apache.org/books/dubbo-dev-book/impls/logger-adapter.html)
+[1]: 自定义扩展可以参考 [日志适配扩展](http://dubbo.apache.org/books/dubbo-dev-book/impls/logger-adapter.html)
\ No newline at end of file
diff --git a/docs/zh-cn/user/demos/static-service.md b/docs/zh-cn/user/demos/static-service.md
index 7814b66..9b3b570 100644
--- a/docs/zh-cn/user/demos/static-service.md
+++ b/docs/zh-cn/user/demos/static-service.md
@@ -14,7 +14,7 @@
 
 服务提供者初次注册时为禁用状态,需人工启用。断线时,将不会被自动删除,需人工禁用。
 
-如果是一个第三方独立提供者,比如 memcached,可以直接向注册中心写入提供者地址信息,消费者正常使用 [^1]:
+如果是一个第三方服务提供者,比如 memcached,可以直接向注册中心写入提供者地址信息,消费者正常使用 [^1]:
 
 ```java
 RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension();