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 02:46:56 UTC

[incubator-dubbo-website] branch asf-site updated: Translate blog/spring-boot-dubbo-start-stop-analysis.md to English from Chinese

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 dee0b96  Translate blog/spring-boot-dubbo-start-stop-analysis.md to English from Chinese
dee0b96 is described below

commit dee0b96325df07d0e631a8c2790b77b89245f6f6
Author: Noah Gao <no...@outlook.com>
AuthorDate: Wed Aug 15 10:46:54 2018 +0800

    Translate blog/spring-boot-dubbo-start-stop-analysis.md to English from Chinese
    
    * Initial commit of translation spring-boot-dubbo-start-stop-analysis.md
    
    * fix spring-boot-dubbo-start-stop-analysis.md(zh-cn) problem
---
 .../en-us/spring-boot-dubbo-start-stop-analysis.md | 223 ++++++++++++++++++
 .../zh-cn/spring-boot-dubbo-start-stop-analysis.md |   4 +-
 en-us/blog/dubbo-loadbalance.html                  | 258 +++++++++++++++++++++
 en-us/blog/dubbo-loadbalance.json                  |   4 +
 en-us/blog/index.html                              |   2 +-
 .../blog/introduction-to-dubbo-qos.html            | 138 +++++------
 en-us/blog/introduction-to-dubbo-qos.json          |   4 +
 .../spring-boot-dubbo-start-stop-analysis.html     | 145 ++++++------
 .../spring-boot-dubbo-start-stop-analysis.json     |   4 +
 site_config/blog.js                                |   9 +-
 zh-cn/blog/dubbo-loadbalance.html                  |  80 +++----
 zh-cn/blog/dubbo-loadbalance.json                  |   2 +-
 zh-cn/blog/introduction-to-dubbo-qos.html          |   6 +-
 zh-cn/blog/introduction-to-dubbo-qos.json          |   2 +-
 .../spring-boot-dubbo-start-stop-analysis.html     |   4 +-
 .../spring-boot-dubbo-start-stop-analysis.json     |   2 +-
 16 files changed, 692 insertions(+), 195 deletions(-)

diff --git a/blog/en-us/spring-boot-dubbo-start-stop-analysis.md b/blog/en-us/spring-boot-dubbo-start-stop-analysis.md
new file mode 100644
index 0000000..27a6c77
--- /dev/null
+++ b/blog/en-us/spring-boot-dubbo-start-stop-analysis.md
@@ -0,0 +1,223 @@
+# Source code analysis of spring-boot+Dubbo App start and stop
+
+### Introduction
+
+[Dubbo Spring Boot](https://github.com/apache/incubator-dubbo-spring-boot-project) project is dedicated to simplifying the development of the Dubbo RPC framework in the Spring Boot application. It also integrates the feature of Spring Boot:
+
+- [Autoconfigure](https://github.com/apache/incubator-dubbo-spring-boot-project/blob/master/dubbo-spring-boot-autoconfigure) (ex: Annotation driver, Autoconfigure, etc.)
+- [Production-Ready](https://github.com/apache/incubator-dubbo-spring-boot-project/blob/master/dubbo-spring-boot-actuator) (ex: Security, Healthy check, Externalize configuration, etc.)
+
+### The analysis of DubboConsumer startup
+
+Have you ever thought about this : since the `DubboConsumerDemo` application in `incubator-dubbo-spring-boot-project` has only one line of code, why not just exit directly when the `main` method is executed?
+
+```java
+@SpringBootApplication(scanBasePackages = "com.alibaba.boot.dubbo.demo.consumer.controller")
+public class DubboConsumerDemo {
+
+    public static void main(String[] args) {
+        SpringApplication.run(DubboConsumerDemo.class,args);
+    }
+
+}
+```
+
+In fact, to answer this question, we need to abstract it first, that is, under what circumstances will a JVM process exit?
+
+Take Java 8 as an example. By referring to the JVM language specification[1], there is a clear description in Section 12.8:
+
+> A program terminates all its activity and *exits* when one of two things happens:
+>
+> - All the threads that are not daemon threads terminate.
+> - Some thread invokes the `exit` method of class `Runtime` or class `System`, and the `exit` operation is not forbidden by the security manager.
+
+Therefore, in view of the above situation, we judge that there must be some non-daemon thread not exiting. All thread information can be seen by `jstack`, including whether they are daemon threads, and `jstack` can be used to find out which threads are non-daemon.
+
+```sh
+➜  jstack 57785 | grep tid | grep -v "daemon"
+"container-0" #37 prio=5 os_prio=31 tid=0x00007fbe312f5800 nid=0x7103 waiting on condition  [0x0000700010144000]
+"container-1" #49 prio=5 os_prio=31 tid=0x00007fbe3117f800 nid=0x7b03 waiting on condition  [0x0000700010859000]
+"DestroyJavaVM" #83 prio=5 os_prio=31 tid=0x00007fbe30011000 nid=0x2703 waiting on condition  [0x0000000000000000]
+"VM Thread" os_prio=31 tid=0x00007fbe3005e800 nid=0x3703 runnable
+"GC Thread#0" os_prio=31 tid=0x00007fbe30013800 nid=0x5403 runnable
+"GC Thread#1" os_prio=31 tid=0x00007fbe30021000 nid=0x5303 runnable
+"GC Thread#2" os_prio=31 tid=0x00007fbe30021800 nid=0x2d03 runnable
+"GC Thread#3" os_prio=31 tid=0x00007fbe30022000 nid=0x2f03 runnable
+"G1 Main Marker" os_prio=31 tid=0x00007fbe30040800 nid=0x5203 runnable
+"G1 Conc#0" os_prio=31 tid=0x00007fbe30041000 nid=0x4f03 runnable
+"G1 Refine#0" os_prio=31 tid=0x00007fbe31044800 nid=0x4e03 runnable
+"G1 Refine#1" os_prio=31 tid=0x00007fbe31045800 nid=0x4d03 runnable
+"G1 Refine#2" os_prio=31 tid=0x00007fbe31046000 nid=0x4c03 runnable
+"G1 Refine#3" os_prio=31 tid=0x00007fbe31047000 nid=0x4b03 runnable
+"G1 Young RemSet Sampling" os_prio=31 tid=0x00007fbe31047800 nid=0x3603 runnable
+"VM Periodic Task Thread" os_prio=31 tid=0x00007fbe31129000 nid=0x6703 waiting on condition
+
+```
+
+> We can find all the thread digests by `grep tid` here, and find the line that doesn't contain the daemon keyword by `grep -v` command.
+
+We can get some information from the above results:
+
+- There are two "suspicious" threads : `container-0`, `container-1`. They are non-daemon thread in wait state.
+- There are alse some threads about GC, and threads that start with `VM`. They are also some non-daemon threads, but they are most likely the JVM's own threads, which we can ignore for now.
+
+In summary, we can infer that it is likely that the `container-0` and `container-1` cause the JVM to not exit. Now let's search through the source code to find out who created the two threads.
+
+By the source code analysis of Spring-boot, we can find these code in the `startDaemonAwaitThread` method of `org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainer`.
+
+```java
+    private void startDaemonAwaitThread() {
+        Thread awaitThread = new Thread("container-" + (containerCounter.get())) {
+
+            @Override
+            public void run() {
+                TomcatEmbeddedServletContainer.this.tomcat.getServer().await();
+            }
+
+        };
+        awaitThread.setContextClassLoader(getClass().getClassLoader());
+        awaitThread.setDaemon(false);
+        awaitThread.start();
+    }
+```
+
+Let's add a breakpoint in this method, and focus on the call stack:
+
+```plain
+initialize:115, TomcatEmbeddedServletContainer (org.springframework.boot.context.embedded.tomcat)
+<init>:84, TomcatEmbeddedServletContainer (org.springframework.boot.context.embedded.tomcat)
+getTomcatEmbeddedServletContainer:554, TomcatEmbeddedServletContainerFactory (org.springframework.boot.context.embedded.tomcat)
+getEmbeddedServletContainer:179, TomcatEmbeddedServletContainerFactory (org.springframework.boot.context.embedded.tomcat)
+createEmbeddedServletContainer:164, EmbeddedWebApplicationContext (org.springframework.boot.context.embedded)
+onRefresh:134, EmbeddedWebApplicationContext (org.springframework.boot.context.embedded)
+refresh:537, AbstractApplicationContext (org.springframework.context.support)
+refresh:122, EmbeddedWebApplicationContext (org.springframework.boot.context.embedded)
+refresh:693, SpringApplication (org.springframework.boot)
+refreshContext:360, SpringApplication (org.springframework.boot)
+run:303, SpringApplication (org.springframework.boot)
+run:1118, SpringApplication (org.springframework.boot)
+run:1107, SpringApplication (org.springframework.boot)
+main:35, DubboConsumerDemo (com.alibaba.boot.dubbo.demo.consumer.bootstrap)
+```
+
+It can be seen that during the startup process of the Spring-boot application, the above method is executed since the execution of Tomcat exposes the HTTP service by default. Also, all threads started by Tomcat are daemon threads by default, such as the Acceptor of the listening request, threads in working threads, etc. Thus the JVM will also exit after the startup is complete in there is no extra control here. Therefore, it is necessary to explicitly start a thread and continue to wait  [...]
+
+Let's dig deeper to find out how the thread stay alive in Tomcat's `this.tomcat.getServer().await()` method.
+
+```java
+public void await() {
+        // ...
+        if( port==-1 ) {
+            try {
+                awaitThread = Thread.currentThread();
+                while(!stopAwait) {
+                    try {
+                        Thread.sleep( 10000 );
+                    } catch( InterruptedException ex ) {
+                        // continue and check the flag
+                    }
+                }
+            } finally {
+                awaitThread = null;
+            }
+            return;
+        }
+        // ...
+    }
+```
+
+In the await method, the current thread checks the variable `stopAwait` every 10 seconds in a while loop. It is a `volatile` variable that is used to ensure that the current thread can see the change immediately after the variable being modified by another thread. If there is no change, it will stay in the loop. This is the reason why the thread does not exit, which is also the reason that the entire Spring-boot application doesn't exit.
+
+Since Spring-boot application enables port 8080 and 8081(management port) at the same time, there are actually two Tomcats. So there are two threads named `container-0` and `container-1`.
+
+Next, let's see how this Spring-boot application exits.
+
+### The analysis of DubboConsumer exit
+
+As mentioned in the previous description, there is a thread that checks the variable `stopAwait` continuously. So there must be a thread to modify `stopAwait` at Stop, thus break the while loop. But who is modifying this variable?
+
+By analyzing the source code, we can see that there is only one method that modifies `stopAwait` : `org.apache.catalina.core.StandardServer#stopAwait`. To figure out who is calling this method, we add a breakpoint here.
+
+> Note that after adding a breakpoint in Intellij IDEA's Debug mode, we also need to type `kill -s INT $PID` or `kill -s TERM $PID` in command line to trigger the breakpoint. Due to buggy IDEA, a single click to the stop button won't trigger the breakpoint.
+
+You can see the method is called by a thread called `Thread-3`:
+
+```java
+stopAwait:390, StandardServer (org.apache.catalina.core)
+stopInternal:819, StandardServer (org.apache.catalina.core)
+stop:226, LifecycleBase (org.apache.catalina.util)
+stop:377, Tomcat (org.apache.catalina.startup)
+stopTomcat:241, TomcatEmbeddedServletContainer (org.springframework.boot.context.embedded.tomcat)
+stop:295, TomcatEmbeddedServletContainer (org.springframework.boot.context.embedded.tomcat)
+stopAndReleaseEmbeddedServletContainer:306, EmbeddedWebApplicationContext (org.springframework.boot.context.embedded)
+onClose:155, EmbeddedWebApplicationContext (org.springframework.boot.context.embedded)
+doClose:1014, AbstractApplicationContext (org.springframework.context.support)
+run:929, AbstractApplicationContext$2 (org.springframework.context.support)
+```
+
+Through source code analysis, it was executed by Spring's registered `ShutdownHook`.
+
+```java
+    @Override
+    public void registerShutdownHook() {
+        if (this.shutdownHook == null) {
+            // No shutdown hook registered yet.
+            this.shutdownHook = new Thread() {
+                @Override
+                public void run() {
+                    synchronized (startupShutdownMonitor) {
+                        doClose();
+                    }
+                }
+            };
+            Runtime.getRuntime().addShutdownHook(this.shutdownHook);
+        }
+    }
+```
+
+By reffering the Java API documentation[2], we found that ShutdownHook will be executed under the following two cases.
+
+> The Java virtual machine *shuts down* in response to two kinds of events:
+>
+> - The program *exits* normally, when the last non-daemon thread exits or when the `exit` (equivalently, [`System.exit`](https://docs.oracle.com/javase/8/docs/api/java/lang/System.html#exit-int-)) method is invoked, or
+> - The virtual machine is *terminated* in response to a user interrupt, such as typing `^C`, or a system-wide event, such as user logoff or system shutdown.
+
+1. So it's either a call of `System.exit()`
+2. Respond to external signals, such as Ctrl+C(actually sent as SIGINT signal), or `SIGTERM` signal (`kill $PID` will send `SIGTERM` signal by default)
+
+Therefore, the normal application will execute the above ShutdownHook during the stop process (except `kill -9 $PID`). Its function is not only to close the Tomcat, but also to perform other cleanup work. It is unnecessary to go into details.
+
+### Summary
+
+1. During the startup of `DubboConsumer`, an independent non-daemon thread is launched to query the status of the variable continuously, thus the process can't exit.
+2. To stop the `DubboConsumer`, one should call ShutdownHook to change the variable to let the thread break the loop.
+
+### Problems
+
+In the example of DubboProvider, we see that Provider doesn't start Tomcat to provide HTTP service, then how does the program stays alive without exiting? We will answer this question in the next article.
+
+#### Notice
+
+By running the following unit test which create a thread in `Intellij IDEA` , we are surprised to find that the program exits with less than 1000s. Why?(The thread being created is a non-daemon thread)
+
+```java
+    @Test
+    public void test() {
+        new Thread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    Thread.sleep(1000000);
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
+            }
+        }).start();
+    }
+```
+
+
+
+[1] https://docs.oracle.com/javase/specs/jls/se8/html/jls-12.html#jls-12.8
+
+[2] https://docs.oracle.com/javase/8/docs/api/java/lang/Runtime.html#addShutdownHook
\ No newline at end of file
diff --git a/blog/zh-cn/spring-boot-dubbo-start-stop-analysis.md b/blog/zh-cn/spring-boot-dubbo-start-stop-analysis.md
index 3e4328a..5448c1f 100644
--- a/blog/zh-cn/spring-boot-dubbo-start-stop-analysis.md
+++ b/blog/zh-cn/spring-boot-dubbo-start-stop-analysis.md
@@ -105,7 +105,7 @@ run:1107, SpringApplication (org.springframework.boot)
 main:35, DubboConsumerDemo (com.alibaba.boot.dubbo.demo.consumer.bootstrap)
 ```
 
-可以看到,spring-boot应用在启动的过程中,由于默认启动了Tomcat暴露HTTP服务,所以执行到了上述方法,而Tomcat启动的所有的线程,默认都是daemon线程,例如监听请求的Acceptor,工作线程池等等,如果这里不加控制的话,启动完成之后JVM也会退出。因此需要显示的启动一个线程,在某个条件下进行持续等待,从而避免线程退出。
+可以看到,spring-boot应用在启动的过程中,由于默认启动了Tomcat暴露HTTP服务,所以执行到了上述方法,而Tomcat启动的所有的线程,默认都是daemon线程,例如监听请求的Acceptor,工作线程池等等,如果这里不加控制的话,启动完成之后JVM也会退出。因此需要显式地启动一个线程,在某个条件下进行持续等待,从而避免线程退出。
 
 下面我们在深挖一下,在Tomcat的`this.tomcat.getServer().await()`这个方法中,线程是如何实现不退出的。这里为了阅读方便,去掉了不相关的代码。
 
@@ -203,7 +203,7 @@ run:929, AbstractApplicationContext$2 (org.springframework.context.support)
 
 #### 彩蛋
 
-在` Intellij IDEA`中运行了如下的单元测试,创建一个线程执行睡眠1000秒的操作,我们惊奇的发现,代码并没有线程执行完就退出了,这又是为什么呢?(被创建的线程是非daemon线程)
+在`Intellij IDEA`中运行了如下的单元测试,创建一个线程执行睡眠1000秒的操作,我们惊奇的发现,代码并没有线程执行完就退出了,这又是为什么呢?(被创建的线程是非daemon线程)
 
 ```java
     @Test
diff --git a/en-us/blog/dubbo-loadbalance.html b/en-us/blog/dubbo-loadbalance.html
new file mode 100644
index 0000000..cd3a35e
--- /dev/null
+++ b/en-us/blog/dubbo-loadbalance.html
@@ -0,0 +1,258 @@
+<!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-loadbalance" />
+	<meta name="description" content="dubbo-loadbalance" />
+	<!-- 网页标签标题 -->
+	<title>dubbo-loadbalance</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="" data-reactid="1" data-react-checksum="946004967"><header class="header-container header-container-normal" data-reactid="2"><div class="header-body" data-reactid="3"><a href="/en-us/index.html" data-reactid="4"><img class="logo" src="/img/dubbo_colorful.png" data-reactid="5"/></a><span class="language-switch language-switch-normal" data-reactid="6">中</span><div class="header-menu" data-reactid="7"><img class="header-menu-togg [...]
+<h2>Background</h2>
+<p>Dubbo is a distributed service framework that avoids single point of failure and horizontal expansion of support services. A service typically deploys multiple instances. How to select a call from a cluster of multiple service providers involves a load balancing strategy.</p>
+<h2>Concepts</h2>
+<p>Before discussing load balancing, I will explain these three concepts first.</p>
+<ol>
+<li>Load Balancing</li>
+<li>Fault-tolerant Cluster</li>
+<li>Service Route</li>
+</ol>
+<p>These three concepts are confusing. They all describe how to choose from multiple Providers to make calls. So what is the difference between them? Let me give a simple example and explain these concepts clearly.</p>
+<p>There is a Dubbo user service, 10 deployed in Beijing and 20 deployed in Shanghai. A service consumer in Hangzhou initiated a call and then the following steps executed:</p>
+<ol>
+<li>According to the configured routing rule, if the call is initiated by Hangzhou, it will be routed to the nearest 20 Providers in Shanghai.</li>
+<li>According to the configured random load balancing strategy, one of the 20 Providers is randomly selected to be called, assuming that the 7th Provider is randomly selected.</li>
+<li>As a result, calling the 7th Provider failed.</li>
+<li>Retried other servers according to the configured Fault-tolerant Cluster mode.</li>
+<li>The call to the 13th Provider was successful.</li>
+</ol>
+<p>Steps 1, 2, and 4 above correspond to routing, load balancing, and fault-tolerant cluster. In Dubbo, a subset is selected by routing from multiple Providers according to routing rules, then a Provider selected from the subset according to load balancing to make this call. If the call fails, Dubbo retry or schedule retransmission or fail-fast according to the Fault-tolerant Cluster policy. You can see the routes in Dubbo, load balancing and Fault-tolerant Cluster exectute at different  [...]
+<h2>Dubbo's Internal Load Balancing Strategy</h2>
+<p>Dubbo has four Internal Load Balancing Strategies:</p>
+<ol>
+<li>RandomLoadBalance: Random load balancing. Choose a Provider randomly. It is Dubbo's default load balancing strategy.</li>
+<li>Round Robin Load Balancing: Polling load balancing, then chooses one Provider.</li>
+<li>LeastActiveLoadBalance: The minimum number of active calls, the random number of the same active number. The active number refers to the difference before and after the call. Make slow providers receive fewer requests, because the slower Provider before and after the difference of calls will be larger.</li>
+<li>ConsistentHashLoadBalance: Consistent hash load balancing. Requests with the same parameters always fall on the same machine.</li>
+</ol>
+<h3>1. Random Load Balancing</h3>
+<p>As the name implies, the random load balancing strategy is to select one from multiple Providers randomly. However, random load balancing in Dubbo has a weighting concept that sets the random probability according to the weight. For example, there are 10 Providers, it's not to say that the probability of each Provider is the same, but to assign the probability by combining the weights of these 10 providers.</p>
+<p>In Dubbo, you can set weights on the Provider. For example, if the performance of the machine is better, you can set a larger weight. If the performance is poorer, you can set a smaller weight. Weights have an impact on load balancing. The weight of provider can be set in Dubbo Admin.</p>
+<h4>Weight-based Load Balancing Algorithm</h4>
+<p>The stochastic strategy will determine whether the weights of all the invokers are the same at first. If they are all the same, then the processing is relatively simple. Using <code>random.nexInt(length)</code>, you can randomly generate an invoker serial number, and select the corresponding invoker according to the serial number. If the service provider not set weight in Dubbo Admin, then all the invokers have the same weight, the default is 100. If the weights are different, then yo [...]
+<table>
+<thead>
+<tr>
+<th>Invoker</th>
+<th>Weight</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>A</td>
+<td>10</td>
+</tr>
+<tr>
+<td>B</td>
+<td>20</td>
+</tr>
+<tr>
+<td>C</td>
+<td>20</td>
+</tr>
+<tr>
+<td>D</td>
+<td>30</td>
+</tr>
+</tbody>
+</table>
+<p>The total weight of A, B, C and D is 10 + 20 + 20 + 30 = 80. Spread 80 numbers in the following diagram:</p>
+<pre><code>+-----------------------------------------------------------------------------------+
+|          |                    |                    |                              |
++-----------------------------------------------------------------------------------+
+1          10                   30                   50                             80
+
+|-----A----|---------B----------|----------C---------|---------------D--------------|
+
+
+---------------------15
+
+-------------------------------------------37
+
+-----------------------------------------------------------54
+</code></pre>
+<p>There are four areas in the above picture, and the lengths are the weights of A, B, C and D, respectively. Use <code>random.nextInt(10 + 20 + 20 + 30)</code> to randomly select one of the 80 numbers. Then determine which area the number is distributed in. For example, if random to 37, 37 is distributed in the C region, then select inboker C. 15 is in the B area, 54 is in the D area.</p>
+<h4>Random load balancing Source code</h4>
+<p>Below is the source code for random load balancing. For ease of reading and understanding, I removed the extraneous parts.</p>
+<pre><code>public class RandomLoadBalance extends AbstractLoadBalance {
+
+    private final Random random = new Random();
+
+    protected &lt;T&gt; Invoker&lt;T&gt; doSelect(List&lt;Invoker&lt;T&gt;&gt; invokers, URL url, Invocation invocation) {
+        int length = invokers.size();      // total invoker
+        int totalWeight = 0;               // Sum of invokers' weights
+
+        // Determine if all the invokers have the same weight
+        // If the weights are the same, it is simple to generate an index directly from Random.
+        boolean sameWeight = true;
+        for (int i = 0; i &lt; length; i++) {
+            int weight = getWeight(invokers.get(i), invocation);
+            totalWeight += weight; // Sum
+            if (sameWeight &amp;&amp; i &gt; 0 &amp;&amp; weight != getWeight(invokers.get(i - 1), invocation)) {
+                sameWeight = false;
+            }
+        }
+
+        if (totalWeight &gt; 0 &amp;&amp; !sameWeight) {
+            // If not all of the invoker weights are the same, load balancer will randomly choose invoker based on its weight. The greater the weight, the greater the probability of being selected
+            int offset = random.nextInt(totalWeight);
+            for (int i = 0; i &lt; length; i++) {
+                offset -= getWeight(invokers.get(i), invocation);
+                if (offset &lt; 0) {
+                    return invokers.get(i);
+                }
+            }
+        }
+        // If all invokers have the same weight
+        return invokers.get(random.nextInt(length));
+    }
+}
+</code></pre>
+<h3>2. Round Robin Load Balancing</h3>
+<p>Round Robin Load Balancing, is to call all Providers in turn. As with random load balancing strategies, Round Robin Load Balancing policies also has a weighting concept. The Round Robin Load Balancing algorithm allows RPC calls to be allocated exactly as we set. Whether it is a small or large number of calls. However, there are also some shortcomings in the Round Robin Load Balancing algorithm. There is a problem that the slow provider accumulates the request. For example, the second  [...]
+<h3>3. Minimum Active Call Load Balancing</h3>
+<p>Official explanation:</p>
+<blockquote>
+<p>The active number refers to the difference between the counts before and after the call. Select the machine with the minimum number of active calls or choose a random one among machines with the same active number, so that the slower machine can receives less requests.</p>
+</blockquote>
+<p>This explanation seems to be ambigious. We know the purpose is to ensure the slower machine receive less requests, but it is not clear how to achieve it. An example is here: each service maintains an active number counter. When A machine starts processing the request, the counter is incremented by 1. At this time, A is still processing. If the processing is completed, the counter is decremented by 1. B machine processes very quickly after receiving the request. Then the active numbers [...]
+<p>When processing a new request, Consumer will check the active number of all Providers. If there is only one Invoker with the minimum active number, the Invoker is returned directly.</p>
+<pre><code>if (leastCount == 1) {
+    // if there is only one minimum value then return directly
+    return invokers.get(leastIndexs[0]);
+}
+</code></pre>
+<p>If there are multiple Invokers with the minimum active number, plus the weights are not equal and the total weight is greater than 0, then generate a random weight ranging from 0 to totalWeight. Finally, the Invoker is selected based on the randomly generated weights.</p>
+<pre><code>if (! sameWeight &amp;&amp; totalWeight &gt; 0) {
+    // if the weights are not equal and the toatl weight is greater than 0 then choose randomly according to total weight
+
+    int offsetWeight = random.nextInt(totalWeight);
+
+    // and determine which segment the random value falls on.
+
+    for (int i = 0; i &lt; leastCount; i++) {
+        int leastIndex = leastIndexs[i];
+        offsetWeight -= getWeight(invokers.get(leastIndex), invocation);
+        if (offsetWeight &lt;= 0)
+            return invokers.get(leastIndex);
+    }
+}
+</code></pre>
+<h3>4. Consistent Hash Algorithm</h3>
+<p>Use consistent hash algorithm to ensure that requests with same parameters are always sent to the same Provider. When a Provider crashes, requests originally sent to the Provider is spread evenly to other Providers based on the virtual node without causing drastic changes. The algorithm can be seen at: <a href="http://en.wikipedia.org/wiki/Consistent_hashing">http://en.wikipedia.org/wiki/Consistent_hashing</a></p>
+<p>By default, only the first parameter is hashed. Configure if you would like to modify it:</p>
+<pre><code>&lt;dubbo:parameter key=&quot;hash.arguments&quot; value=&quot;0,1&quot; /&gt;
+</code></pre>
+<p>By default, 160 virtual nodes are used. Configure if you would like to modify it:</p>
+<pre><code>&lt;dubbo:parameter key=&quot;hash.nodes&quot; value=&quot;320&quot; /&gt;
+</code></pre>
+<p>Consistent hash algorithms can be used in conjunction with caching mechanisms. For example, there is a service getUserInfo(String userId). After the hash algorithm is set, the same userId call is sent to the same Provider. This Provider can cache user data in memory, reducing the number of accesses to the database or distributed cache. If this part of the data is allowed to be inconsistent for some time, this approach can be considered. The number of dependencies and accesses to middl [...]
+<h2>Load Balancing Configuration</h2>
+<p>If load balancing is not specified, random load balancing is used by default. Load balancing can also be explicitly specified based on our needs. Load balancing can be configured in multiple local classes, such as Provider Side, Consumer Side, Service Level, and Method Level.</p>
+<h3>Server Side Service Level</h3>
+<pre><code>&lt;dubbo:service interface=&quot;...&quot; loadbalance=&quot;roundrobin&quot; /&gt;
+</code></pre>
+<p>All methods of the service use roundrobin load balancing.</p>
+<h3>Client Side Service Level</h3>
+<pre><code>&lt;dubbo:reference interface=&quot;...&quot; loadbalance=&quot;roundrobin&quot; /&gt;
+</code></pre>
+<p>All methods of the service use roundrobin load balancing.</p>
+<h3>Server Side Method Level</h3>
+<pre><code>&lt;dubbo:service interface=&quot;...&quot;&gt;
+    &lt;dubbo:method name=&quot;hello&quot; loadbalance=&quot;roundrobin&quot;/&gt;
+&lt;/dubbo:service&gt;
+</code></pre>
+<p>Only the hello method of the service uses roundrobin load balancing.</p>
+<h3>Client Side Method Level</h3>
+<pre><code>&lt;dubbo:reference interface=&quot;...&quot;&gt;
+    &lt;dubbo:method name=&quot;hello&quot; loadbalance=&quot;roundrobin&quot;/&gt;
+&lt;/dubbo:reference&gt;
+</code></pre>
+<p>Only the hello method of the service uses roundrobin load balancing.</p>
+<p>Similar to other Dubbo configurations, multiple configurations are covered:</p>
+<ol>
+<li>The method level takes precedence, the interface level is next, and the global configuration comes last.</li>
+<li>If the level is the same, the Consumer is given priority and the Provider is next</li>
+</ol>
+<p>Therefore, the priority of the above four configurations is:</p>
+<ol>
+<li>Client side method level configuration.</li>
+<li>Client side interface level configuration.</li>
+<li>Server side method level configuration.</li>
+<li>Server side interface level configuration.</li>
+</ol>
+<h2>Extended Load Balancing</h2>
+<p>Four load balancing implementations of Dubbo meet the requirements in most cases. Sometimes, we may need to implement our own load balancing strategy because of the needs of the business. This chapter only explains how to configure the load balancing algorithm. For more on the Dubbo extension mechanism, go to the Dubbo extension mechanism practice.</p>
+<ol>
+<li>Implementing the LoadBalance interface</li>
+</ol>
+<p>The following is Dubbo's LoadBalance interface:</p>
+<pre><code>@SPI(RandomLoadBalance.NAME)
+public interface LoadBalance {
+    @Adaptive(&quot;loadbalance&quot;)
+    &lt;T&gt; Invoker&lt;T&gt; select(List&lt;Invoker&lt;T&gt;&gt; invokers, URL url, Invocation invocation) throws RpcException;
+}
+</code></pre>
+<p>This is the interface of the SPI. The parameters of the select method are as follows:</p>
+<ul>
+<li>invokers: A list of all service Providers.</li>
+<li>url: Some configuration information, such as interface name, check or not, serialization.</li>
+<li>invocation: Information called by the RPC, including the method name, method parameter type, and method parameters. Here is a LoadBalance implemented by us. The implementation is very simple - Choose the first Invoker:</li>
+</ul>
+<pre><code>package com.demo.dubbo;
+public class DemoLoadBalance implements LoadBalance {
+    @Override
+    public &lt;T&gt; Invoker&lt;T&gt; select(List&lt;Invoker&lt;T&gt;&gt; invokers, URL url, Invocation invocation) throws RpcException {
+        System.out.println(&quot;[DemoLoadBalance]Select the first invoker...&quot;);
+        return invokers.get(0);
+    }
+}
+</code></pre>
+<ol start="2">
+<li>Add a resource file</li>
+</ol>
+<p>Add a file:
+<code>src/main/resource/META-INF/dubbo/com.alibaba.dubbo.rpc.cluster.LoadBalance</code>
+This is a simple text file. The file contents are as follows:</p>
+<pre><code>demo=my=com.demo.dubbo.DemoLoadBalance
+</code></pre>
+<ol start="3">
+<li>Configure to use custom LoadBalance</li>
+</ol>
+<pre><code>&lt;dubbo:reference id=&quot;helloService&quot; interface=&quot;com.demo.dubbo.api.IHelloService&quot; loadbalance=&quot;demo&quot; /&gt;
+</code></pre>
+<p>Configure  <code>&lt;loadbalance=&quot;demo&quot;&gt;</code> in <code>dubbo:reference</code> at the Consumer side.</p>
+<p>After 3 steps above, we wrote a custom LoadBalance and told Dubbo to use it. Start Dubbo and we can see that Dubbo has used a custom DemoLoadBalance.</p>
+</section><footer class="footer-container" data-reactid="19"><div class="footer-body" data-reactid="20"><img src="/img/dubbo_gray.png" data-reactid="21"/><img class="apache" src="/img/apache_logo.png" data-reactid="22"/><div class="cols-container" data-reactid="23"><div class="col col-12" data-reactid="24"><h3 data-reactid="25">Disclaimer</h3><p data-reactid="26">Apache Dubbo is an effort undergoing incubation at The Apache Software Foundation (ASF), sponsored by the Incubator. Incubatio [...]
+	<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/dubbo-loadbalance.json b/en-us/blog/dubbo-loadbalance.json
new file mode 100644
index 0000000..4a99efa
--- /dev/null
+++ b/en-us/blog/dubbo-loadbalance.json
@@ -0,0 +1,4 @@
+{
+  "filename": "dubbo-loadbalance.md",
+  "__html": "<h1>Dubbo's Load Balance</h1>\n<h2>Background</h2>\n<p>Dubbo is a distributed service framework that avoids single point of failure and horizontal expansion of support services. A service typically deploys multiple instances. How to select a call from a cluster of multiple service providers involves a load balancing strategy.</p>\n<h2>Concepts</h2>\n<p>Before discussing load balancing, I will explain these three concepts first.</p>\n<ol>\n<li>Load Balancing</li>\n<li>Fault-t [...]
+}
\ No newline at end of file
diff --git a/en-us/blog/index.html b/en-us/blog/index.html
index a58f15e..64bcfa0 100644
--- a/en-us/blog/index.html
+++ b/en-us/blog/index.html
@@ -12,7 +12,7 @@
 	<link rel="stylesheet" href="/build/blog.css" />
 </head>
 <body>
-	<div id="root"><div class="blog-list-page" data-reactroot="" data-reactid="1" data-react-checksum="-1130478652"><header class="header-container header-container-normal" data-reactid="2"><div class="header-body" data-reactid="3"><a href="/en-us/index.html" data-reactid="4"><img class="logo" src="/img/dubbo_colorful.png" data-reactid="5"/></a><span class="language-switch language-switch-normal" data-reactid="6">中</span><div class="header-menu" data-reactid="7"><img class="header-menu-togg [...]
+	<div id="root"><div class="blog-list-page" data-reactroot="" data-reactid="1" data-react-checksum="2024873649"><header class="header-container header-container-normal" data-reactid="2"><div class="header-body" data-reactid="3"><a href="/en-us/index.html" data-reactid="4"><img class="logo" src="/img/dubbo_colorful.png" data-reactid="5"/></a><span class="language-switch language-switch-normal" data-reactid="6">中</span><div class="header-menu" data-reactid="7"><img class="header-menu-toggl [...]
 	<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>
diff --git a/zh-cn/blog/introduction-to-dubbo-qos.html b/en-us/blog/introduction-to-dubbo-qos.html
similarity index 54%
copy from zh-cn/blog/introduction-to-dubbo-qos.html
copy to en-us/blog/introduction-to-dubbo-qos.html
index c1d2f91..8093625 100644
--- a/zh-cn/blog/introduction-to-dubbo-qos.html
+++ b/en-us/blog/introduction-to-dubbo-qos.html
@@ -12,35 +12,35 @@
 	<link rel="stylesheet" href="/build/blogDetail.css" />
 </head>
 <body>
-	<div id="root"><div class="blog-detail-page" data-reactroot="" data-reactid="1" data-react-checksum="-96574520"><header class="header-container header-container-normal" data-reactid="2"><div class="header-body" data-reactid="3"><a href="/zh-cn/index.html" data-reactid="4"><img class="logo" src="/img/dubbo_colorful.png" data-reactid="5"/></a><span class="language-switch language-switch-normal" data-reactid="6">En</span><div class="header-menu" data-reactid="7"><img class="header-menu-tog [...]
-<p>QoS,全称为<code>Quality of Service</code>, 是常见于网络设备中的一个术语 ,例如在路由器中,可以通过Qos动态的调整和控制某些端口的权重,从优先的保障运行在这些端口上的服务质量。</p>
-<p>在Dubbo中,QoS这个概念被用于动态的对服务进行查询和控制。例如对获取当前提供和消费的所有服务,以及对服务进行动态的上下线,即从注册中心上进行注册和反注册操作。</p>
-<h3>QoS工作机制</h3>
-<p>从Dubbo 2.5.8开始,默认引入了Qos功能,默认处于启动状态。所有的QoS功能被抽象成一个个的命令,通过执行这些命令,Qos会返回响应的结果。</p>
+	<div id="root"><div class="blog-detail-page" data-reactroot="" data-reactid="1" data-react-checksum="-1448616405"><header class="header-container header-container-normal" data-reactid="2"><div class="header-body" data-reactid="3"><a href="/en-us/index.html" data-reactid="4"><img class="logo" src="/img/dubbo_colorful.png" data-reactid="5"/></a><span class="language-switch language-switch-normal" data-reactid="6">中</span><div class="header-menu" data-reactid="7"><img class="header-menu-to [...]
+<p>QoS (short form of <strong>Quality of Service</strong>), is a common terminology talking about network devices. For example, by adjusting and manipulating the weights of ports of a router dynamically via QoS, engineers could give priority to services running on these ports and make sure these services' quality and reliability.</p>
+<p>In Dubbo, QoS is used to query and manipulate services dynamically, like getting a list of active provider and consumer services, and launching or withdrawing services (i.e registering to or unregistering services from registration center).</p>
+<h2>Mechanism of QoS</h2>
+<p>From 2.5.8, QoS is introduced into Dubbo and is activated by default. All QoS's features are abstracted to commands, which could be executed to get responses from QoS.</p>
 <blockquote>
-<p>Qos功能基于Netty4实现,在Dubbo 2.6.x之前的版本中,默认依赖的是Netty3,因此需要显示的添加Netty4的依赖,才能确保Netty4正常工作。如果使用http://start.dubbo.io自动生成的Dubbo应用,则无需添加额外的配置,因为已经默认加上了Netty4的依赖。</p>
+<p>QoS is based on Netty4. In versions earlier than 2.6.x, Dubbo relies on Netty3, so you have to add Netty4 as a dependency explicitly to ensure that Netty4 works. If you generate a Dubbo application on <a href="http://start.dubbo.io">http://start.dubbo.io</a>, there's no need to add configurations because Netty4 is listed as a dependency by default.</p>
 </blockquote>
-<p>Qos的工作机制如下图所示:</p>
 <p><img src="../../img/blog/qos-architecture.png" alt="undefined"></p>
+<p>The picture above shows how QoS works:</p>
 <ol>
-<li>启动并监听一个端口,默认端口是22222</li>
-<li>识别目标请求的协议是Http或者是Telnet,根据协议不同动态添加对应的处理器</li>
-<li>针对不同的协议进行解码,解析出需要执行的命令</li>
-<li>执行命令并返回结果</li>
+<li>Start and listen to a port (22222 by default).</li>
+<li>Choose a corresponding request handler by detecting the protocol (telnet or http) a request comply with.</li>
+<li>Decode and parse the request to generate corresponding command according to the protocol.</li>
+<li>Execute commands and return with responses.</li>
 </ol>
-<h3>QoS命令</h3>
-<p>QoS目前支持的命令包括:</p>
+<h3>QoS Commands:</h3>
+<p>Commands that QoS supports at the current moment include:</p>
 <ul>
-<li>help: 帮助命令,列出</li>
-<li>ls: 列出当前所有的正在提供的服务,以及消费的服务</li>
-<li>online: 动态将某个或全部服务向注册中心进行注册</li>
-<li>offline: 动态将某个或全部服务从注册中心摘除(反注册)</li>
-<li>quit: 退出当前telnet会话</li>
+<li><code>help</code>, list available commands</li>
+<li><code>ls</code>: list all active provider services and consumer services</li>
+<li><code>online</code>: dynamically register a service or all services to registration center</li>
+<li><code>offline</code>: dynamically remove (unregister) a services or all services from registration center</li>
+<li><code>quit</code>: quit the current telnet session</li>
 </ul>
-<p>下面,我们具体来操作一下如何通过用QoS对服务进行动态控制。</p>
-<h4>通过Telnet方式访问QoS</h4>
-<p>假设我们的Dubbo服务端已经启动,我们通过Telnet方式进行连接:</p>
-<pre><code>$ telnet localhost 22222
+<p>Now we are going to demonstrate how to manipulate services dynamically via QoS.</p>
+<h4>Access QoS via Telnet</h4>
+<p>Assuming that our Dubbo server has started, connect to it via telnet:</p>
+<pre><code class="language-shell"><span class="hljs-meta">$</span><span class="bash"> telnet localhost 22222</span>
 Trying 127.0.0.1...
 Connected to localhost.
 Escape character is '^]'.
@@ -52,14 +52,14 @@ Escape character is '^]'.
   ???    ??? ???    ???   ???    ???   ???    ??? ???    ???
   ???   ???? ???    ???   ???    ???   ???    ??? ???    ???
   ?????????  ?????????  ???????????  ???????????   ????????
+<span class="hljs-meta">
 
-
-dubbo&gt;
+dubbo&gt;</span><span class="bash"></span>
 </code></pre>
-<p>连接成功后,会出现<code>dubbo&gt;</code>提示符,此时输入<code>help</code>命令</p>
-<pre><code>dubbo&gt;help
+<p>A <code>dubbo&gt;</code> prompt would show up once you connect to server. Now input <code>help</code>:</p>
+<pre><code class="language-sh">dubbo&gt;<span class="hljs-built_in">help</span>
 +---------+----------------------------------------------------------------------------------+
-|    help | help command                                                                     |
+|    <span class="hljs-built_in">help</span> | <span class="hljs-built_in">help</span> <span class="hljs-built_in">command</span>                                                                     |
 +---------+----------------------------------------------------------------------------------+
 |      ls | ls service                                                                       |
 +---------+----------------------------------------------------------------------------------+
@@ -72,9 +72,9 @@ dubbo&gt;
 
 dubbo&gt;
 </code></pre>
-<p>会列出当前所有可用的命令,及相应的说明。</p>
-<p>也可以对单个命令进行help操作,可以看到该命令对应的示例</p>
-<pre><code>dubbo&gt;help online
+<p>This command lists all available commands with explanations.</p>
+<p>You can also use <code>help</code> to a specific command to read examples of that command.</p>
+<pre><code class="language-sh">dubbo&gt;<span class="hljs-built_in">help</span> online
 +--------------+----------------------------------------------------------------------------------+
 | COMMAND NAME | online                                                                           |
 +--------------+----------------------------------------------------------------------------------+
@@ -82,8 +82,8 @@ dubbo&gt;
 |              | online xx.xx.xxx.service                                                         |
 +--------------+----------------------------------------------------------------------------------+
 </code></pre>
-<p>通过<code>ls</code> 查看当前的服务状态</p>
-<pre><code>dubbo&gt;ls
+<p>Use <code>ls</code> to check services' status:</p>
+<pre><code class="language-sh">dubbo&gt;ls
 As Provider side:
 +------------------------------------------+---+
 |           Provider Service Name          |PUB|
@@ -95,13 +95,13 @@ As Consumer side:
 |Consumer Service Name|NUM|
 +---------------------+---+
 </code></pre>
-<p>可以看到,在服务端可以看到一个服务<code>org.apache.dubbo.demo.provider.DemoService</code>,第二列里面的<code>PUB=Y</code>代表改服务已经发布到注册中心,可供消费端进行调用。</p>
-<p>假设我们需要动态的对该服务进行下线操作,可以通过<code>offline</code>命令来完成</p>
+<p>There is a service named <code>org.apache.dubbo.demo.provider.DemoService</code> in the provider side. <code>PUB=Y</code> in the second columns means that the service has been published to the registration center, waiting to be called by the consumer side.</p>
+<p>Assuming that we need to withdraw a service dynamically, we can use <code>offline</code> command:</p>
 <pre><code>dubbo&gt;offline org.apache.dubbo.demo.provider.DemoService
 OK
 </code></pre>
-<p>可以看到命令返回了OK,我们再通过ls看下当前的状态:</p>
-<pre><code>dubbo&gt;ls
+<p>You can see that the command responds with <code>OK</code>. Check the services' status using <code>ls</code>:</p>
+<pre><code class="language-sh">dubbo&gt;ls
 As Provider side:
 +------------------------------------------+---+
 |           Provider Service Name          |PUB|
@@ -113,25 +113,25 @@ As Consumer side:
 |Consumer Service Name|NUM|
 +---------------------+---+
 </code></pre>
-<p>可以看到<code>org.apache.dubbo.demo.provider.DemoService</code>的<code>PUB</code>已经被设置成了<code>N</code>。</p>
-<p>通过<code>quit</code>命令退出当前的telnet会话:</p>
-<pre><code>dubbo&gt;quit
+<p>You can see that <code>PUB</code> of <code>org.apache.dubbo.demo.provider.DemoService</code> has been set to <code>N</code>.</p>
+<p>Quit the current telnet session using <code>quit</code>:</p>
+<pre><code class="language-sh">dubbo&gt;quit
 BYE!
 Connection closed by foreign host.
 </code></pre>
-<h4>通过HTTP方式访问QOS</h4>
-<p>在上面的例子中,我们已经对<code>org.apache.dubbo.demo.provider.DemoService</code>进行了下线操作,下面,我们通过对Http方式对上面的服务进行注册操作:</p>
-<pre><code>$ curl -i http://localhost:22222/online?service=org.apache.dubbo.demo.provider.DemoService
+<h4>Access QoS via HTTP</h4>
+<p>In the example above we performed an offline action to <code>org.apache.dubbo.demo.provider.DemoService</code>. Now we are going to demonstrate how to register the service above via HTTP.</p>
+<pre><code class="language-sh">$ curl -i http://localhost:22222/online?service=org.apache.dubbo.demo.provider.DemoService
 HTTP/1.1 200 OK
 Content-Type: text/plain
 Content-Length: 2
 
-OK% 
+OK%
 </code></pre>
 <blockquote>
-<p>注意online操作对应的参数,需要以<code>key=value</code>的形式提供,但实际上key会被忽略</p>
+<p>Beware of the parameters of online action. They need to be provided in the form of <code>key=value</code>. However, <code>key</code> would be ignored actually.</p>
 </blockquote>
-<p>看到操作返回了OK,下面通过ls命令查看下当前的状态</p>
+<p>The action responds with <code>OK</code>. Now use <code>ls</code> to check providers' status at the current moment.</p>
 <pre><code>$ curl -i http://localhost:22222/ls
 HTTP/1.1 200 OK
 Content-Type: text/plain
@@ -148,59 +148,59 @@ As Consumer side:
 |Consumer Service Name|NUM|
 +---------------------+---+
 </code></pre>
-<p>可以看到服务的<code>PUB</code>状态已经变成了<code>Y</code>。</p>
-<h3>QoS相关参数说明</h3>
-<p>QoS提供了一些启动参数,来对启动进行配置,他们主要包括:</p>
+<p>You can see that the service's <code>PUB</code> status has been changed to <code>Y</code>.</p>
+<h3>QoS' Parameters</h3>
+<p>You can use parameters that QoS provides to config its startup. These parameters include:</p>
 <table>
 <thead>
 <tr>
-<th>参数</th>
-<th>说明</th>
-<th>默认值</th>
+<th>Parameter</th>
+<th>Explanation</th>
+<th>Default</th>
 </tr>
 </thead>
 <tbody>
 <tr>
 <td>qosEnable</td>
-<td>是否启动QoS</td>
+<td>Activate QoS or not</td>
 <td>true</td>
 </tr>
 <tr>
 <td>qosPort</td>
-<td>启动QoS绑定的端口</td>
+<td>The port QoS would bind to</td>
 <td>22222</td>
 </tr>
 <tr>
 <td>qosAcceptForeignIp</td>
-<td>是否允许远程访问</td>
+<td>Enable remote access or not</td>
 <td>false</td>
 </tr>
 </tbody>
 </table>
 <blockquote>
-<p>注意,从2.6.4/2.7.0开始,qosAcceptForeignIp默认配置改为false,如果qosAcceptForeignIp设置为true,有可能带来安全风险,请仔细评估后再打开。</p>
+<p>Attention. From 2.6.4/2.7.0, <code>qosAcceptForeignIp</code> is set to <code>false</code> by default, because it's risky if this property is set to <code>true</code>. Think twice before you turn it on.</p>
 </blockquote>
-<p>QoS参数可以通过如下方式进行配置</p>
+<p>You can configure these parameters in the following ways:</p>
 <ul>
-<li>系统属性</li>
-<li>dubbo.properties</li>
-<li>XML方式</li>
-<li>Spring-boot自动装配方式</li>
+<li>System property</li>
+<li><code>dubbo.properties</code></li>
+<li>XML</li>
+<li>Spring-boot auto configuration</li>
 </ul>
-<p>其中,上述方式的优先顺序为系统属性 &gt; dubbo.properties &gt; XML/Spring-boot自动装配方式。</p>
-<h4>使用系统属性方式进行配置</h4>
+<p>They have priority in the following order: system property &gt; <code>dubbo.properties</code> &gt; XML &gt; spring-boot.</p>
+<h4>System Property</h4>
 <pre><code>-Ddubbo.application.qos.enable=true
 -Ddubbo.application.qos.port=33333
 -Ddubbo.application.qos.accept.foreign.ip=false
 </code></pre>
-<h4>使用dubbo.properties文件进行配置</h4>
-<p>在项目的<code>src/main/resources</code>目录下添加dubbo.properties文件,内容如下:</p>
+<h4><code>Dubbo.properties</code></h4>
+<p>Create a <code>dubbo.properties</code> file in this directory <code>src/main/resources</code> in your project, and copy the following codes into it:</p>
 <pre><code>dubbo.application.qos.enable=true
 dubbo.application.qos.port=33333
 dubbo.application.qos.accept.foreign.ip=false
 </code></pre>
-<h4>使用XML方法进行配置</h4>
-<p>如果要通过XML配置响应的QoS相关的参数,可以进行如下配置:</p>
+<h4>XML</h4>
+<p>If you are going to config using XML, you can try this:</p>
 <pre><code class="language-xml"><span class="php"><span class="hljs-meta">&lt;?</span>xml version=<span class="hljs-string">"1.0"</span> encoding=<span class="hljs-string">"UTF-8"</span><span class="hljs-meta">?&gt;</span></span>
 <span class="hljs-tag">&lt;<span class="hljs-name">beans</span> <span class="hljs-attr">xmlns</span>=<span class="hljs-string">"http://www.springframework.org/schema/beans"</span>
        <span class="hljs-attr">xmlns:xsi</span>=<span class="hljs-string">"http://www.w3.org/2001/XMLSchema-instance"</span>
@@ -219,13 +219,13 @@ dubbo.application.qos.accept.foreign.ip=false
   <span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"demoService"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"org.apache.dubbo.demo.provider.DemoServiceImpl"</span>/&gt;</span>
 <span class="hljs-tag">&lt;/<span class="hljs-name">beans</span>&gt;</span>
 </code></pre>
-<h4>使用spring-boot自动装配方式配置</h4>
-<p>如果是spring-boot的应用,可以在<code>application.properties</code>或者<code>application.yml</code>上配置:</p>
+<h4><code>spring-boot</code> auto configuration</h4>
+<p>If you are developing a spring-boot application, you can configure in <code>application.properties</code> or <code>application.yml</code>:</p>
 <pre><code>dubbo.application.qosEnable=true
 dubbo.application.qosPort=33333
 dubbo.application.qosAcceptForeignIp=false
 </code></pre>
-</section><footer class="footer-container" data-reactid="19"><div class="footer-body" data-reactid="20"><img src="/img/dubbo_gray.png" data-reactid="21"/><img class="apache" src="/img/apache_logo.png" data-reactid="22"/><div class="cols-container" data-reactid="23"><div class="col col-12" data-reactid="24"><h3 data-reactid="25">Disclaimer</h3><p data-reactid="26">Apache Dubbo is an effort undergoing incubation at The Apache Software Foundation (ASF), sponsored by the Incubator. Incubatio [...]
+</section><footer class="footer-container" data-reactid="19"><div class="footer-body" data-reactid="20"><img src="/img/dubbo_gray.png" data-reactid="21"/><img class="apache" src="/img/apache_logo.png" data-reactid="22"/><div class="cols-container" data-reactid="23"><div class="col col-12" data-reactid="24"><h3 data-reactid="25">Disclaimer</h3><p data-reactid="26">Apache Dubbo is an effort undergoing incubation at The Apache Software Foundation (ASF), sponsored by the Incubator. Incubatio [...]
 	<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>
diff --git a/en-us/blog/introduction-to-dubbo-qos.json b/en-us/blog/introduction-to-dubbo-qos.json
new file mode 100644
index 0000000..c6c5222
--- /dev/null
+++ b/en-us/blog/introduction-to-dubbo-qos.json
@@ -0,0 +1,4 @@
+{
+  "filename": "introduction-to-dubbo-qos.md",
+  "__html": "<h1>Manipulating Services Dynamically via QoS</h1>\n<p>QoS (short form of <strong>Quality of Service</strong>), is a common terminology talking about network devices. For example, by adjusting and manipulating the weights of ports of a router dynamically via QoS, engineers could give priority to services running on these ports and make sure these services' quality and reliability.</p>\n<p>In Dubbo, QoS is used to query and manipulate services dynamically, like getting a list [...]
+}
\ No newline at end of file
diff --git a/zh-cn/blog/spring-boot-dubbo-start-stop-analysis.html b/en-us/blog/spring-boot-dubbo-start-stop-analysis.html
similarity index 50%
copy from zh-cn/blog/spring-boot-dubbo-start-stop-analysis.html
copy to en-us/blog/spring-boot-dubbo-start-stop-analysis.html
index 2eba8a3..bf3adb0 100644
--- a/zh-cn/blog/spring-boot-dubbo-start-stop-analysis.html
+++ b/en-us/blog/spring-boot-dubbo-start-stop-analysis.html
@@ -12,15 +12,15 @@
 	<link rel="stylesheet" href="/build/blogDetail.css" />
 </head>
 <body>
-	<div id="root"><div class="blog-detail-page" data-reactroot="" data-reactid="1" data-react-checksum="68597831"><header class="header-container header-container-normal" data-reactid="2"><div class="header-body" data-reactid="3"><a href="/zh-cn/index.html" data-reactid="4"><img class="logo" src="/img/dubbo_colorful.png" data-reactid="5"/></a><span class="language-switch language-switch-normal" data-reactid="6">En</span><div class="header-menu" data-reactid="7"><img class="header-menu-togg [...]
-<h3>背景介绍</h3>
-<p><a href="https://github.com/apache/incubator-dubbo-spring-boot-project">Dubbo Spring Boot</a> 工程致力于简化 Dubbo RPC 框架在Spring Boot应用场景的开发。同时也整合了 Spring Boot 特性:</p>
+	<div id="root"><div class="blog-detail-page" data-reactroot="" data-reactid="1" data-react-checksum="-194004511"><header class="header-container header-container-normal" data-reactid="2"><div class="header-body" data-reactid="3"><a href="/en-us/index.html" data-reactid="4"><img class="logo" src="/img/dubbo_colorful.png" data-reactid="5"/></a><span class="language-switch language-switch-normal" data-reactid="6">中</span><div class="header-menu" data-reactid="7"><img class="header-menu-tog [...]
+<h3>Introduction</h3>
+<p><a href="https://github.com/apache/incubator-dubbo-spring-boot-project">Dubbo Spring Boot</a> project is dedicated to simplifying the development of the Dubbo RPC framework in the Spring Boot application. It also integrates the feature of Spring Boot:</p>
 <ul>
-<li><a href="https://github.com/apache/incubator-dubbo-spring-boot-project/blob/master/dubbo-spring-boot-autoconfigure">自动装配</a> (比如: 注解驱动, 自动装配等).</li>
-<li><a href="https://github.com/apache/incubator-dubbo-spring-boot-project/blob/master/dubbo-spring-boot-actuator">Production-Ready</a> (比如: 安全, 健康检查, 外部化配置等).</li>
+<li><a href="https://github.com/apache/incubator-dubbo-spring-boot-project/blob/master/dubbo-spring-boot-autoconfigure">Autoconfigure</a> (ex: Annotation driver, Autoconfigure, etc.)</li>
+<li><a href="https://github.com/apache/incubator-dubbo-spring-boot-project/blob/master/dubbo-spring-boot-actuator">Production-Ready</a> (ex: Security, Healthy check, Externalize configuration, etc.)</li>
 </ul>
-<h3>DubboConsumer启动分析</h3>
-<p>你有没有想过一个问题?<code>incubator-dubbo-spring-boot-project</code>中的<code>DubboConsumerDemo</code>应用就一行代码,<code>main</code>方法执行完之后,为什么不会直接退出呢?</p>
+<h3>The analysis of DubboConsumer startup</h3>
+<p>Have you ever thought about this : since the <code>DubboConsumerDemo</code> application in <code>incubator-dubbo-spring-boot-project</code> has only one line of code, why not just exit directly when the <code>main</code> method is executed?</p>
 <pre><code class="language-java"><span class="hljs-meta">@SpringBootApplication</span>(scanBasePackages = <span class="hljs-string">"com.alibaba.boot.dubbo.demo.consumer.controller"</span>)
 <span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DubboConsumerDemo</span> </span>{
 
@@ -30,19 +30,16 @@
 
 }
 </code></pre>
-<p>其实要回答这样一个问题,我们首先需要把这个问题进行一个抽象,即一个JVM进程,在什么情况下会退出?</p>
-<p>以Java 8为例,通过查阅JVM语言规范[1],在12.8章节中有清晰的描述:</p>
+<p>In fact, to answer this question, we need to abstract it first, that is, under what circumstances will a JVM process exit?</p>
+<p>Take Java 8 as an example. By referring to the JVM language specification[1], there is a clear description in Section 12.8:</p>
+<blockquote>
 <p>A program terminates all its activity and <em>exits</em> when one of two things happens:</p>
 <ul>
 <li>All the threads that are not daemon threads terminate.</li>
 <li>Some thread invokes the <code>exit</code> method of class <code>Runtime</code> or class <code>System</code>, and the <code>exit</code> operation is not forbidden by the security manager.</li>
 </ul>
-<p>也就是说,导致JVM的退出只有2种情况:</p>
-<ol>
-<li>所有的非daemon进程完全终止</li>
-<li>某个线程调用了<code>System.exit()</code>或<code>Runtime.exit()</code></li>
-</ol>
-<p>因此针对上面的情况,我们判断,一定是有某个非daemon线程没有退出导致。我们知道,通过jstack可以看到所有的线程信息,包括他们是否是daemon线程,可以通过jstack找出那些是非deamon的线程。</p>
+</blockquote>
+<p>Therefore, in view of the above situation, we judge that there must be some non-daemon thread not exiting. All thread information can be seen by <code>jstack</code>, including whether they are daemon threads, and <code>jstack</code> can be used to find out which threads are non-daemon.</p>
 <pre><code class="language-sh">➜  jstack 57785 | grep tid | grep -v <span class="hljs-string">"daemon"</span>
 <span class="hljs-string">"container-0"</span> <span class="hljs-comment">#37 prio=5 os_prio=31 tid=0x00007fbe312f5800 nid=0x7103 waiting on condition  [0x0000700010144000]</span>
 <span class="hljs-string">"container-1"</span> <span class="hljs-comment">#49 prio=5 os_prio=31 tid=0x00007fbe3117f800 nid=0x7b03 waiting on condition  [0x0000700010859000]</span>
@@ -63,31 +60,31 @@
 
 </code></pre>
 <blockquote>
-<p>此处通过grep tid 找出所有的线程摘要,通过grep -v找出不包含daemon关键字的行</p>
+<p>We can find all the thread digests by <code>grep tid</code> here, and find the line that doesn't contain the daemon keyword by <code>grep -v</code> command.</p>
 </blockquote>
-<p>通过上面的结果,我们发现了一些信息:</p>
+<p>We can get some information from the above results:</p>
 <ul>
-<li>有两个线程<code>container-0</code>, <code>container-1</code>非常可疑,他们是非daemon线程,处于wait状态</li>
-<li>有一些GC相关的线程,和VM打头的线程,也是非daemon线程,但他们很有可能是JVM自己的线程,在此暂时忽略。</li>
+<li>There are two &quot;suspicious&quot; threads : <code>container-0</code>, <code>container-1</code>. They are non-daemon thread in wait state.</li>
+<li>There are alse some threads about GC, and threads that start with <code>VM</code>. They are also some non-daemon threads, but they are most likely the JVM's own threads, which we can ignore for now.</li>
 </ul>
-<p>综上,我们可以推断,很可能是因为<code>container-0</code>和<code>container-1</code>导致JVM没有退出。现在我们通过源码,搜索一下到底是谁创建的这两个线程。</p>
-<p>通过对spring-boot的源码分析,我们在<code>org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainer</code>的<code>startDaemonAwaitThread</code>找到了如下代码</p>
-<pre><code class="language-java">	<span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">startDaemonAwaitThread</span><span class="hljs-params">()</span> </span>{
-		Thread awaitThread = <span class="hljs-keyword">new</span> Thread(<span class="hljs-string">"container-"</span> + (containerCounter.get())) {
+<p>In summary, we can infer that it is likely that the <code>container-0</code> and <code>container-1</code> cause the JVM to not exit. Now let's search through the source code to find out who created the two threads.</p>
+<p>By the source code analysis of Spring-boot, we can find these code in the <code>startDaemonAwaitThread</code> method of <code>org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainer</code>.</p>
+<pre><code class="language-java">    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">startDaemonAwaitThread</span><span class="hljs-params">()</span> </span>{
+        Thread awaitThread = <span class="hljs-keyword">new</span> Thread(<span class="hljs-string">"container-"</span> + (containerCounter.get())) {
 
-			<span class="hljs-meta">@Override</span>
-			<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">run</span><span class="hljs-params">()</span> </span>{
-				TomcatEmbeddedServletContainer.<span class="hljs-keyword">this</span>.tomcat.getServer().await();
-			}
+            <span class="hljs-meta">@Override</span>
+            <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">run</span><span class="hljs-params">()</span> </span>{
+                TomcatEmbeddedServletContainer.<span class="hljs-keyword">this</span>.tomcat.getServer().await();
+            }
 
-		};
-		awaitThread.setContextClassLoader(getClass().getClassLoader());
-		awaitThread.setDaemon(<span class="hljs-keyword">false</span>);
-		awaitThread.start();
-	}
+        };
+        awaitThread.setContextClassLoader(getClass().getClassLoader());
+        awaitThread.setDaemon(<span class="hljs-keyword">false</span>);
+        awaitThread.start();
+    }
 </code></pre>
-<p>在这个方法加个断点,看下调用堆栈:</p>
-<pre><code>initialize:115, TomcatEmbeddedServletContainer (org.springframework.boot.context.embedded.tomcat)
+<p>Let's add a breakpoint in this method, and focus on the call stack:</p>
+<pre><code class="language-plain">initialize:115, TomcatEmbeddedServletContainer (org.springframework.boot.context.embedded.tomcat)
 &lt;init&gt;:84, TomcatEmbeddedServletContainer (org.springframework.boot.context.embedded.tomcat)
 getTomcatEmbeddedServletContainer:554, TomcatEmbeddedServletContainerFactory (org.springframework.boot.context.embedded.tomcat)
 getEmbeddedServletContainer:179, TomcatEmbeddedServletContainerFactory (org.springframework.boot.context.embedded.tomcat)
@@ -102,10 +99,10 @@ run:1118, SpringApplication (org.springframework.boot)
 run:1107, SpringApplication (org.springframework.boot)
 main:35, DubboConsumerDemo (com.alibaba.boot.dubbo.demo.consumer.bootstrap)
 </code></pre>
-<p>可以看到,spring-boot应用在启动的过程中,由于默认启动了Tomcat暴露HTTP服务,所以执行到了上述方法,而Tomcat启动的所有的线程,默认都是daemon线程,例如监听请求的Acceptor,工作线程池等等,如果这里不加控制的话,启动完成之后JVM也会退出。因此需要显示的启动一个线程,在某个条件下进行持续等待,从而避免线程退出。</p>
-<p>下面我们在深挖一下,在Tomcat的<code>this.tomcat.getServer().await()</code>这个方法中,线程是如何实现不退出的。这里为了阅读方便,去掉了不相关的代码。</p>
+<p>It can be seen that during the startup process of the Spring-boot application, the above method is executed since the execution of Tomcat exposes the HTTP service by default. Also, all threads started by Tomcat are daemon threads by default, such as the Acceptor of the listening request, threads in working threads, etc. Thus the JVM will also exit after the startup is complete in there is no extra control here. Therefore, it is necessary to explicitly start a thread and continue to wa [...]
+<p>Let's dig deeper to find out how the thread stay alive in Tomcat's <code>this.tomcat.getServer().await()</code> method.</p>
 <pre><code class="language-java"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">await</span><span class="hljs-params">()</span> </span>{
-    	<span class="hljs-comment">// ...</span>
+        <span class="hljs-comment">// ...</span>
         <span class="hljs-keyword">if</span>( port==-<span class="hljs-number">1</span> ) {
             <span class="hljs-keyword">try</span> {
                 awaitThread = Thread.currentThread();
@@ -121,19 +118,19 @@ main:35, DubboConsumerDemo (com.alibaba.boot.dubbo.demo.consumer.bootstrap)
             }
             <span class="hljs-keyword">return</span>;
         }
-		<span class="hljs-comment">// ...</span>
+        <span class="hljs-comment">// ...</span>
     }
 </code></pre>
-<p>在await方法中,实际上当前线程在一个while循环中每10秒检查一次 <code>stopAwait</code>这个变量,它是一个<code>volatile</code>类型变量,用于确保被另一个线程修改后,当前线程能够立即看到这个变化。如果没有变化,就会一直处于while循环中。这就是该线程不退出的原因,也就是整个spring-boot应用不退出的原因。</p>
-<p>因为Springboot应用同时启动了8080和8081(management port)两个端口,实际是启动了两个Tomcat,因此会有两个线程<code>container-0</code>和<code>container-1</code>。</p>
-<p>接下来,我们再看看,这个Spring-boot应用又是如何退出的呢?</p>
-<h3>DubboConsumer退出分析</h3>
-<p>在前面的描述中提到,有一个线程持续的在检查<code>stopAwait</code>这个变量,那么我们自然想到,在Stop的时候,应该会有一个线程去修改<code>stopAwait</code>,打破这个while循环,那又是谁在修改这个变量呢?</p>
-<p>通过对源码分析,可以看到只有一个方法修改了<code>stopAwait</code>,即<code>org.apache.catalina.core.StandardServer#stopAwait</code>,我们在此处加个断点,看看是谁在调用。</p>
+<p>In the await method, the current thread checks the variable <code>stopAwait</code> every 10 seconds in a while loop. It is a <code>volatile</code> variable that is used to ensure that the current thread can see the change immediately after the variable being modified by another thread. If there is no change, it will stay in the loop. This is the reason why the thread does not exit, which is also the reason that the entire Spring-boot application doesn't exit.</p>
+<p>Since Spring-boot application enables port 8080 and 8081(management port) at the same time, there are actually two Tomcats. So there are two threads named <code>container-0</code> and <code>container-1</code>.</p>
+<p>Next, let's see how this Spring-boot application exits.</p>
+<h3>The analysis of DubboConsumer exit</h3>
+<p>As mentioned in the previous description, there is a thread that checks the variable <code>stopAwait</code> continuously. So there must be a thread to modify <code>stopAwait</code> at Stop, thus break the while loop. But who is modifying this variable?</p>
+<p>By analyzing the source code, we can see that there is only one method that modifies <code>stopAwait</code> : <code>org.apache.catalina.core.StandardServer#stopAwait</code>. To figure out who is calling this method, we add a breakpoint here.</p>
 <blockquote>
-<p>注意,当我们在Intellij IDEA的Debug模式,加上一个断点后,需要在命令行下使用<code>kill -s INT $PID</code>或者<code>kill -s TERM $PID</code>才能触发断点,点击IDE上的Stop按钮,不会触发断点。这是IDEA的bug</p>
+<p>Note that after adding a breakpoint in Intellij IDEA's Debug mode, we also need to type <code>kill -s INT $PID</code> or <code>kill -s TERM $PID</code> in command line to trigger the breakpoint. Due to buggy IDEA, a single click to the stop button won't trigger the breakpoint.</p>
 </blockquote>
-<p>可以看到有一个名为<code>Thread-3</code>的线程调用了该方法:</p>
+<p>You can see the method is called by a thread called <code>Thread-3</code>:</p>
 <pre><code class="language-java">stopAwait:<span class="hljs-number">390</span>, StandardServer (org.apache.catalina.core)
 stopInternal:<span class="hljs-number">819</span>, StandardServer (org.apache.catalina.core)
 stop:<span class="hljs-number">226</span>, LifecycleBase (org.apache.catalina.util)
@@ -145,24 +142,24 @@ onClose:<span class="hljs-number">155</span>, EmbeddedWebApplicationContext (org
 doClose:<span class="hljs-number">1014</span>, AbstractApplicationContext (org.springframework.context.support)
 run:<span class="hljs-number">929</span>, AbstractApplicationContext$<span class="hljs-number">2</span> (org.springframework.context.support)
 </code></pre>
-<p>通过源码分析,原来是通过Spring注册的<code>ShutdownHook</code>来执行的</p>
-<pre><code class="language-java">	<span class="hljs-meta">@Override</span>
-	<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">registerShutdownHook</span><span class="hljs-params">()</span> </span>{
-		<span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.shutdownHook == <span class="hljs-keyword">null</span>) {
-			<span class="hljs-comment">// No shutdown hook registered yet.</span>
-			<span class="hljs-keyword">this</span>.shutdownHook = <span class="hljs-keyword">new</span> Thread() {
-				<span class="hljs-meta">@Override</span>
-				<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">run</span><span class="hljs-params">()</span> </span>{
-					<span class="hljs-keyword">synchronized</span> (startupShutdownMonitor) {
-						doClose();
-					}
-				}
-			};
-			Runtime.getRuntime().addShutdownHook(<span class="hljs-keyword">this</span>.shutdownHook);
-		}
-	}
+<p>Through source code analysis, it was executed by Spring's registered <code>ShutdownHook</code>.</p>
+<pre><code class="language-java">    <span class="hljs-meta">@Override</span>
+    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">registerShutdownHook</span><span class="hljs-params">()</span> </span>{
+        <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.shutdownHook == <span class="hljs-keyword">null</span>) {
+            <span class="hljs-comment">// No shutdown hook registered yet.</span>
+            <span class="hljs-keyword">this</span>.shutdownHook = <span class="hljs-keyword">new</span> Thread() {
+                <span class="hljs-meta">@Override</span>
+                <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">run</span><span class="hljs-params">()</span> </span>{
+                    <span class="hljs-keyword">synchronized</span> (startupShutdownMonitor) {
+                        doClose();
+                    }
+                }
+            };
+            Runtime.getRuntime().addShutdownHook(<span class="hljs-keyword">this</span>.shutdownHook);
+        }
+    }
 </code></pre>
-<p>通过查阅Java的API文档[2], 我们可以知道ShutdownHook将在下面两种情况下执行</p>
+<p>By reffering the Java API documentation[2], we found that ShutdownHook will be executed under the following two cases.</p>
 <blockquote>
 <p>The Java virtual machine <em>shuts down</em> in response to two kinds of events:</p>
 <ul>
@@ -171,19 +168,19 @@ run:<span class="hljs-number">929</span>, AbstractApplicationContext$<span class
 </ul>
 </blockquote>
 <ol>
-<li>调用了System.exit()方法</li>
-<li>响应外部的信号,例如Ctrl+C(其实发送的是SIGINT信号),或者是<code>SIGTERM</code>信号(默认<code>kill $PID</code>发送的是<code>SIGTERM</code>信号)</li>
+<li>So it's either a call of <code>System.exit()</code></li>
+<li>Respond to external signals, such as Ctrl+C(actually sent as SIGINT signal), or <code>SIGTERM</code> signal (<code>kill $PID</code> will send <code>SIGTERM</code> signal by default)</li>
 </ol>
-<p>因此,正常的应用在停止过程中(<code>kill -9 $PID</code>除外),都会执行上述ShutdownHook,它的作用不仅仅是关闭tomcat,还有进行其他的清理工作,在此不再赘述。</p>
-<h3>总结</h3>
+<p>Therefore, the normal application will execute the above ShutdownHook during the stop process (except <code>kill -9 $PID</code>). Its function is not only to close the Tomcat, but also to perform other cleanup work. It is unnecessary to go into details.</p>
+<h3>Summary</h3>
 <ol>
-<li>在<code>DubboConsumer</code>启动的过程中,通过启动一个独立的非daemon线程循环检查变量的状态,确保进程不退出</li>
-<li>在<code>DubboConsumer</code>停止的过程中,通过执行spring容器的shutdownhook,修改了变量的状态,使得程序正常退出</li>
+<li>During the startup of <code>DubboConsumer</code>, an independent non-daemon thread is launched to query the status of the variable continuously, thus the process can't exit.</li>
+<li>To stop the <code>DubboConsumer</code>, one should call ShutdownHook to change the variable to let the thread break the loop.</li>
 </ol>
-<h3>问题</h3>
-<p>在DubboProvider的例子中,我们看到Provider并没有启动Tomcat提供HTTP服务,那又是如何实现不退出的呢?我们将在下一篇文章中回答这个问题。</p>
-<h4>彩蛋</h4>
-<p>在<code>Intellij IDEA</code>中运行了如下的单元测试,创建一个线程执行睡眠1000秒的操作,我们惊奇的发现,代码并没有线程执行完就退出了,这又是为什么呢?(被创建的线程是非daemon线程)</p>
+<h3>Problems</h3>
+<p>In the example of DubboProvider, we see that Provider doesn't start Tomcat to provide HTTP service, then how does the program stays alive without exiting? We will answer this question in the next article.</p>
+<h4>Notice</h4>
+<p>By running the following unit test which create a thread in <code>Intellij IDEA</code> , we are surprised to find that the program exits with less than 1000s. Why?(The thread being created is a non-daemon thread)</p>
 <pre><code class="language-java">    <span class="hljs-meta">@Test</span>
     <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">test</span><span class="hljs-params">()</span> </span>{
         <span class="hljs-keyword">new</span> Thread(<span class="hljs-keyword">new</span> Runnable() {
@@ -200,7 +197,7 @@ run:<span class="hljs-number">929</span>, AbstractApplicationContext$<span class
 </code></pre>
 <p>[1] <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-12.html#jls-12.8">https://docs.oracle.com/javase/specs/jls/se8/html/jls-12.html#jls-12.8</a></p>
 <p>[2] <a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Runtime.html#addShutdownHook">https://docs.oracle.com/javase/8/docs/api/java/lang/Runtime.html#addShutdownHook</a></p>
-</section><footer class="footer-container" data-reactid="19"><div class="footer-body" data-reactid="20"><img src="/img/dubbo_gray.png" data-reactid="21"/><img class="apache" src="/img/apache_logo.png" data-reactid="22"/><div class="cols-container" data-reactid="23"><div class="col col-12" data-reactid="24"><h3 data-reactid="25">Disclaimer</h3><p data-reactid="26">Apache Dubbo is an effort undergoing incubation at The Apache Software Foundation (ASF), sponsored by the Incubator. Incubatio [...]
+</section><footer class="footer-container" data-reactid="19"><div class="footer-body" data-reactid="20"><img src="/img/dubbo_gray.png" data-reactid="21"/><img class="apache" src="/img/apache_logo.png" data-reactid="22"/><div class="cols-container" data-reactid="23"><div class="col col-12" data-reactid="24"><h3 data-reactid="25">Disclaimer</h3><p data-reactid="26">Apache Dubbo is an effort undergoing incubation at The Apache Software Foundation (ASF), sponsored by the Incubator. Incubatio [...]
 	<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>
diff --git a/en-us/blog/spring-boot-dubbo-start-stop-analysis.json b/en-us/blog/spring-boot-dubbo-start-stop-analysis.json
new file mode 100644
index 0000000..a448956
--- /dev/null
+++ b/en-us/blog/spring-boot-dubbo-start-stop-analysis.json
@@ -0,0 +1,4 @@
+{
+  "filename": "spring-boot-dubbo-start-stop-analysis.md",
+  "__html": "<h1>Source code analysis of spring-boot+Dubbo App start and stop</h1>\n<h3>Introduction</h3>\n<p><a href=\"https://github.com/apache/incubator-dubbo-spring-boot-project\">Dubbo Spring Boot</a> project is dedicated to simplifying the development of the Dubbo RPC framework in the Spring Boot application. It also integrates the feature of Spring Boot:</p>\n<ul>\n<li><a href=\"https://github.com/apache/incubator-dubbo-spring-boot-project/blob/master/dubbo-spring-boot-autoconfigu [...]
+}
\ No newline at end of file
diff --git a/site_config/blog.js b/site_config/blog.js
index 8f98dd6..058e8ae 100644
--- a/site_config/blog.js
+++ b/site_config/blog.js
@@ -3,6 +3,13 @@ export default {
     barText: 'Blog',
     postsTitle: 'All posts',
     list: [
+        {
+          title: 'Source code analysis of spring-boot+Dubbo App start and stop',
+          author: '@noahziheng',
+          dateStr: 'August 14th, 2018',
+          desc: 'Dubbo Spring Boot project is dedicated to simplifying the development of the Dubbo RPC framework in the Spring Boot application.',
+          link: '/en-us/blog/spring-boot-dubbo-start-stop-analysis.html',
+        },
       {
         title: 'Dubbo Loadbalance',
         author: '@CyanCity, @liaoandi',
@@ -67,7 +74,7 @@ export default {
         link: '/en-us/blog/introduction-to-dubbo-qos.html',
       },
       {
-        title: 'Use anntation in Dubbo',
+        title: 'Use annotation in Dubbo',
         author: 'Ge Shao',
         dateStr: 'August 7nd,2018',
         desc: 'This blog introduces how to use annotations',
diff --git a/zh-cn/blog/dubbo-loadbalance.html b/zh-cn/blog/dubbo-loadbalance.html
index 9c1fa1a..a847ab5 100644
--- a/zh-cn/blog/dubbo-loadbalance.html
+++ b/zh-cn/blog/dubbo-loadbalance.html
@@ -12,39 +12,39 @@
 	<link rel="stylesheet" href="/build/blogDetail.css" />
 </head>
 <body>
-	<div id="root"><div class="blog-detail-page" data-reactroot="" data-reactid="1" data-react-checksum="1435217025"><header class="header-container header-container-normal" data-reactid="2"><div class="header-body" data-reactid="3"><a href="/zh-cn/index.html" data-reactid="4"><img class="logo" src="/img/dubbo_colorful.png" data-reactid="5"/></a><span class="language-switch language-switch-normal" data-reactid="6">En</span><div class="header-menu" data-reactid="7"><img class="header-menu-to [...]
-<h1>背景</h1>
-<p>Dubbo是一个分布式服务框架,能避免单点故障和支持服务的横向扩容。一个服务通常会部署多个实例。如何从多个服务提供者组成的集群中挑选出一个进行调用,就涉及到一个负载均衡的策略。</p>
-<h1>几个概念</h1>
+	<div id="root"><div class="blog-detail-page" data-reactroot="" data-reactid="1" data-react-checksum="-1952568320"><header class="header-container header-container-normal" data-reactid="2"><div class="header-body" data-reactid="3"><a href="/zh-cn/index.html" data-reactid="4"><img class="logo" src="/img/dubbo_colorful.png" data-reactid="5"/></a><span class="language-switch language-switch-normal" data-reactid="6">En</span><div class="header-menu" data-reactid="7"><img class="header-menu-t [...]
+<h2>背景</h2>
+<p>Dubbo是一个分布式服务框架,能避免单点故障和支持服务的横向扩容。一个服务通常会部署多个实例。如何从多个服务 Provider 组成的集群中挑选出一个进行调用,就涉及到一个负载均衡的策略。</p>
+<h2>几个概念</h2>
 <p>在讨论负载均衡之前,我想先解释一下这3个概念。</p>
 <ol>
 <li>负载均衡</li>
 <li>集群容错</li>
 <li>服务路由</li>
 </ol>
-<p>这3个概念容易混淆。他们都描述了怎么从多个Provider中选择一个来进行调用。那他们到底有什么区别呢?下面我来举一个简单的例子,把这几个概念阐述清楚吧。</p>
+<p>这3个概念容易混淆。他们都描述了怎么从多个 Provider 中选择一个来进行调用。那他们到底有什么区别呢?下面我来举一个简单的例子,把这几个概念阐述清楚吧。</p>
 <p>有一个Dubbo的用户服务,在北京部署了10个,在上海部署了20个。一个杭州的服务消费方发起了一次调用,然后发生了以下的事情:</p>
 <ol>
-<li>根据配置的路由规则,如果杭州发起的调用,会路由到比较近的上海的20个Provider。</li>
-<li>根据配置的随机负载均衡策略。在20个Provider中随机选择了一个来调用,假设随机到了第7个Provider。</li>
-<li>结果调用第7个Provider失败了。</li>
+<li>根据配置的路由规则,如果杭州发起的调用,会路由到比较近的上海的20个 Provider。</li>
+<li>根据配置的随机负载均衡策略,在20个 Provider 中随机选择了一个来调用,假设随机到了第7个 Provider。</li>
+<li>结果调用第7个 Provider 失败了。</li>
 <li>根据配置的Failover集群容错模式,重试其他服务器。</li>
-<li>重试了第13个Provider,调用成功。</li>
+<li>重试了第13个 Provider,调用成功。</li>
 </ol>
-<p>上面的第1,2,4步骤就分别对应了路由,负载均衡和集群容错。 Dubbo中,先通过路由,从多个Provider中按照路由规则,选出一个子集。再根据负载均衡从子集中选出一个Provider进行本次调用。如果调用失败了,根据集群容错策略,进行重试或定时重发或快速失败等。 可以看到Dubbo中的路由,负载均衡和集群容错发生在一次RPC调用的不同阶段。最先是路由,然后是负载均衡,最后是集群容错。 本文档只讨论负载均衡,路由和集群容错在其他的文档中进行说明。</p>
-<h1>Dubbo内置负载均衡策略</h1>
+<p>上面的第1,2,4步骤就分别对应了路由,负载均衡和集群容错。 Dubbo中,先通过路由,从多个 Provider 中按照路由规则,选出一个子集。再根据负载均衡从子集中选出一个 Provider 进行本次调用。如果调用失败了,根据集群容错策略,进行重试或定时重发或快速失败等。 可以看到Dubbo中的路由,负载均衡和集群容错发生在一次RPC调用的不同阶段。最先是路由,然后是负载均衡,最后是集群容错。 本文档只讨论负载均衡,路由和集群容错在其他的文档中进行说明。</p>
+<h2>Dubbo内置负载均衡策略</h2>
 <p>Dubbo内置了4种负载均衡策略:</p>
 <ol>
 <li>RandomLoadBalance:随机负载均衡。随机的选择一个。是Dubbo的<strong>默认</strong>负载均衡策略。</li>
 <li>RoundRobinLoadBalance:轮询负载均衡。轮询选择一个。</li>
-<li>LeastActiveLoadBalance:最少活跃调用数,相同活跃数的随机,活跃数指调用前后计数差。使慢的提供者收到更少请求,因为越慢的提供者的调用前后计数差会越大。</li>
+<li>LeastActiveLoadBalance:最少活跃调用数,相同活跃数的随机。活跃数指调用前后计数差。使慢的 Provider 收到更少请求,因为越慢的 Provider 的调用前后计数差会越大。</li>
 <li>ConsistentHashLoadBalance:一致性哈希负载均衡。相同参数的请求总是落在同一台机器上。</li>
 </ol>
 <h3>1.随机负载均衡</h3>
-<p>顾名思义,随机负载均衡策略就是从多个Provider中随机选择一个。但是Dubbo中的随机负载均衡有一个权重的概念,即按照权重设置随机概率。比如说,有10个Provider,并不是说,每个Provider的概率都是一样的,而是要结合这10个provider的权重来分配概率。</p>
-<p>Dubbo中,可以对Provider设置权重。比如机器性能好的,可以设置大一点的权重,性能差的,可以设置小一点的权重。权重会对负载均衡产生影响。可以在Dubbo Admin中对provider进行权重的设置。</p>
+<p>顾名思义,随机负载均衡策略就是从多个 Provider 中随机选择一个。但是 Dubbo 中的随机负载均衡有一个权重的概念,即按照权重设置随机概率。比如说,有10个 Provider,并不是说,每个 Provider 的概率都是一样的,而是要结合这10个 Provider 的权重来分配概率。</p>
+<p>Dubbo中,可以对 Provider 设置权重。比如机器性能好的,可以设置大一点的权重,性能差的,可以设置小一点的权重。权重会对负载均衡产生影响。可以在Dubbo Admin中对 Provider 进行权重的设置。</p>
 <p><strong>基于权重的负载均衡算法</strong></p>
-<p>随机策略会先判断所有的invoker的权重是不是一样的,如果都是一样的,那么处理就比较简单了。使用random.nexInt(length)就可以随机生成一个invoker的序号,根据序号选择对应的invoker。如果没有在Dubbo Admin中对服务提供者设置权重,那么所有的invoker的权重就是一样的,默认是100。 如果权重不一样,那就需要结合权重来设置随机概率了。算法大概如下: 假如有4个invoker</p>
+<p>随机策略会先判断所有的 Invoker 的权重是不是一样的,如果都是一样的,那么处理就比较简单了。使用random.nexInt(length)就可以随机生成一个 Invoker 的序号,根据序号选择对应的 Invoker 。如果没有在Dubbo Admin中对服务 Provider 设置权重,那么所有的 Invoker 的权重就是一样的,默认是100。 如果权重不一样,那就需要结合权重来设置随机概率了。算法大概如下: 假如有4个 Invoker。</p>
 <table>
 <thead>
 <tr>
@@ -75,7 +75,7 @@
 <pre><code>+-----------------------------------------------------------------------------------+
 |          |                    |                    |                              |
 +-----------------------------------------------------------------------------------+
-1          10                   30                   50                             80            
+1          10                   30                   50                             80
 
 |-----A----|---------B----------|----------C---------|---------------D--------------|
 
@@ -86,7 +86,7 @@
 
 -----------------------------------------------------------54
 </code></pre>
-<p>上面的图中一共有4块区域,长度分别是A,B,C和D的权重。使用random.nextInt(10 + 20 + 20 + 30),从80个数中随机选择一个。然后再判断该数分布在哪个区域。比如,如果随机到37,37是分布在C区域的,那么就选择inboker C。15是在B区域,54是在D区域。</p>
+<p>上面的图中一共有4块区域,长度分别是A,B,C和D的权重。使用random.nextInt(10 + 20 + 20 + 30),从80个数中随机选择一个。然后再判断该数分布在哪个区域。比如,如果随机到37,37是分布在C区域的,那么就选择 Invoker C。15是在B区域,54是在D区域。</p>
 <p><strong>随机负载均衡源码</strong></p>
 <p>下面是随机负载均衡的源码,为了方便阅读和理解,我把无关部分都去掉了。</p>
 <pre><code>public class RandomLoadBalance extends AbstractLoadBalance {
@@ -94,12 +94,12 @@
     private final Random random = new Random();
 
     protected &lt;T&gt; Invoker&lt;T&gt; doSelect(List&lt;Invoker&lt;T&gt;&gt; invokers, URL url, Invocation invocation) {
-        int length = invokers.size();      // invoker总数
-        int totalWeight = 0;               // 所有invoker的权重的和
-        
-        // 判断是不是所有的invoker的权重都是一样的
+        int length = invokers.size();      // Invoker 总数
+        int totalWeight = 0;               // 所有 Invoker 的权重的和
+
+        // 判断是不是所有的 Invoker 的权重都是一样的
         // 如果权重都一样,就简单了。直接用Random生成索引就可以了。
-        boolean sameWeight = true; 
+        boolean sameWeight = true;
         for (int i = 0; i &lt; length; i++) {
             int weight = getWeight(invokers.get(i), invocation);
             totalWeight += weight; // Sum
@@ -107,9 +107,9 @@
                 sameWeight = false;
             }
         }
-        
+
         if (totalWeight &gt; 0 &amp;&amp; !sameWeight) {
-            // 如果不是所有的invoker权重都相同,那么基于权重来随机选择。权重越大的,被选中的概率越大
+            // 如果不是所有的 Invoker 权重都相同,那么基于权重来随机选择。权重越大的,被选中的概率越大
             int offset = random.nextInt(totalWeight);
             for (int i = 0; i &lt; length; i++) {
                 offset -= getWeight(invokers.get(i), invocation);
@@ -118,26 +118,26 @@
                 }
             }
         }
-        // 如果所有invoker权重相同
+        // 如果所有 Invoker 权重相同
         return invokers.get(random.nextInt(length));
     }
 }
 </code></pre>
 <h3>2.轮循负载均衡</h3>
-<p>轮询负载均衡,就是依次的调用所有的Provider。和随机负载均衡策略一样,轮询负载均衡策略也有权重的概念。 轮询负载均衡算法可以让RPC调用严格按照我们设置的比例来分配。不管是少量的调用还是大量的调用。但是轮询负载均衡算法也有不足的地方,存在慢的提供者累积请求的问题,比如:第二台机器很慢,但没挂,当请求调到第二台时就卡在那,久而久之,所有请求都卡在调到第二台上,导致整个系统变慢。</p>
+<p>轮询负载均衡,就是依次的调用所有的 Provider。和随机负载均衡策略一样,轮询负载均衡策略也有权重的概念。 轮询负载均衡算法可以让RPC调用严格按照我们设置的比例来分配。不管是少量的调用还是大量的调用。但是轮询负载均衡算法也有不足的地方,存在慢的 Provider 累积请求的问题,比如:第二台机器很慢,但没挂,当请求调到第二台时就卡在那,久而久之,所有请求都卡在调到第二台上,导致整个系统变慢。</p>
 <h3>3.最少活跃调用数负载均衡</h3>
 <p>官方解释:</p>
 <blockquote>
 <p>最少活跃调用数,相同活跃数的随机,活跃数指调用前后计数差,使慢的机器收到更少。</p>
 </blockquote>
-<p>这个解释好像说的不是太明白。知道了目的是让慢的机器收到更少,但具体怎么实现的还是不太清楚。让我来举个例子吧: 例如,每个服务维护一个活跃数计数器。当A机器开始处理请求,该计数器加1,此时A还未处理完成。若处理完毕则计数器减1。而B机器接受到请求后很快处理完毕。那么A,B的活跃数分别是1,0。当又产生了一个新的请求,则选择B机器去执行(B活跃数最小),这样使慢的机器A收到少的请求。</p>
-<p>处理一个新的请求时,Consumer会检查所有Provider的活跃数,如果具有最小活跃数的invoker只有一个,直接返回该Invoker:</p>
+<p>这个解释好像说的不是太明白。目的是让更慢的机器收到更少的请求,但具体怎么实现的还是不太清楚。举个例子:每个服务维护一个活跃数计数器。当A机器开始处理请求,该计数器加1,此时A还未处理完成。若处理完毕则计数器减1。而B机器接受到请求后很快处理完毕。那么A,B的活跃数分别是1,0。当又产生了一个新的请求,则选择B机器去执行(B活跃数最小),这样使慢的机器A收到少的请求。</p>
+<p>处理一个新的请求时,Consumer 会检查所有 Provider 的活跃数,如果具有最小活跃数的 Invoker 只有一个,直接返回该 Invoker:</p>
 <pre><code>if (leastCount == 1) {
     // 如果只有一个最小则直接返回
     return invokers.get(leastIndexs[0]);
 }
 </code></pre>
-<p>如果最小活跃数的invoker有多个,且权重不相等同时总权重大于0,这时随机生成一个权重,范围在0,totalWeight 间内。最后根据随机生成的权重,来选择invoker。</p>
+<p>如果最小活跃数的 Invoker 有多个,且权重不相等同时总权重大于0,这时随机生成一个权重,范围在 (0,totalWeight) 间内。最后根据随机生成的权重,来选择 Invoker。</p>
 <pre><code>if (! sameWeight &amp;&amp; totalWeight &gt; 0) {
     // 如果权重不相同且权重大于0则按总权重数随机
     int offsetWeight = random.nextInt(totalWeight);
@@ -151,16 +151,16 @@
 }
 </code></pre>
 <h3>4.一致性Hash算法</h3>
-<p>使用一致性 Hash,让相同参数的请求总是发到同一提供者。 当某一台提供者挂时,原本发往该提供者的请求,基于虚拟节点,平摊到其它提供者,不会引起剧烈变动。 算法参见:<a href="http://en.wikipedia.org/wiki/Consistent_hashing">http://en.wikipedia.org/wiki/Consistent_hashing</a>。</p>
+<p>使用一致性 Hash 算法,让相同参数的请求总是发到同一 Provider。 当某一台 Provider 崩溃时,原本发往该 Provider 的请求,基于虚拟节点,平摊到其它 Provider,不会引起剧烈变动。 算法参见:<a href="http://en.wikipedia.org/wiki/Consistent_hashing">http://en.wikipedia.org/wiki/Consistent_hashing</a>。</p>
 <p>缺省只对第一个参数Hash,如果要修改,请配置:</p>
 <pre><code>&lt;dubbo:parameter key=&quot;hash.arguments&quot; value=&quot;0,1&quot; /&gt;
 </code></pre>
 <p>缺省用160份虚拟节点,如果要修改,请配置:</p>
 <pre><code>&lt;dubbo:parameter key=&quot;hash.nodes&quot; value=&quot;320&quot; /&gt;
 </code></pre>
-<p>一致性Hash算法可以和缓存机制配合起来使用。比如有一个服务getUserInfo(String userId)。设置了Hash算法后,相同的userId的调用,都会发送到同一个提供者。这个提供者上可以把用户数据在内存中进行缓存,减少访问数据库或分布式缓存的次数。如果业务上允许这部分数据有一段时间的不一致,可以考虑这种做法。减少对数据库,缓存等中间件的依赖和访问次数,同时减少了网络IO操作,提高系统性能。</p>
-<h1>负载均衡配置</h1>
-<p>如果不指定负载均衡,默认使用随机负载均衡。我们也可以根据自己的需要,显式指定一个负载均衡。 可以在多个地方类来配置负载均衡,比如Provider端,Consumer端,服务级别,方法级别等。</p>
+<p>一致性Hash算法可以和缓存机制配合起来使用。比如有一个服务getUserInfo(String userId)。设置了Hash算法后,相同的userId的调用,都会发送到同一个 Provider。这个 Provider 上可以把用户数据在内存中进行缓存,减少访问数据库或分布式缓存的次数。如果业务上允许这部分数据有一段时间的不一致,可以考虑这种做法。减少对数据库,缓存等中间件的依赖和访问次数,同时减少了网络IO操作,提高系统性能。</p>
+<h2>负载均衡配置</h2>
+<p>如果不指定负载均衡,默认使用随机负载均衡。我们也可以根据自己的需要,显式指定一个负载均衡。 可以在多个地方类来配置负载均衡,比如 Provider 端,Consumer端,服务级别,方法级别等。</p>
 <h3>服务端服务级别</h3>
 <pre><code>&lt;dubbo:service interface=&quot;...&quot; loadbalance=&quot;roundrobin&quot; /&gt;
 </code></pre>
@@ -193,10 +193,10 @@
 <li>服务端方法级别配置。</li>
 <li>服务端接口级别配置。</li>
 </ol>
-<h1>扩展负载均衡</h1>
+<h2>扩展负载均衡</h2>
 <p>Dubbo的4种负载均衡的实现,大多数情况下能满足要求。有时候,因为业务的需要,我们可能需要实现自己的负载均衡策略。本章只说明如何配置负载均衡算法。关于Dubbo扩展机制的更多内容,请前往<a href="https://lark.alipay.com/aliware_articles/vtpf9h/pe9pyr">Dubbo可扩展机制实战</a>。</p>
 <ol>
-<li>实现LoadBalance接口 以下是Dubbo的LoadBalance接口:</li>
+<li>实现LoadBalance接口, 以下是Dubbo的LoadBalance接口:</li>
 </ol>
 <pre><code>@SPI(RandomLoadBalance.NAME)
 public interface LoadBalance {
@@ -206,9 +206,9 @@ public interface LoadBalance {
 </code></pre>
 <p>这是SPI的接口,select方法的参数如下:</p>
 <ul>
-<li>invokers: 所有的服务提供者列表。</li>
+<li>invokers: 所有的服务 Provider 列表。</li>
 <li>url: 一些配置信息,比如接口名,是否check,序列化方式。</li>
-<li>invocation: RPC调用的信息,包括方法名,方法参数类型,方法参数。 下面是我们自己实现的一个LoadBalance,实现很简单,选择第一个invoker:</li>
+<li>invocation: RPC调用的信息,包括方法名,方法参数类型,方法参数。 下面是我们自己实现的一个LoadBalance,实现很简单,选择第一个 Invoker:</li>
 </ul>
 <pre><code>package com.demo.dubbo;
 public class DemoLoadBalance implements LoadBalance {
@@ -219,17 +219,17 @@ public class DemoLoadBalance implements LoadBalance {
     }
 }
 </code></pre>
-<ol>
+<ol start="2">
 <li>添加资源文件 添加文件:<code>src/main/resource/META-INF/dubbo/com.alibaba.dubbo.rpc.cluster.LoadBalance</code>。这是一个简单的文本文件。文件内容如下:</li>
 </ol>
 <pre><code>demo=my=com.demo.dubbo.DemoLoadBalance
 </code></pre>
-<ol>
+<ol start="3">
 <li>配置使用自定义LoadBalance</li>
 </ol>
 <pre><code>&lt;dubbo:reference id=&quot;helloService&quot; interface=&quot;com.demo.dubbo.api.IHelloService&quot; loadbalance=&quot;demo&quot; /&gt;
 </code></pre>
-<p>在consumer端的dubbo:reference中配置&lt;loadbalance=&quot;demo&quot;&gt;</p>
+<p>在Consumer端的<code>dubbo:reference</code>中配置<code>&lt;loadbalance=&quot;demo&quot;&gt;</code></p>
 <p>经过上面的3个步骤,我们编写了一个自定义的LoadBalance,并告诉Dubbo使用它了。启动Dubbo,我们就能看到Dubbo已经使用了自定义的DemoLoadBalance。</p>
 </section><footer class="footer-container" data-reactid="19"><div class="footer-body" data-reactid="20"><img src="/img/dubbo_gray.png" data-reactid="21"/><img class="apache" src="/img/apache_logo.png" data-reactid="22"/><div class="cols-container" data-reactid="23"><div class="col col-12" data-reactid="24"><h3 data-reactid="25">Disclaimer</h3><p data-reactid="26">Apache Dubbo is an effort undergoing incubation at The Apache Software Foundation (ASF), sponsored by the Incubator. Incubatio [...]
 	<script src="https://f.alicdn.com/react/15.4.1/react-with-addons.min.js"></script>
diff --git a/zh-cn/blog/dubbo-loadbalance.json b/zh-cn/blog/dubbo-loadbalance.json
index a507cf9..b363814 100644
--- a/zh-cn/blog/dubbo-loadbalance.json
+++ b/zh-cn/blog/dubbo-loadbalance.json
@@ -1,4 +1,4 @@
 {
   "filename": "dubbo-loadbalance.md",
-  "__html": "<h1>Dubbo的负载均衡</h1>\n<h1>背景</h1>\n<p>Dubbo是一个分布式服务框架,能避免单点故障和支持服务的横向扩容。一个服务通常会部署多个实例。如何从多个服务提供者组成的集群中挑选出一个进行调用,就涉及到一个负载均衡的策略。</p>\n<h1>几个概念</h1>\n<p>在讨论负载均衡之前,我想先解释一下这3个概念。</p>\n<ol>\n<li>负载均衡</li>\n<li>集群容错</li>\n<li>服务路由</li>\n</ol>\n<p>这3个概念容易混淆。他们都描述了怎么从多个Provider中选择一个来进行调用。那他们到底有什么区别呢?下面我来举一个简单的例子,把这几个概念阐述清楚吧。</p>\n<p>有一个Dubbo的用户服务,在北京部署了10个,在上海部署了20个。一个杭州的服务消费方发起了一次调用,然后发生了以下的事情:</p>\n<ol>\n<li>根据配置的路由规则,如果杭州发起的调用,会路由到比较近的
 上海的20个Provider。</li>\n<li>根据配置的随机负载均衡策略。在20个Pro [...]
+  "__html": "<h1>Dubbo的负载均衡</h1>\n<h2>背景</h2>\n<p>Dubbo是一个分布式服务框架,能避免单点故障和支持服务的横向扩容。一个服务通常会部署多个实例。如何从多个服务 Provider 组成的集群中挑选出一个进行调用,就涉及到一个负载均衡的策略。</p>\n<h2>几个概念</h2>\n<p>在讨论负载均衡之前,我想先解释一下这3个概念。</p>\n<ol>\n<li>负载均衡</li>\n<li>集群容错</li>\n<li>服务路由</li>\n</ol>\n<p>这3个概念容易混淆。他们都描述了怎么从多个 Provider 中选择一个来进行调用。那他们到底有什么区别呢?下面我来举一个简单的例子,把这几个概念阐述清楚吧。</p>\n<p>有一个Dubbo的用户服务,在北京部署了10个,在上海部署了20个。一个杭州的服务消费方发起了一次调用,然后发生了以下的事情:</p>\n<ol>\n<li>根据配置的路由规则,如果杭州发起的调用,会路由到比较近
 的上海的20个 Provider。</li>\n<li>根据配置的随机负载均衡 [...]
 }
\ No newline at end of file
diff --git a/zh-cn/blog/introduction-to-dubbo-qos.html b/zh-cn/blog/introduction-to-dubbo-qos.html
index c1d2f91..40052cc 100644
--- a/zh-cn/blog/introduction-to-dubbo-qos.html
+++ b/zh-cn/blog/introduction-to-dubbo-qos.html
@@ -12,8 +12,8 @@
 	<link rel="stylesheet" href="/build/blogDetail.css" />
 </head>
 <body>
-	<div id="root"><div class="blog-detail-page" data-reactroot="" data-reactid="1" data-react-checksum="-96574520"><header class="header-container header-container-normal" data-reactid="2"><div class="header-body" data-reactid="3"><a href="/zh-cn/index.html" data-reactid="4"><img class="logo" src="/img/dubbo_colorful.png" data-reactid="5"/></a><span class="language-switch language-switch-normal" data-reactid="6">En</span><div class="header-menu" data-reactid="7"><img class="header-menu-tog [...]
-<p>QoS,全称为<code>Quality of Service</code>, 是常见于网络设备中的一个术语 ,例如在路由器中,可以通过Qos动态的调整和控制某些端口的权重,从优先的保障运行在这些端口上的服务质量。</p>
+	<div id="root"><div class="blog-detail-page" data-reactroot="" data-reactid="1" data-react-checksum="111731636"><header class="header-container header-container-normal" data-reactid="2"><div class="header-body" data-reactid="3"><a href="/zh-cn/index.html" data-reactid="4"><img class="logo" src="/img/dubbo_colorful.png" data-reactid="5"/></a><span class="language-switch language-switch-normal" data-reactid="6">En</span><div class="header-menu" data-reactid="7"><img class="header-menu-tog [...]
+<p>QoS,全称为<code>Quality of Service</code>, 是常见于网络设备中的一个术语 ,例如在路由器中,可以通过Qos动态的调整和控制某些端口的权重,从而优先的保障运行在这些端口上的服务质量。</p>
 <p>在Dubbo中,QoS这个概念被用于动态的对服务进行查询和控制。例如对获取当前提供和消费的所有服务,以及对服务进行动态的上下线,即从注册中心上进行注册和反注册操作。</p>
 <h3>QoS工作机制</h3>
 <p>从Dubbo 2.5.8开始,默认引入了Qos功能,默认处于启动状态。所有的QoS功能被抽象成一个个的命令,通过执行这些命令,Qos会返回响应的结果。</p>
@@ -126,7 +126,7 @@ HTTP/1.1 200 OK
 Content-Type: text/plain
 Content-Length: 2
 
-OK% 
+OK%
 </code></pre>
 <blockquote>
 <p>注意online操作对应的参数,需要以<code>key=value</code>的形式提供,但实际上key会被忽略</p>
diff --git a/zh-cn/blog/introduction-to-dubbo-qos.json b/zh-cn/blog/introduction-to-dubbo-qos.json
index 481ba89..cf6adb1 100644
--- a/zh-cn/blog/introduction-to-dubbo-qos.json
+++ b/zh-cn/blog/introduction-to-dubbo-qos.json
@@ -1,4 +1,4 @@
 {
   "filename": "introduction-to-dubbo-qos.md",
-  "__html": "<h1>通过QoS对服务进行动态控制</h1>\n<p>QoS,全称为<code>Quality of Service</code>, 是常见于网络设备中的一个术语 ,例如在路由器中,可以通过Qos动态的调整和控制某些端口的权重,从优先的保障运行在这些端口上的服务质量。</p>\n<p>在Dubbo中,QoS这个概念被用于动态的对服务进行查询和控制。例如对获取当前提供和消费的所有服务,以及对服务进行动态的上下线,即从注册中心上进行注册和反注册操作。</p>\n<h3>QoS工作机制</h3>\n<p>从Dubbo 2.5.8开始,默认引入了Qos功能,默认处于启动状态。所有的QoS功能被抽象成一个个的命令,通过执行这些命令,Qos会返回响应的结果。</p>\n<blockquote>\n<p>Qos功能基于Netty4实现,在Dubbo 2.6.x之前的版本中,默认依赖的是Netty3,因此需要显示的添加Netty4的依赖,才能确保Netty4正常工作。如果使用http://start.dubbo.io自动�
 �成的Dubbo应用,则无需添加额外的 [...]
+  "__html": "<h1>通过QoS对服务进行动态控制</h1>\n<p>QoS,全称为<code>Quality of Service</code>, 是常见于网络设备中的一个术语 ,例如在路由器中,可以通过Qos动态的调整和控制某些端口的权重,从而优先的保障运行在这些端口上的服务质量。</p>\n<p>在Dubbo中,QoS这个概念被用于动态的对服务进行查询和控制。例如对获取当前提供和消费的所有服务,以及对服务进行动态的上下线,即从注册中心上进行注册和反注册操作。</p>\n<h3>QoS工作机制</h3>\n<p>从Dubbo 2.5.8开始,默认引入了Qos功能,默认处于启动状态。所有的QoS功能被抽象成一个个的命令,通过执行这些命令,Qos会返回响应的结果。</p>\n<blockquote>\n<p>Qos功能基于Netty4实现,在Dubbo 2.6.x之前的版本中,默认依赖的是Netty3,因此需要显示的添加Netty4的依赖,才能确保Netty4正常工作。如果使用http://start.dubbo.io自�
 �生成的Dubbo应用,则无需添加额外 [...]
 }
\ No newline at end of file
diff --git a/zh-cn/blog/spring-boot-dubbo-start-stop-analysis.html b/zh-cn/blog/spring-boot-dubbo-start-stop-analysis.html
index 2eba8a3..5e32612 100644
--- a/zh-cn/blog/spring-boot-dubbo-start-stop-analysis.html
+++ b/zh-cn/blog/spring-boot-dubbo-start-stop-analysis.html
@@ -12,7 +12,7 @@
 	<link rel="stylesheet" href="/build/blogDetail.css" />
 </head>
 <body>
-	<div id="root"><div class="blog-detail-page" data-reactroot="" data-reactid="1" data-react-checksum="68597831"><header class="header-container header-container-normal" data-reactid="2"><div class="header-body" data-reactid="3"><a href="/zh-cn/index.html" data-reactid="4"><img class="logo" src="/img/dubbo_colorful.png" data-reactid="5"/></a><span class="language-switch language-switch-normal" data-reactid="6">En</span><div class="header-menu" data-reactid="7"><img class="header-menu-togg [...]
+	<div id="root"><div class="blog-detail-page" data-reactroot="" data-reactid="1" data-react-checksum="1504542408"><header class="header-container header-container-normal" data-reactid="2"><div class="header-body" data-reactid="3"><a href="/zh-cn/index.html" data-reactid="4"><img class="logo" src="/img/dubbo_colorful.png" data-reactid="5"/></a><span class="language-switch language-switch-normal" data-reactid="6">En</span><div class="header-menu" data-reactid="7"><img class="header-menu-to [...]
 <h3>背景介绍</h3>
 <p><a href="https://github.com/apache/incubator-dubbo-spring-boot-project">Dubbo Spring Boot</a> 工程致力于简化 Dubbo RPC 框架在Spring Boot应用场景的开发。同时也整合了 Spring Boot 特性:</p>
 <ul>
@@ -102,7 +102,7 @@ run:1118, SpringApplication (org.springframework.boot)
 run:1107, SpringApplication (org.springframework.boot)
 main:35, DubboConsumerDemo (com.alibaba.boot.dubbo.demo.consumer.bootstrap)
 </code></pre>
-<p>可以看到,spring-boot应用在启动的过程中,由于默认启动了Tomcat暴露HTTP服务,所以执行到了上述方法,而Tomcat启动的所有的线程,默认都是daemon线程,例如监听请求的Acceptor,工作线程池等等,如果这里不加控制的话,启动完成之后JVM也会退出。因此需要显示的启动一个线程,在某个条件下进行持续等待,从而避免线程退出。</p>
+<p>可以看到,spring-boot应用在启动的过程中,由于默认启动了Tomcat暴露HTTP服务,所以执行到了上述方法,而Tomcat启动的所有的线程,默认都是daemon线程,例如监听请求的Acceptor,工作线程池等等,如果这里不加控制的话,启动完成之后JVM也会退出。因此需要显式地启动一个线程,在某个条件下进行持续等待,从而避免线程退出。</p>
 <p>下面我们在深挖一下,在Tomcat的<code>this.tomcat.getServer().await()</code>这个方法中,线程是如何实现不退出的。这里为了阅读方便,去掉了不相关的代码。</p>
 <pre><code class="language-java"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">await</span><span class="hljs-params">()</span> </span>{
     	<span class="hljs-comment">// ...</span>
diff --git a/zh-cn/blog/spring-boot-dubbo-start-stop-analysis.json b/zh-cn/blog/spring-boot-dubbo-start-stop-analysis.json
index bad6d27..bbcae1d 100644
--- a/zh-cn/blog/spring-boot-dubbo-start-stop-analysis.json
+++ b/zh-cn/blog/spring-boot-dubbo-start-stop-analysis.json
@@ -1,4 +1,4 @@
 {
   "filename": "spring-boot-dubbo-start-stop-analysis.md",
-  "__html": "<h1>Spring-boot+Dubbo应用启停源码分析</h1>\n<h3>背景介绍</h3>\n<p><a href=\"https://github.com/apache/incubator-dubbo-spring-boot-project\">Dubbo Spring Boot</a> 工程致力于简化 Dubbo RPC 框架在Spring Boot应用场景的开发。同时也整合了 Spring Boot 特性:</p>\n<ul>\n<li><a href=\"https://github.com/apache/incubator-dubbo-spring-boot-project/blob/master/dubbo-spring-boot-autoconfigure\">自动装配</a> (比如: 注解驱动, 自动装配等).</li>\n<li><a href=\"https://github.com/apache/incubator-dubbo-spring-boot-project/blob/master/dubbo-sprin [...]
+  "__html": "<h1>Spring-boot+Dubbo应用启停源码分析</h1>\n<h3>背景介绍</h3>\n<p><a href=\"https://github.com/apache/incubator-dubbo-spring-boot-project\">Dubbo Spring Boot</a> 工程致力于简化 Dubbo RPC 框架在Spring Boot应用场景的开发。同时也整合了 Spring Boot 特性:</p>\n<ul>\n<li><a href=\"https://github.com/apache/incubator-dubbo-spring-boot-project/blob/master/dubbo-spring-boot-autoconfigure\">自动装配</a> (比如: 注解驱动, 自动装配等).</li>\n<li><a href=\"https://github.com/apache/incubator-dubbo-spring-boot-project/blob/master/dubbo-sprin [...]
 }
\ No newline at end of file