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

wangxin 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 1d96fc9  generate html
1d96fc9 is described below

commit 1d96fc9e6e9fb90ff9bea72fc0131d7e7e52d608
Author: Xin Wang <xin.victorw...@gmail.com>
AuthorDate: Mon Jan 28 09:27:44 2019 +0800

    generate html
---
 build/blog.js                                 |   6 +-
 build/blogDetail.js                           |   6 +-
 build/community.js                            |   6 +-
 build/documentation.js                        |   6 +-
 build/home.js                                 |   6 +-
 en-us/docs/developers/developers_dev.html     |  21 +-
 en-us/docs/developers/developers_dev.json     |   2 +-
 en-us/docs/user/references/telnet.html        |  16 +-
 en-us/docs/user/references/telnet.json        |   2 +-
 md_json/blog.json                             |  19 ++
 zh-cn/blog/Configuration Conclude.html        | 189 ++++++++++++++
 zh-cn/blog/Configuration Conclude.json        |   6 +
 zh-cn/blog/Guides for upgrading to 2.7.x.html | 342 ++++++++++++++++++++++++
 zh-cn/blog/Guides for upgrading to 2.7.x.json |   6 +
 zh-cn/blog/dubbo-heartbeat-design.html        | 358 ++++++++++++++++++++++++++
 zh-cn/blog/dubbo-heartbeat-design.json        |  10 +
 zh-cn/blog/index.html                         |   2 +-
 zh-cn/docs/dev/principals/code-detail.html    |   4 +-
 zh-cn/docs/dev/principals/code-detail.json    |   2 +-
 zh-cn/docs/dev/principals/robustness.html     |   4 +-
 zh-cn/docs/dev/principals/robustness.json     |   2 +-
 zh-cn/docs/developers/developers_dev.html     |  21 +-
 zh-cn/docs/developers/developers_dev.json     |   2 +-
 zh-cn/docs/user/references/telnet.html        |  15 +-
 zh-cn/docs/user/references/telnet.json        |   2 +-
 25 files changed, 1010 insertions(+), 45 deletions(-)

diff --git a/build/blog.js b/build/blog.js
index 7ff2578..3097b5b 100644
--- a/build/blog.js
+++ b/build/blog.js
@@ -1,6 +1,6 @@
-!function(e){function t(r){if(n[r])return n[r].exports;var 
o=n[r]={i:r,l:!1,exports:{}};return 
e[r].call(o.exports,o,o.exports,t),o.l=!0,o.exports}var 
n={};t.m=e,t.c=n,t.i=function(e){return 
e},t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:r})},t.n=function(e){var
 n=e&&e.__esModule?function(){return e.default}:function(){return e};return 
t.d(n,"a",n),n},t.o=function(e,t){return 
Object.prototype.hasOwnProperty.call(e,t)},t.p="/build/",t(t.s=80) [...]
-  Copyright (c) 2016 Jed Watson.
+!function(e){function t(r){if(n[r])return n[r].exports;var 
o=n[r]={i:r,l:!1,exports:{}};return 
e[r].call(o.exports,o,o.exports,t),o.l=!0,o.exports}var 
n={};t.m=e,t.c=n,t.i=function(e){return 
e},t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:r})},t.n=function(e){var
 n=e&&e.__esModule?function(){return e.default}:function(){return e};return 
t.d(n,"a",n),n},t.o=function(e,t){return 
Object.prototype.hasOwnProperty.call(e,t)},t.p="/build/",t(t.s=78) [...]
+  Copyright (c) 2017 Jed Watson.
   Licensed under the MIT License (MIT), see
   http://jedwatson.github.io/classnames
 */
-!function(){"use strict";function n(){for(var 
e=[],t=0;t<arguments.length;t++){var r=arguments[t];if(r){var o=typeof 
r;if("string"===o||"number"===o)e.push(r);else 
if(Array.isArray(r))e.push(n.apply(null,r));else if("object"===o)for(var a in 
r)i.call(r,a)&&r[a]&&e.push(a)}}return e.join(" ")}var i={}.hasOwnProperty;void 
0!==e&&e.exports?e.exports=n:(r=[],void 0!==(o=function(){return 
n}.apply(t,r))&&(e.exports=o))}()},function(e,t,n){"use strict";function 
r(e,t,r){var o=r.configurable,u= [...]
\ No newline at end of file
+!function(){"use strict";function n(){for(var 
e=[],t=0;t<arguments.length;t++){var r=arguments[t];if(r){var o=typeof 
r;if("string"===o||"number"===o)e.push(r);else 
if(Array.isArray(r)&&r.length){var a=n.apply(null,r);a&&e.push(a)}else 
if("object"===o)for(var u in r)i.call(r,u)&&r[u]&&e.push(u)}}return e.join(" 
")}var i={}.hasOwnProperty;void 
0!==e&&e.exports?(n.default=n,e.exports=n):(r=[],void 0!==(o=function(){return 
n}.apply(t,r))&&(e.exports=o))}()},function(e,t,n){"use strict";funct [...]
\ No newline at end of file
diff --git a/build/blogDetail.js b/build/blogDetail.js
index f364b11..1d97e31 100644
--- a/build/blogDetail.js
+++ b/build/blogDetail.js
@@ -1,6 +1,6 @@
-!function(e){function t(r){if(n[r])return n[r].exports;var 
o=n[r]={i:r,l:!1,exports:{}};return 
e[r].call(o.exports,o,o.exports,t),o.l=!0,o.exports}var 
n={};t.m=e,t.c=n,t.i=function(e){return 
e},t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:r})},t.n=function(e){var
 n=e&&e.__esModule?function(){return e.default}:function(){return e};return 
t.d(n,"a",n),n},t.o=function(e,t){return 
Object.prototype.hasOwnProperty.call(e,t)},t.p="/build/",t(t.s=81) [...]
-  Copyright (c) 2016 Jed Watson.
+!function(e){function t(r){if(n[r])return n[r].exports;var 
o=n[r]={i:r,l:!1,exports:{}};return 
e[r].call(o.exports,o,o.exports,t),o.l=!0,o.exports}var 
n={};t.m=e,t.c=n,t.i=function(e){return 
e},t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:r})},t.n=function(e){var
 n=e&&e.__esModule?function(){return e.default}:function(){return e};return 
t.d(n,"a",n),n},t.o=function(e,t){return 
Object.prototype.hasOwnProperty.call(e,t)},t.p="/build/",t(t.s=79) [...]
+  Copyright (c) 2017 Jed Watson.
   Licensed under the MIT License (MIT), see
   http://jedwatson.github.io/classnames
 */
-!function(){"use strict";function n(){for(var 
e=[],t=0;t<arguments.length;t++){var r=arguments[t];if(r){var o=typeof 
r;if("string"===o||"number"===o)e.push(r);else 
if(Array.isArray(r))e.push(n.apply(null,r));else if("object"===o)for(var a in 
r)i.call(r,a)&&r[a]&&e.push(a)}}return e.join(" ")}var i={}.hasOwnProperty;void 
0!==e&&e.exports?e.exports=n:(r=[],void 0!==(o=function(){return 
n}.apply(t,r))&&(e.exports=o))}()},function(e,t,n){"use strict";function 
r(e,t,r){var o=r.configurable,u= [...]
\ No newline at end of file
+!function(){"use strict";function n(){for(var 
e=[],t=0;t<arguments.length;t++){var r=arguments[t];if(r){var o=typeof 
r;if("string"===o||"number"===o)e.push(r);else 
if(Array.isArray(r)&&r.length){var a=n.apply(null,r);a&&e.push(a)}else 
if("object"===o)for(var u in r)i.call(r,u)&&r[u]&&e.push(u)}}return e.join(" 
")}var i={}.hasOwnProperty;void 
0!==e&&e.exports?(n.default=n,e.exports=n):(r=[],void 0!==(o=function(){return 
n}.apply(t,r))&&(e.exports=o))}()},function(e,t,n){"use strict";funct [...]
\ No newline at end of file
diff --git a/build/community.js b/build/community.js
index 775a6c2..84c0d15 100644
--- a/build/community.js
+++ b/build/community.js
@@ -1,6 +1,6 @@
-!function(e){function t(r){if(n[r])return n[r].exports;var 
o=n[r]={i:r,l:!1,exports:{}};return 
e[r].call(o.exports,o,o.exports,t),o.l=!0,o.exports}var 
n={};t.m=e,t.c=n,t.i=function(e){return 
e},t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:r})},t.n=function(e){var
 n=e&&e.__esModule?function(){return e.default}:function(){return e};return 
t.d(n,"a",n),n},t.o=function(e,t){return 
Object.prototype.hasOwnProperty.call(e,t)},t.p="/build/",t(t.s=82) [...]
-  Copyright (c) 2016 Jed Watson.
+!function(e){function t(r){if(n[r])return n[r].exports;var 
o=n[r]={i:r,l:!1,exports:{}};return 
e[r].call(o.exports,o,o.exports,t),o.l=!0,o.exports}var 
n={};t.m=e,t.c=n,t.i=function(e){return 
e},t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:r})},t.n=function(e){var
 n=e&&e.__esModule?function(){return e.default}:function(){return e};return 
t.d(n,"a",n),n},t.o=function(e,t){return 
Object.prototype.hasOwnProperty.call(e,t)},t.p="/build/",t(t.s=80) [...]
+  Copyright (c) 2017 Jed Watson.
   Licensed under the MIT License (MIT), see
   http://jedwatson.github.io/classnames
 */
-!function(){"use strict";function n(){for(var 
e=[],t=0;t<arguments.length;t++){var r=arguments[t];if(r){var o=typeof 
r;if("string"===o||"number"===o)e.push(r);else 
if(Array.isArray(r))e.push(n.apply(null,r));else if("object"===o)for(var a in 
r)i.call(r,a)&&r[a]&&e.push(a)}}return e.join(" ")}var i={}.hasOwnProperty;void 
0!==e&&e.exports?e.exports=n:(r=[],void 0!==(o=function(){return 
n}.apply(t,r))&&(e.exports=o))}()},function(e,t,n){"use strict";function 
r(e,t,r){var o=r.configurable,l= [...]
\ No newline at end of file
+!function(){"use strict";function n(){for(var 
e=[],t=0;t<arguments.length;t++){var r=arguments[t];if(r){var o=typeof 
r;if("string"===o||"number"===o)e.push(r);else 
if(Array.isArray(r)&&r.length){var a=n.apply(null,r);a&&e.push(a)}else 
if("object"===o)for(var l in r)i.call(r,l)&&r[l]&&e.push(l)}}return e.join(" 
")}var i={}.hasOwnProperty;void 
0!==e&&e.exports?(n.default=n,e.exports=n):(r=[],void 0!==(o=function(){return 
n}.apply(t,r))&&(e.exports=o))}()},function(e,t,n){"use strict";funct [...]
\ No newline at end of file
diff --git a/build/documentation.js b/build/documentation.js
index 7b59326..a09500d 100644
--- a/build/documentation.js
+++ b/build/documentation.js
@@ -1,6 +1,6 @@
-!function(e){function t(r){if(n[r])return n[r].exports;var 
o=n[r]={i:r,l:!1,exports:{}};return 
e[r].call(o.exports,o,o.exports,t),o.l=!0,o.exports}var 
n={};t.m=e,t.c=n,t.i=function(e){return 
e},t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:r})},t.n=function(e){var
 n=e&&e.__esModule?function(){return e.default}:function(){return e};return 
t.d(n,"a",n),n},t.o=function(e,t){return 
Object.prototype.hasOwnProperty.call(e,t)},t.p="/build/",t(t.s=83) [...]
-  Copyright (c) 2016 Jed Watson.
+!function(e){function t(r){if(n[r])return n[r].exports;var 
o=n[r]={i:r,l:!1,exports:{}};return 
e[r].call(o.exports,o,o.exports,t),o.l=!0,o.exports}var 
n={};t.m=e,t.c=n,t.i=function(e){return 
e},t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:r})},t.n=function(e){var
 n=e&&e.__esModule?function(){return e.default}:function(){return e};return 
t.d(n,"a",n),n},t.o=function(e,t){return 
Object.prototype.hasOwnProperty.call(e,t)},t.p="/build/",t(t.s=81) [...]
+  Copyright (c) 2017 Jed Watson.
   Licensed under the MIT License (MIT), see
   http://jedwatson.github.io/classnames
 */
-!function(){"use strict";function n(){for(var 
e=[],t=0;t<arguments.length;t++){var r=arguments[t];if(r){var o=typeof 
r;if("string"===o||"number"===o)e.push(r);else 
if(Array.isArray(r))e.push(n.apply(null,r));else if("object"===o)for(var l in 
r)i.call(r,l)&&r[l]&&e.push(l)}}return e.join(" ")}var i={}.hasOwnProperty;void 
0!==e&&e.exports?e.exports=n:(r=[],void 0!==(o=function(){return 
n}.apply(t,r))&&(e.exports=o))}()},function(e,t,n){"use strict";function 
r(e,t,r){var o=r.configurable,s= [...]
\ No newline at end of file
+!function(){"use strict";function n(){for(var 
e=[],t=0;t<arguments.length;t++){var r=arguments[t];if(r){var o=typeof 
r;if("string"===o||"number"===o)e.push(r);else 
if(Array.isArray(r)&&r.length){var l=n.apply(null,r);l&&e.push(l)}else 
if("object"===o)for(var s in r)i.call(r,s)&&r[s]&&e.push(s)}}return e.join(" 
")}var i={}.hasOwnProperty;void 
0!==e&&e.exports?(n.default=n,e.exports=n):(r=[],void 0!==(o=function(){return 
n}.apply(t,r))&&(e.exports=o))}()},function(e,t,n){"use strict";funct [...]
\ No newline at end of file
diff --git a/build/home.js b/build/home.js
index ead259e..ee5c8c3 100644
--- a/build/home.js
+++ b/build/home.js
@@ -1,6 +1,6 @@
-!function(e){function t(r){if(n[r])return n[r].exports;var 
o=n[r]={i:r,l:!1,exports:{}};return 
e[r].call(o.exports,o,o.exports,t),o.l=!0,o.exports}var 
n={};t.m=e,t.c=n,t.i=function(e){return 
e},t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:r})},t.n=function(e){var
 n=e&&e.__esModule?function(){return e.default}:function(){return e};return 
t.d(n,"a",n),n},t.o=function(e,t){return 
Object.prototype.hasOwnProperty.call(e,t)},t.p="/build/",t(t.s=84) [...]
-  Copyright (c) 2016 Jed Watson.
+!function(e){function t(r){if(n[r])return n[r].exports;var 
o=n[r]={i:r,l:!1,exports:{}};return 
e[r].call(o.exports,o,o.exports,t),o.l=!0,o.exports}var 
n={};t.m=e,t.c=n,t.i=function(e){return 
e},t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:r})},t.n=function(e){var
 n=e&&e.__esModule?function(){return e.default}:function(){return e};return 
t.d(n,"a",n),n},t.o=function(e,t){return 
Object.prototype.hasOwnProperty.call(e,t)},t.p="/build/",t(t.s=82) [...]
+  Copyright (c) 2017 Jed Watson.
   Licensed under the MIT License (MIT), see
   http://jedwatson.github.io/classnames
 */
-!function(){"use strict";function n(){for(var 
e=[],t=0;t<arguments.length;t++){var r=arguments[t];if(r){var o=typeof 
r;if("string"===o||"number"===o)e.push(r);else 
if(Array.isArray(r))e.push(n.apply(null,r));else if("object"===o)for(var i in 
r)a.call(r,i)&&r[i]&&e.push(i)}}return e.join(" ")}var a={}.hasOwnProperty;void 
0!==e&&e.exports?e.exports=n:(r=[],void 0!==(o=function(){return 
n}.apply(t,r))&&(e.exports=o))}()},function(e,t,n){"use strict";function 
r(e,t,r){var o=r.configurable,u= [...]
\ No newline at end of file
+!function(){"use strict";function n(){for(var 
e=[],t=0;t<arguments.length;t++){var r=arguments[t];if(r){var o=typeof 
r;if("string"===o||"number"===o)e.push(r);else 
if(Array.isArray(r)&&r.length){var i=n.apply(null,r);i&&e.push(i)}else 
if("object"===o)for(var u in r)a.call(r,u)&&r[u]&&e.push(u)}}return e.join(" 
")}var a={}.hasOwnProperty;void 
0!==e&&e.exports?(n.default=n,e.exports=n):(r=[],void 0!==(o=function(){return 
n}.apply(t,r))&&(e.exports=o))}()},function(e,t,n){"use strict";funct [...]
\ No newline at end of file
diff --git a/en-us/docs/developers/developers_dev.html 
b/en-us/docs/developers/developers_dev.html
index 6371bcd..7dc5bb5 100644
--- a/en-us/docs/developers/developers_dev.html
+++ b/en-us/docs/developers/developers_dev.html
@@ -139,6 +139,13 @@
 <td>+8</td>
 </tr>
 <tr>
+<td>carryxyh</td>
+<td>Yuhang Xiu</td>
+<td>Netease</td>
+<td>PPMC</td>
+<td>+8</td>
+</tr>
+<tr>
 <td>hyunkun</td>
 <td>YunKun Huang</td>
 <td></td>
@@ -160,13 +167,6 @@
 <td>+8</td>
 </tr>
 <tr>
-<td>carryxyh</td>
-<td>Yuhang Xiu</td>
-<td>Netease</td>
-<td>Committer</td>
-<td>+8</td>
-</tr>
-<tr>
 <td>min</td>
 <td>Minxuan Zhuang</td>
 <td>Alibaba</td>
@@ -208,6 +208,13 @@
 <td>Committer</td>
 <td>+8</td>
 </tr>
+<tr>
+<td>tswstarplanet</td>
+<td>Taosheng Wei</td>
+<td>NetsUnion</td>
+<td>Committer</td>
+<td>+8</td>
+</tr>
 </tbody>
 </table>
 <h3>Contributors</h3>
diff --git a/en-us/docs/developers/developers_dev.json 
b/en-us/docs/developers/developers_dev.json
index 272fda6..ca181d5 100644
--- a/en-us/docs/developers/developers_dev.json
+++ b/en-us/docs/developers/developers_dev.json
@@ -1,6 +1,6 @@
 {
   "filename": "developers_dev.md",
-  "__html": "<h2>Developers</h2>\n<p>This page shows Dubbo developers. Please 
file PR to add or change 
items.</p>\n<h3>Committers</h3>\n<table>\n<thead>\n<tr>\n<th>Apache 
ID</th>\n<th>Name</th>\n<th>Organization</th>\n<th>Role</th>\n<th>TimeZone</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>jmclean</td>\n<td>Justin
 
Mclean</td>\n<td>Apache</td>\n<td>Mentor</td>\n<td>+11</td>\n</tr>\n<tr>\n<td>markt</td>\n<td>Mark
 
Thomas</td>\n<td>Apache</td>\n<td>Mentor</td>\n<td>+0</td>\n</tr>\n<tr>\n<td>wav
 [...]
+  "__html": "<h2>Developers</h2>\n<p>This page shows Dubbo developers. Please 
file PR to add or change 
items.</p>\n<h3>Committers</h3>\n<table>\n<thead>\n<tr>\n<th>Apache 
ID</th>\n<th>Name</th>\n<th>Organization</th>\n<th>Role</th>\n<th>TimeZone</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>jmclean</td>\n<td>Justin
 
Mclean</td>\n<td>Apache</td>\n<td>Mentor</td>\n<td>+11</td>\n</tr>\n<tr>\n<td>markt</td>\n<td>Mark
 
Thomas</td>\n<td>Apache</td>\n<td>Mentor</td>\n<td>+0</td>\n</tr>\n<tr>\n<td>wav
 [...]
   "link": "/en-us/docs/developers/developers_dev.html",
   "meta": {}
 }
\ No newline at end of file
diff --git a/en-us/docs/user/references/telnet.html 
b/en-us/docs/user/references/telnet.html
index c93c6dc..bdd0e27 100644
--- a/en-us/docs/user/references/telnet.html
+++ b/en-us/docs/user/references/telnet.html
@@ -64,12 +64,16 @@
 <li><code>invoke XxxService.xxxMethod({&quot;prop&quot;: 
&quot;value&quot;})</code>: invoke particular method for the given service</li>
 <li><code>invoke xxxMethod({&quot;prop&quot;: &quot;value&quot;})</code>: 
invoke particular method for the default service</li>
 </ol>
+<h3><code>select</code> <sup class="footnote-ref"><a href="#fn1" 
id="fnref1">[1]</a></sup></h3>
+<ol start="0">
+<li><code>select 1</code>: used when the invoke command matches multiple 
methods, select the method to be called according to the prompt list</li>
+</ol>
 <h3><code>status</code></h3>
 <ol start="0">
 <li><code>status</code>: show summarized status. This status summarizes 
statuses from all resources, and it shows OK when all resources are OK, shows 
ERROR when any resource has ERROR, and WARN when any has WARN.</li>
 <li><code>status -l</code>: show status list</li>
 </ol>
-<h3><code>log</code> <sup class="footnote-ref"><a href="#fn1" 
id="fnref1">[1]</a></sup></h3>
+<h3><code>log</code> <sup class="footnote-ref"><a href="#fn2" 
id="fnref2">[2]</a></sup></h3>
 <ol start="0">
 <li><code>log debug</code>: modify logger level to debug</li>
 <li><code>log 100</code>: examine the last 100 characters from the file 
logger</li>
@@ -77,7 +81,6 @@
 <h3><code>help</code></h3>
 <ol start="0">
 <li><code>help</code>: show help for telnet commands</li>
-<li><code>help xxx</code>: 显示xxx命令的详细帮助信息</li>
 <li><code>help xxx</code>: show help for particular telnet command</li>
 </ol>
 <h3><code>clear</code></h3>
@@ -87,10 +90,17 @@
 </ol>
 <h3><code>exit</code></h3>
 <p><code>exit</code>: exit current telnet session</p>
+<h3><code>shutdown</code> <sup class="footnote-ref"><a href="#fn1" 
id="fnref1:1">[1:1]</a></sup></h3>
+<ol start="0">
+<li><code>shutdown</code>: shutdown dubbo application</li>
+<li><code>shutdown -t 1000</code>: delay 1000 ms to shutdown dubbo 
application</li>
+</ol>
 <hr class="footnotes-sep">
 <section class="footnotes">
 <ol class="footnotes-list">
-<li id="fn1" class="footnote-item"><p>support since <code>2.0.6</code> <a 
href="#fnref1" class="footnote-backref">↩︎</a></p>
+<li id="fn1" class="footnote-item"><p>support since <code>2.7.1</code> <a 
href="#fnref1" class="footnote-backref">↩︎</a> <a href="#fnref1:1" 
class="footnote-backref">↩︎</a></p>
+</li>
+<li id="fn2" class="footnote-item"><p>support since <code>2.0.6</code> <a 
href="#fnref2" class="footnote-backref">↩︎</a></p>
 </li>
 </ol>
 </section>
diff --git a/en-us/docs/user/references/telnet.json 
b/en-us/docs/user/references/telnet.json
index 564889b..9bea1c5 100644
--- a/en-us/docs/user/references/telnet.json
+++ b/en-us/docs/user/references/telnet.json
@@ -1,6 +1,6 @@
 {
   "filename": "telnet.md",
-  "__html": "<h1>Telnet Command Reference</h1>\n<p>Since <code>2.0.5</code> 
dubbo starts supporting to use telnet command to govern services.</p>\n<h2>How 
To Use</h2>\n<pre><code class=\"language-sh\">telnet localhost 
20880\n</code></pre>\n<p>Or:</p>\n<pre><code class=\"language-sh\"><span 
class=\"hljs-built_in\">echo</span> status | nc -i 1 localhost 
20880\n</code></pre>\n<p>It is possible to extend command <code>status</code> 
to check more resources, pls. refer to <a href=\"http://dubb [...]
+  "__html": "<h1>Telnet Command Reference</h1>\n<p>Since <code>2.0.5</code> 
dubbo starts supporting to use telnet command to govern services.</p>\n<h2>How 
To Use</h2>\n<pre><code class=\"language-sh\">telnet localhost 
20880\n</code></pre>\n<p>Or:</p>\n<pre><code class=\"language-sh\"><span 
class=\"hljs-built_in\">echo</span> status | nc -i 1 localhost 
20880\n</code></pre>\n<p>It is possible to extend command <code>status</code> 
to check more resources, pls. refer to <a href=\"http://dubb [...]
   "link": "/en-us/docs/user/references/telnet.html",
   "meta": {}
 }
\ No newline at end of file
diff --git a/md_json/blog.json b/md_json/blog.json
index f2e3a34..8e45a79 100644
--- a/md_json/blog.json
+++ b/md_json/blog.json
@@ -211,6 +211,16 @@
   ],
   "zh-cn": [
     {
+      "filename": "Configuration Conclude.md",
+      "link": "/zh-cn/blog/Configuration Conclude.html",
+      "meta": {}
+    },
+    {
+      "filename": "Guides for upgrading to 2.7.x.md",
+      "link": "/zh-cn/blog/Guides for upgrading to 2.7.x.html",
+      "meta": {}
+    },
+    {
       "filename": "apachecon-na-2018.md",
       "link": "/zh-cn/blog/apachecon-na-2018.html",
       "meta": {}
@@ -321,6 +331,15 @@
       }
     },
     {
+      "filename": "dubbo-heartbeat-design.md",
+      "link": "/zh-cn/blog/dubbo-heartbeat-design.html",
+      "meta": {
+        "title": "Dubbo 现有心跳方案总结以及改进建议",
+        "keywords": "Dubbo, 心跳",
+        "description": "一种心跳,两种设计"
+      }
+    },
+    {
       "filename": "dubbo-integrate-with-hystrix.md",
       "link": "/zh-cn/blog/dubbo-integrate-with-hystrix.html",
       "meta": {
diff --git a/zh-cn/blog/Configuration Conclude.html b/zh-cn/blog/Configuration 
Conclude.html
new file mode 100644
index 0000000..86bef09
--- /dev/null
+++ b/zh-cn/blog/Configuration Conclude.html    
@@ -0,0 +1,189 @@
+<!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="Configuration Conclude" />
+       <meta name="description" content="Configuration Conclude" />
+       <!-- 网页标签标题 -->
+       <title>Configuration Conclude</title>
+       <link rel="shortcut icon" href="/img/dubbo.ico"/>
+       <link rel="stylesheet" href="/build/blogDetail.css" />
+</head>
+<body>
+       <div id="root"><div class="blog-detail-page" data-reactroot=""><header 
class="header-container header-container-normal"><div class="header-body"><a 
href="/zh-cn/index.html"><img class="logo" 
src="/img/dubbo_colorful.png"/></a><div class="search search-normal"><span 
class="icon-search"></span></div><span class="language-switch 
language-switch-normal">En</span><div class="header-menu"><img 
class="header-menu-toggle" src="/img/menu_gray.png"/><ul><li class="menu-item 
menu-item-normal"><a h [...]
+<p>我们这篇文章主要讲在<strong>应用启动阶段,Dubbo框架如何将所需要的配置采集起来</strong>(包括应用配置、注册中心配置、服务配置等),以完成服务的暴露和引用流程。</p>
+<p>根据驱动方式的不同(比如Spring或裸API编程)配置形式上肯定会有所差异,这个我们接下来会对<a 
href="#%E5%87%A0%E7%A7%8D%E7%BC%96%E7%A8%8B%E9%85%8D%E7%BD%AE%E6%96%B9%E5%BC%8F">每种方式分别展开介绍</a>。除了外围驱动方式上的差异,Dubbo的配置读取总体上遵循了以下几个原则:</p>
+<ol>
+<li>Dubbo支持了多层级的配置,并预定按优先级自动实现配置间的覆盖,最终被汇总到数据总线URL驱动后续的服务暴露、引用等流程。</li>
+<li>ApplicationConfig、ServiceConfig、ReferenceConfig可以被理解成配置来源的一种,是直接面向用户编程的配置采集方式。</li>
+<li>配置格式以Properties为主,在key的命名上有一套自己的<a 
href="#%E9%85%8D%E7%BD%AE%E6%A0%BC%E5%BC%8F">规范</a></li>
+</ol>
+<h2>配置来源</h2>
+<p>首先,从Dubbo支持的配置来源说起,默认有四种配置来源:</p>
+<ul>
+<li>JVM System Properties,-D参数</li>
+<li>Externalized Configuration,外部化配置</li>
+<li>ServiceConfig、ReferenceConfig等编程接口采集的配置</li>
+<li>本地配置文件dubbo.properties</li>
+</ul>
+<h3>覆盖关系</h3>
+<p>下图展示了配置覆盖关系的优先级,从上到下优先级依次降低:</p>
+<p><img src="../../img/blog/configuration.jpg" alt="覆盖关系"></p>
+<h3>外部化配置</h3>
+<p>外部化配置即Config 
Center是2.7.0中新引入的一种配置源,目的是能实现配置的集中式管理,对于配置集中管理业界已经有很多成熟的专业配置系统如Apollo, 
Nacos等,Dubbo所做的只是保证能配合这些系统正常工作。</p>
+<p>2.7.0版本开始支持<code>Zookeeper</code>、<code>Apollo</code>两种配置存储。</p>
+<p>以Zookeeper为例,外部化配置就是存储在<code>/dubbo/config/dubbo/dubbo.properties</code>路径下的<code>.properties</code>文件:</p>
+<pre><code class="language-properties"><span class="hljs-comment"># 
将注册中心地址、元数据中心地址等配置集中管理,可以做到统一环境、减少开发侧感知。</span>
+<span class="hljs-meta">dubbo.registry.address</span>=<span 
class="hljs-string">zookeeper://127.0.0.1:2181</span>
+<span class="hljs-meta">dubbo.registry.simplified</span>=<span 
class="hljs-string">true</span>
+
+<span class="hljs-meta">dubbo.metadataReport.address</span>=<span 
class="hljs-string">zookeeper://127.0.0.1:2181</span>
+
+<span class="hljs-meta">dubbo.protocol.name</span>=<span 
class="hljs-string">dubbo</span>
+<span class="hljs-meta">dubbo.protocol.port</span>=<span 
class="hljs-string">20880</span>
+
+<span class="hljs-meta">dubbo.application.qos.port</span>=<span 
class="hljs-string">33333</span>
+</code></pre>
+<p>所谓Dubbo对这些配置中心的支持,本质上就是把<code>.properties</code>从远程拉取到本地,然后和本地的配置做一次融合。所以理论上只要Dubbo框架能拿到需要的配置就可以正常的工作,所以Dubbo还提供了以下API,让用户将自己组织好的配置塞给Dubbo框架(至于配置从哪里来是用户要完成的事情),这样Dubbo框架就不再直接和Apollo或Zookeeper做读取配置交互。</p>
+<pre><code class="language-java">Map&lt;String, String&gt; dubboConfigurations 
= <span class="hljs-keyword">new</span> HashMap&lt;&gt;();
+dubboConfigurations.put(<span 
class="hljs-string">"dubbo.registry.address"</span>, <span 
class="hljs-string">"zookeeper://127.0.0.1:2181"</span>);
+dubboConfigurations.put(<span 
class="hljs-string">"dubbo.registry.simplified"</span>, <span 
class="hljs-string">"true"</span>);
+
+ConfigCenterConfig configCenter = <span class="hljs-keyword">new</span> 
ConfigCenterConfig();
+configCenter.setExternalConfig(dubboConfigurations);
+</code></pre>
+<h2>配置格式</h2>
+<p>目前Dubbo支持的所有配置都是<code>.properties</code>格式的,包括<code>-D</code>、<code>Externalized
 
Configuration</code>等,<code>.properties</code>中的所有配置项遵循一种<code>path-based</code>的配置格式:</p>
+<pre><code class="language-properties"><span class="hljs-comment"># 应用级别</span>
+<span 
class="hljs-meta">dubbo.{config-type}[.{config-id}].{config-item}</span>=<span 
class="hljs-string">{config-item-value}</span>
+<span class="hljs-comment"># 服务级别</span>
+<span 
class="hljs-meta">dubbo.service.{interface-name}[.{method-name}].{config-item}</span>=<span
 class="hljs-string">{config-item-value}</span>
+<span 
class="hljs-meta">dubbo.reference.{interface-name}[.{method-name}].{config-item}</span>=<span
 class="hljs-string">{config-item-value}</span>
+<span class="hljs-comment"># 多配置项</span>
+<span 
class="hljs-meta">dubbo.{config-type}s.{config-id}.{config-item}</span>=<span 
class="hljs-string">{config-item-value}</span>
+</code></pre>
+<ul>
+<li>应用级别</li>
+</ul>
+<pre><code class="language-properties"><span 
class="hljs-meta">dubbo.application.name</span>=<span 
class="hljs-string">demo-provider</span>
+<span class="hljs-meta">dubbo.registry.address</span>=<span 
class="hljs-string">zookeeper://127.0.0.1:2181</span>
+<span class="hljs-meta">dubbo.protocol.port</span>=<span 
class="hljs-string">-1</span>
+</code></pre>
+<ul>
+<li>服务级别</li>
+</ul>
+<pre><code class="language-properties"><span 
class="hljs-meta">dubbo.service.org.apache.dubbo.samples.api.DemoService.timeout</span>=<span
 class="hljs-string">5000</span>
+<span 
class="hljs-meta">dubbo.reference.org.apache.dubbo.samples.api.DemoService.tineout</span>=<span
 class="hljs-string">6000</span>
+<span 
class="hljs-meta">dubbo.reference.org.apache.dubbo.samples.api.DemoService.sayHello.timeout</span>=<span
 class="hljs-string">7000</span>
+</code></pre>
+<ul>
+<li>多配置项</li>
+</ul>
+<pre><code class="language-properties"><span 
class="hljs-meta">dubbo.registries.unit1.address</span>=<span 
class="hljs-string">zookeeper://127.0.0.1:2181</span>
+<span class="hljs-meta">dubbo.registries.unit2.address</span>=<span 
class="hljs-string">zookeeper://127.0.0.1:2182</span>
+
+<span class="hljs-meta">dubbo.protocols.dubbo.name</span>=<span 
class="hljs-string">dubbo</span>
+<span class="hljs-meta">dubbo.protocols.dubbo.port</span>=<span 
class="hljs-string">20880</span>
+<span class="hljs-meta">dubbo.protocols.hessian.name</span>=<span 
class="hljs-string">hessian</span>
+<span class="hljs-meta">dubbo.protocols.hessian.port</span>=<span 
class="hljs-string">8089</span>
+</code></pre>
+<h2>几种编程配置方式</h2>
+<p>接下来,我们看一下选择不同的开发方式时,对应到<code>ServiceConfig、ReferenceConfig等编程接口采集的配置</code>的变化。</p>
+<h3>Spring</h3>
+<ul>
+<li>XML</li>
+</ul>
+<p>参见<a 
href="https://github.com/apache/incubator-dubbo-samples/tree/master/dubbo-samples-basic";>示例</a></p>
+<pre><code class="language-xml">  <span class="hljs-comment">&lt;!-- 
dubbo-provier.xml --&gt;</span>
+  
+  <span class="hljs-tag">&lt;<span class="hljs-name">dubbo:application</span> 
<span class="hljs-attr">name</span>=<span 
class="hljs-string">"demo-provider"</span>/&gt;</span>
+  <span class="hljs-tag">&lt;<span class="hljs-name">dubbo:conig-center</span> 
<span class="hljs-attr">address</span>=<span 
class="hljs-string">"zookeeper://127.0.0.1:2181"</span>/&gt;</span>
+  
+  <span class="hljs-tag">&lt;<span class="hljs-name">dubbo:registry</span> 
<span class="hljs-attr">address</span>=<span 
class="hljs-string">"zookeeper://127.0.0.1:2181"</span> <span 
class="hljs-attr">simplified</span>=<span 
class="hljs-string">"true"</span>/&gt;</span>
+  <span class="hljs-tag">&lt;<span 
class="hljs-name">dubbo:metadata-report</span> <span 
class="hljs-attr">address</span>=<span 
class="hljs-string">"redis://127.0.0.1:6379"</span>/&gt;</span>
+  <span class="hljs-tag">&lt;<span class="hljs-name">dubbo:protocol</span> 
<span class="hljs-attr">name</span>=<span class="hljs-string">"dubbo"</span> 
<span class="hljs-attr">port</span>=<span 
class="hljs-string">"20880"</span>/&gt;</span>
+  
+  <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.samples.basic.impl.DemoServiceImpl"</span>/&gt;</span>
+  <span class="hljs-tag">&lt;<span class="hljs-name">dubbo:service</span> 
<span class="hljs-attr">interface</span>=<span 
class="hljs-string">"org.apache.dubbo.samples.basic.api.DemoService"</span> 
<span class="hljs-attr">ref</span>=<span 
class="hljs-string">"demoService"</span>/&gt;</span>
+</code></pre>
+<ul>
+<li>Annotation</li>
+</ul>
+<p>参见<a 
href="https://github.com/apache/incubator-dubbo-samples/tree/master/dubbo-samples-annotation";>示例</a></p>
+<pre><code class="language-java">  <span class="hljs-comment">// 
AnnotationService服务实现</span>
+  
+  <span class="hljs-meta">@Service</span>
+  <span class="hljs-keyword">public</span> <span class="hljs-class"><span 
class="hljs-keyword">class</span> <span 
class="hljs-title">AnnotationServiceImpl</span> <span 
class="hljs-keyword">implements</span> <span 
class="hljs-title">AnnotationService</span> </span>{
+      <span class="hljs-meta">@Override</span>
+      <span class="hljs-function"><span class="hljs-keyword">public</span> 
String <span class="hljs-title">sayHello</span><span 
class="hljs-params">(String name)</span> </span>{
+          System.out.println(<span class="hljs-string">"async provider 
received: "</span> + name);
+          <span class="hljs-keyword">return</span> <span 
class="hljs-string">"annotation: hello, "</span> + name;
+      }
+  }
+</code></pre>
+<pre><code class="language-properties"><span class="hljs-comment">  ## 
dubbo.properties</span>
+  
+  <span class="hljs-meta">dubbo.application.name</span>=<span 
class="hljs-string">annotation-provider</span>
+  <span class="hljs-meta">dubbo.registry.address</span>=<span 
class="hljs-string">zookeeper://127.0.0.1:2181</span>
+  <span class="hljs-meta">dubbo.protocol.name</span>=<span 
class="hljs-string">dubbo</span>
+  <span class="hljs-meta">dubbo.protocol.port</span>=<span 
class="hljs-string">20880</span>
+</code></pre>
+<ul>
+<li>Spring Boot</li>
+</ul>
+<p>参见<a 
href="https://github.com/apache/incubator-dubbo-spring-boot-project/tree/master/dubbo-spring-boot-samples";>示例</a></p>
+<pre><code class="language-properties"><span class="hljs-comment">  ## 
application.properties</span>
+<span class="hljs-comment">  
+  # Spring boot application</span>
+  <span class="hljs-meta">spring.application.name</span>=<span 
class="hljs-string">dubbo-externalized-configuration-provider-sample</span>
+<span class="hljs-comment">  
+  # Base packages to scan Dubbo Component: 
@com.alibaba.dubbo.config.annotation.Service</span>
+  <span class="hljs-meta">dubbo.scan.base-packages</span>=<span 
class="hljs-string">com.alibaba.boot.dubbo.demo.provider.service</span>
+<span class="hljs-comment">  
+  # Dubbo Application</span>
+<span class="hljs-comment">  ## The default value of dubbo.application.name is 
${spring.application.name}</span>
+<span class="hljs-comment">  ## 
dubbo.application.name=${spring.application.name}</span>
+<span class="hljs-comment">  
+  # Dubbo Protocol</span>
+  <span class="hljs-meta">dubbo.protocol.name</span>=<span 
class="hljs-string">dubbo</span>
+  <span class="hljs-meta">dubbo.protocol.port</span>=<span 
class="hljs-string">12345</span>
+<span class="hljs-comment">  
+  ## Dubbo Registry</span>
+  <span class="hljs-meta">dubbo.registry.address</span>=<span 
class="hljs-string">N/A</span>
+<span class="hljs-comment">  
+  ## DemoService version</span>
+  <span class="hljs-meta">demo.service.version</span>=<span 
class="hljs-string">1.0.0</span>
+</code></pre>
+<h3>API</h3>
+<pre><code class="language-java"><span class="hljs-function"><span 
class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> 
<span class="hljs-keyword">void</span> <span 
class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> 
<span class="hljs-keyword">throws</span> IOException </span>{
+    ServiceConfig&lt;GreetingsService&gt; service = <span 
class="hljs-keyword">new</span> ServiceConfig&lt;&gt;();
+    service.setApplication(<span class="hljs-keyword">new</span> 
ApplicationConfig(<span class="hljs-string">"first-dubbo-provider"</span>));
+    service.setRegistry(<span class="hljs-keyword">new</span> 
RegistryConfig(<span class="hljs-string">"multicast://224.5.6.7:1234"</span>));
+    service.setInterface(GreetingsService.class);
+    service.setRef(<span class="hljs-keyword">new</span> 
GreetingsServiceImpl());
+    service.export();
+    System.out.println(<span class="hljs-string">"first-dubbo-provider is 
running."</span>);
+    System.in.read();
+}
+</code></pre>
+<p>参考<a 
href="https://github.com/apache/incubator-dubbo-samples/tree/master/dubbo-samples-api";>示例</a></p>
+</section><footer class="footer-container"><div class="footer-body"><img 
src="/img/dubbo_gray.png"/><img class="apache" src="/img/apache_logo.png"/><div 
class="cols-container"><div class="col col-12"><h3>Disclaimer</h3><p>Apache 
Dubbo is an effort undergoing incubation at The Apache Software Foundation 
(ASF), sponsored by the Incubator. Incubation is required of all newly accepted 
projects until a further review indicates that the infrastructure, 
communications, and decision making proce [...]
+       <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/zh-cn/blog/Configuration Conclude.json b/zh-cn/blog/Configuration 
Conclude.json
new file mode 100644
index 0000000..2f463fb
--- /dev/null
+++ b/zh-cn/blog/Configuration Conclude.json    
@@ -0,0 +1,6 @@
+{
+  "filename": "Configuration Conclude.md",
+  "__html": 
"<h1>配置方式总结</h1>\n<p>我们这篇文章主要讲在<strong>应用启动阶段,Dubbo框架如何将所需要的配置采集起来</strong>(包括应用配置、注册中心配置、服务配置等),以完成服务的暴露和引用流程。</p>\n<p>根据驱动方式的不同(比如Spring或裸API编程)配置形式上肯定会有所差异,这个我们接下来会对<a
 
href=\"#%E5%87%A0%E7%A7%8D%E7%BC%96%E7%A8%8B%E9%85%8D%E7%BD%AE%E6%96%B9%E5%BC%8F\">每种方式分别展开介绍</a>。除了外围驱动方式上的差异,Dubbo的配置读取总体上遵循了以下几个原则:</p>\n<ol>\n<li>Dubbo支持了多层级的配置,并预定按优先级自动实现配置间的覆盖,最终被汇总到数据总线URL驱动后续的服务暴露、引用等流程。</li>\n<li>ApplicationConfig、ServiceConfig、ReferenceConfig可以被理解成配置来源的一种,是直接面向用户编程的配置采集方式。</li>\n<
 [...]
+  "link": "/zh-cn/blog/Configuration Conclude.html",
+  "meta": {}
+}
\ No newline at end of file
diff --git a/zh-cn/blog/Guides for upgrading to 2.7.x.html b/zh-cn/blog/Guides 
for upgrading to 2.7.x.html
new file mode 100644
index 0000000..9833fba
--- /dev/null
+++ b/zh-cn/blog/Guides for upgrading to 2.7.x.html     
@@ -0,0 +1,342 @@
+<!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="Guides for upgrading to 2.7.x" />
+       <meta name="description" content="Guides for upgrading to 2.7.x" />
+       <!-- 网页标签标题 -->
+       <title>Guides for upgrading to 2.7.x</title>
+       <link rel="shortcut icon" href="/img/dubbo.ico"/>
+       <link rel="stylesheet" href="/build/blogDetail.css" />
+</head>
+<body>
+       <div id="root"><div class="blog-detail-page" data-reactroot=""><header 
class="header-container header-container-normal"><div class="header-body"><a 
href="/zh-cn/index.html"><img class="logo" 
src="/img/dubbo_colorful.png"/></a><div class="search search-normal"><span 
class="icon-search"></span></div><span class="language-switch 
language-switch-normal">En</span><div class="header-menu"><img 
class="header-menu-toggle" src="/img/menu_gray.png"/><ul><li class="menu-item 
menu-item-normal"><a h [...]
+<p>环境要求:需要<strong>Java 8</strong>及以上版本。</p>
+<p>2.7.0版本在改造的过程中遵循了一个原则,即<strong>保持与低版本的兼容性,因此从功能层面来说它是与2.6.x及更低版本完全兼容的</strong>。这里所说的兼容性主要是和<a
 
href="#%E5%8C%85%E5%90%8D%E6%94%B9%E9%80%A0">包重命名</a>相关的,接下来会详细说明影响点。另外,虽然功能用法保持向后兼容,但参考本文能帮助您尽快用到2.7.0版本的新特性。</p>
+<h2>升级步骤</h2>
+<ol>
+<li>升级pom到2.7.0(以all-in-one依赖为例)。</li>
+</ol>
+<pre><code class="language-xml"><span class="hljs-tag">&lt;<span 
class="hljs-name">properties</span>&gt;</span>
+    <span class="hljs-tag">&lt;<span 
class="hljs-name">dubbo.version</span>&gt;</span>2.7.0<span 
class="hljs-tag">&lt;/<span class="hljs-name">dubbo.version</span>&gt;</span>
+<span class="hljs-tag">&lt;/<span 
class="hljs-name">properties</span>&gt;</span>
+<span class="hljs-tag">&lt;<span 
class="hljs-name">dependencyManagement</span>&gt;</span>
+    <span class="hljs-tag">&lt;<span 
class="hljs-name">dependencies</span>&gt;</span>
+        <span class="hljs-tag">&lt;<span 
class="hljs-name">dependency</span>&gt;</span>
+            <span class="hljs-tag">&lt;<span 
class="hljs-name">groupId</span>&gt;</span>org.apache.dubbo<span 
class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
+            <span class="hljs-tag">&lt;<span 
class="hljs-name">artifactId</span>&gt;</span>dubbo-dependencies-bom<span 
class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
+            <span class="hljs-tag">&lt;<span 
class="hljs-name">version</span>&gt;</span>${dubbo.version}<span 
class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
+            <span class="hljs-tag">&lt;<span 
class="hljs-name">type</span>&gt;</span>pom<span class="hljs-tag">&lt;/<span 
class="hljs-name">type</span>&gt;</span>
+            <span class="hljs-tag">&lt;<span 
class="hljs-name">scope</span>&gt;</span>import<span 
class="hljs-tag">&lt;/<span class="hljs-name">scope</span>&gt;</span>
+        <span class="hljs-tag">&lt;/<span 
class="hljs-name">dependency</span>&gt;</span>
+    <span class="hljs-tag">&lt;/<span 
class="hljs-name">dependencies</span>&gt;</span>
+<span class="hljs-tag">&lt;/<span 
class="hljs-name">dependencyManagement</span>&gt;</span>
+
+<span class="hljs-tag">&lt;<span 
class="hljs-name">dependencies</span>&gt;</span>
+    <span class="hljs-tag">&lt;<span 
class="hljs-name">dependency</span>&gt;</span>
+        <span class="hljs-tag">&lt;<span 
class="hljs-name">groupId</span>&gt;</span>org.apache.dubbo<span 
class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
+        <span class="hljs-tag">&lt;<span 
class="hljs-name">artifactId</span>&gt;</span>dubbo<span 
class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
+        <span class="hljs-tag">&lt;<span 
class="hljs-name">version</span>&gt;</span>${dubbo.version}<span 
class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
+    <span class="hljs-tag">&lt;/<span 
class="hljs-name">dependency</span>&gt;</span>
+    <span class="hljs-tag">&lt;<span 
class="hljs-name">dependency</span>&gt;</span>
+        <span class="hljs-tag">&lt;<span 
class="hljs-name">groupId</span>&gt;</span>io.netty<span 
class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
+        <span class="hljs-tag">&lt;<span 
class="hljs-name">artifactId</span>&gt;</span>netty-all<span 
class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
+    <span class="hljs-tag">&lt;/<span 
class="hljs-name">dependency</span>&gt;</span>
+<span class="hljs-tag">&lt;/<span 
class="hljs-name">dependencies</span>&gt;</span>
+</code></pre>
+<p>如果升级依赖后出现API或SPI扩展相关的编译错误,请参考<a 
href="#%E5%8C%85%E5%90%8D%E6%94%B9%E9%80%A0">包兼容性问题</a></p>
+<p>此时重新部署应用,所有默认行为和2.6.x保持一致,如果要用到2.7的新特性,则需要继续做以下配置(可选):</p>
+<ul>
+<li>简化的URL</li>
+<li>配置元数据中心</li>
+<li>使用外部化配置</li>
+<li>服务治理规则</li>
+<li>使用异步API</li>
+</ul>
+<p>下面我们就对这几部分的配置分别做详细说明。</p>
+<h4>简化的URL</h4>
+<pre><code class="language-xml"><span class="hljs-comment">&lt;!-- 
simplified="true"表示注册简化版的URL到Registry --&gt;</span>
+<span class="hljs-tag">&lt;<span class="hljs-name">dubbo:registry</span> <span 
class="hljs-attr">address</span>=<span 
class="hljs-string">"zookeeper://127.0.0.1:2181"</span> <span 
class="hljs-attr">simplified</span>=<span 
class="hljs-string">"true"</span>/&gt;</span>
+</code></pre>
+<pre><code class="language-properties"><span 
class="hljs-meta">dubbo.registry.simplified</span>=<span 
class="hljs-string">true</span>
+</code></pre>
+<p>建议将此配置集中管理,参考<a 
href="#%E4%BD%BF%E7%94%A8%E5%A4%96%E9%83%A8%E5%8C%96%E9%85%8D%E7%BD%AE">外部化配置</a>。</p>
+<blockquote>
+<p>URL简化只是剔除了一些纯粹的查询用的参数,并没有做大刀阔斧的服务发现模型改造,因此精简后的URL完全可以被2.6及以下版本的消费端实现服务发现与调用,同样2.7版本也可以发现和调用低版本的提供者。</p>
+</blockquote>
+<h4>配置元数据中心</h4>
+<pre><code class="language-xml"><span class="hljs-tag">&lt;<span 
class="hljs-name">dubbo:metadata-report</span> <span 
class="hljs-attr">address</span>=<span 
class="hljs-string">"redis://127.0.0.1:6379"</span>/&gt;</span>
+</code></pre>
+<pre><code class="language-properties"><span 
class="hljs-meta">dubbo.metadataReport.address</span>=<span 
class="hljs-string">redis://127.0.0.1:6379</span>
+</code></pre>
+<p>建议将此配置集中管理,参考<a 
href="#%E4%BD%BF%E7%94%A8%E5%A4%96%E9%83%A8%E5%8C%96%E9%85%8D%E7%BD%AE">外部化配置</a>。
+<a href="">元数据中心</a>设计及用途,请参考文档。</p>
+<h4>使用外部化配置</h4>
+<p>需要在项目启动前,使用<a 
href="https://github.com/apache/incubator-dubbo-ops";>最新版本Dubbo-OPS</a>完成外部化配置迁移,理论上配置中心支持所有本地dubbo.properties所支持的配置项。</p>
+<p>以XML开发形式为例,假设我们本地有如下配置:</p>
+<pre><code class="language-xml"><span class="hljs-tag">&lt;<span 
class="hljs-name">dubbo:application</span> <span 
class="hljs-attr">name</span>=<span 
class="hljs-string">"demo-provider"</span>/&gt;</span>
+<span class="hljs-tag">&lt;<span class="hljs-name">dubbo:conig-center</span> 
<span class="hljs-attr">address</span>=<span 
class="hljs-string">"zookeeper://127.0.0.1:2181"</span>/&gt;</span>
+
+<span class="hljs-tag">&lt;<span class="hljs-name">dubbo:registry</span> <span 
class="hljs-attr">address</span>=<span 
class="hljs-string">"zookeeper://127.0.0.1:2181"</span> <span 
class="hljs-attr">simplified</span>=<span 
class="hljs-string">"true"</span>/&gt;</span>
+<span class="hljs-tag">&lt;<span 
class="hljs-name">dubbo:metadata-report</span> <span 
class="hljs-attr">address</span>=<span 
class="hljs-string">"redis://127.0.0.1:6379"</span>/&gt;</span>
+<span class="hljs-tag">&lt;<span class="hljs-name">dubbo:protocol</span> <span 
class="hljs-attr">name</span>=<span class="hljs-string">"dubbo"</span> <span 
class="hljs-attr">port</span>=<span 
class="hljs-string">"20880"</span>/&gt;</span>
+
+<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.samples.basic.impl.DemoServiceImpl"</span>/&gt;</span>
+<span class="hljs-tag">&lt;<span class="hljs-name">dubbo:service</span> <span 
class="hljs-attr">interface</span>=<span 
class="hljs-string">"org.apache.dubbo.samples.basic.api.DemoService"</span> 
<span class="hljs-attr">ref</span>=<span 
class="hljs-string">"demoService"</span>/&gt;</span>
+</code></pre>
+<p>通过<a 
href="http://47.91.207.147/#/management?key=global";>OPS控制台</a>将以下全局配置迁移到配置中心,成为所有应用共享的配置。</p>
+<pre><code class="language-properties"><span 
class="hljs-meta">dubbo.registry.address</span>=<span 
class="hljs-string">zookeeper://127.0.0.1:2181</span>
+<span class="hljs-meta">dubbo.registry.simplified</span>=<span 
class="hljs-string">true</span>
+
+<span class="hljs-meta">dubbo.metadataReport.address</span>=<span 
class="hljs-string">redis://127.0.0.1:6379</span>
+
+<span class="hljs-meta">dubbo.protocol.name</span>=<span 
class="hljs-string">dubbo</span>
+<span class="hljs-meta">dubbo.protocol.port</span>=<span 
class="hljs-string">20880</span>
+</code></pre>
+<p>这样应用开发者只需要关心配置中心的配置。</p>
+<pre><code class="language-xml"><span class="hljs-tag">&lt;<span 
class="hljs-name">dubbo:application</span> <span 
class="hljs-attr">name</span>=<span 
class="hljs-string">"demo-provider"</span>/&gt;</span>
+<span class="hljs-tag">&lt;<span class="hljs-name">dubbo:conig-center</span> 
<span class="hljs-attr">address</span>=<span 
class="hljs-string">"zookeeper://127.0.0.1:2181"</span>/&gt;</span>
+
+<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.samples.basic.impl.DemoServiceImpl"</span>/&gt;</span>
+<span class="hljs-tag">&lt;<span class="hljs-name">dubbo:service</span> <span 
class="hljs-attr">interface</span>=<span 
class="hljs-string">"org.apache.dubbo.samples.basic.api.DemoService"</span> 
<span class="hljs-attr">ref</span>=<span 
class="hljs-string">"demoService"</span>/&gt;</span>
+</code></pre>
+<p>这里增加了一篇<a href="">Dubbo配置方式</a>的说明文档,详细描述了Dubbo当前支持的配置类型、不同配置之间的覆盖关系等。</p>
+<h4>服务治理规则迁移</h4>
+<p>2.7版本可以读取到老的治理规则,因此不用担心升级2.7的应用后老规则会失效,可以选择先升级上线,再慢慢的做增量式规则迁移。</p>
+<p>请参考<a href="http://47.91.207.147/#/governance/routingRule";>OPS -&gt; 
服务治理</a>了解规则配置方式,这里我们重点关注的是规则格式,以下提供几个简单示例:</p>
+<ul>
+<li>
+<p>条件路由</p>
+<pre><code class="language-yaml"><span class="hljs-meta">---</span>
+<span class="hljs-attr">scope:</span> <span 
class="hljs-string">application</span>
+<span class="hljs-attr">force:</span> <span class="hljs-literal">true</span>
+<span class="hljs-attr">runtime:</span> <span class="hljs-literal">true</span>
+<span class="hljs-attr">enabled:</span> <span class="hljs-literal">true</span>
+<span class="hljs-attr">key:</span> <span 
class="hljs-string">governance-conditionrouter-consumer</span>
+<span class="hljs-attr">conditions:</span>
+<span class="hljs-bullet">-</span> <span 
class="hljs-string">method=sayHello</span> <span 
class="hljs-string">=&gt;</span> <span 
class="hljs-string">address=*:20880</span>
+<span class="hljs-bullet">-</span> <span 
class="hljs-string">method=sayHi</span> <span class="hljs-string">=&gt;</span> 
<span class="hljs-string">address=*:20881</span>
+<span class="hljs-string">...</span>
+</code></pre>
+</li>
+<li>
+<p>标签路由</p>
+<pre><code class="language-yaml"><span class="hljs-meta">---</span>
+<span class="hljs-attr">force:</span> <span class="hljs-literal">false</span>
+<span class="hljs-attr">runtime:</span> <span class="hljs-literal">true</span>
+<span class="hljs-attr">enabled:</span> <span class="hljs-literal">true</span>
+<span class="hljs-attr">key:</span> <span 
class="hljs-string">governance-tagrouter-provider</span>
+<span class="hljs-attr">tags:</span>
+<span class="hljs-attr">- name:</span> <span class="hljs-string">tag1</span>
+<span class="hljs-attr">addresses:</span> <span 
class="hljs-string">["127.0.0.1:20880"]</span>
+<span class="hljs-attr">- name:</span> <span class="hljs-string">tag2</span>
+<span class="hljs-attr">addresses:</span> <span 
class="hljs-string">["127.0.0.1:20881"]</span>
+<span class="hljs-string">...</span>
+</code></pre>
+</li>
+<li>
+<p>动态配置(覆盖规则)</p>
+<pre><code class="language-yaml"><span class="hljs-meta">---</span>
+<span class="hljs-attr">scope:</span> <span class="hljs-string">service</span>
+<span class="hljs-attr">key:</span> <span 
class="hljs-string">org.apache.dubbo.samples.governance.api.DemoService</span>
+<span class="hljs-attr">enabled:</span> <span class="hljs-literal">true</span>
+<span class="hljs-attr">configs:</span>
+<span class="hljs-attr">- addresses:</span> <span 
class="hljs-string">[0.0.0.0]</span>
+<span class="hljs-attr">  side:</span> <span 
class="hljs-string">consumer</span>
+<span class="hljs-attr">  parameters:</span>
+<span class="hljs-attr">    timeout:</span> <span 
class="hljs-number">6000</span>
+<span class="hljs-string">...</span>
+</code></pre>
+</li>
+</ul>
+<p>关于治理规则更多详细说明,请参考<a href="">路由规则</a>和<a href="">覆盖规则</a>用户文档。</p>
+<p>也可继续了解<a href="">使用示例</a>。</p>
+<h4>使用异步API</h4>
+<p>这部分的接口和低版本同样是完全兼容的,你仅须在打算使用CompletableFuture<T>提供的回调或者异步组装能力时,再考虑升级这部分内容即可。</p>
+<ul>
+<li>
+<p>定义CompletableFuture<T>类型接口</p>
+</li>
+<li>
+<p>同步签名接口实现Provider端异步执行</p>
+</li>
+<li>
+<p>感知异步返回值的Filter链路</p>
+</li>
+</ul>
+<p>点击链接,了解关于异步API如何使用的更多<a href="">使用示例</a>。</p>
+<h2>包名改造</h2>
+<ol>
+<li>Maven坐标</li>
+</ol>
+<p><strong>groupId 由 <code>com.alibaba</code> 改为 
<code>org.apache.dubbo</code></strong></p>
+<ol start="2">
+<li>package</li>
+</ol>
+<p><strong>package 由 <code>com.alibaba.dubbo</code> 改为 
<code>org.apache.dubbo</code></strong></p>
+<p>Maven坐标升级比较直观,只需要修改相应的pom文件就可以了;而package变更则可能会带来编译问题,升级过程需要用户修改代码。因此为了减少用户升级成本,让用户可以做到渐进式升级,2.7.0版本继续保留了一些常用基础API和SP<code>com.alibaba.dubb</code>的支持。</p>
+<h4>API编程接口</h4>
+<ul>
+<li>注解</li>
+</ul>
+<table>
+<thead>
+<tr>
+<th>注解</th>
+<th>说明</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>@Reference</td>
+<td>消费端服务引用注解</td>
+</tr>
+<tr>
+<td>@Service</td>
+<td>提供端服务暴露注解</td>
+</tr>
+<tr>
+<td>@EnableDubbo</td>
+<td></td>
+</tr>
+<tr>
+<td>其他常用Spring注解API</td>
+<td></td>
+</tr>
+</tbody>
+</table>
+<ul>
+<li>编程API</li>
+</ul>
+<table>
+<thead>
+<tr>
+<th>API</th>
+<th>说明</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>ReferenceConfig</td>
+<td>Service配置采集和引用编程接口</td>
+</tr>
+<tr>
+<td>ServiceConfig</td>
+<td>Service配置采集和暴露编程接口</td>
+</tr>
+<tr>
+<td>ApplicationConfig</td>
+<td>Application配置采集API</td>
+</tr>
+<tr>
+<td>RegistryConfig</td>
+<td>注册中心配置采集API</td>
+</tr>
+<tr>
+<td>ConsumerConfig</td>
+<td>提供端默认配置采集API</td>
+</tr>
+<tr>
+<td>ProviderConfig</td>
+<td>消费端默认配置采集API</td>
+</tr>
+<tr>
+<td>ProtocolConfig</td>
+<td>RPC协议配置采集API</td>
+</tr>
+<tr>
+<td>ArcumentConfig</td>
+<td>服务参数级配置采集API</td>
+</tr>
+<tr>
+<td>MethodConfig</td>
+<td>服务方法级配置采集API</td>
+</tr>
+<tr>
+<td>ModuleConfig</td>
+<td>服务治理Module配置采集API</td>
+</tr>
+<tr>
+<td>MonitorConfig</td>
+<td>监控配置采集API</td>
+</tr>
+<tr>
+<td>RpcContext</td>
+<td>编程上下文API</td>
+</tr>
+</tbody>
+</table>
+<h4>SPI扩展</h4>
+<blockquote>
+<p>如果公司内部有维护的自定义SPI扩展库,在业务工程升级到2.7.0之前,请务必先确保扩展库与2.7.0的兼容性。如果发现有兼容性问题,请通过修改包名引用的方式完成升级,并重新打包。</p>
+</blockquote>
+<table>
+<thead>
+<tr>
+<th>SPI扩展点</th>
+<th>说明</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>Registry</td>
+<td>包括<code>RegistryFactory</code>, <code>Registry</code> 
,<code>RegistryService</code>等扩展点</td>
+</tr>
+<tr>
+<td>Protocol</td>
+<td>RPC协议扩展</td>
+</tr>
+<tr>
+<td>Serialization</td>
+<td>序列化协议扩展</td>
+</tr>
+<tr>
+<td>Cluster</td>
+<td>集群容错策略扩展,如Failover, Failfast等</td>
+</tr>
+<tr>
+<td>Loadbalance</td>
+<td>负载均衡策略扩展</td>
+</tr>
+<tr>
+<td>Transporter</td>
+<td>传输框架扩展,如Netty等</td>
+</tr>
+<tr>
+<td>Monitor</td>
+<td>监控中心扩展,包括MonitorFactory, Monitor, MonitorService等</td>
+</tr>
+<tr>
+<td>Router</td>
+<td>路由规则扩展</td>
+</tr>
+<tr>
+<td>Filter</td>
+<td>拦截器扩展</td>
+</tr>
+</tbody>
+</table>
+<h2>FAQ</h2>
+<ol>
+<li>升级后启动出现curator依赖报错</li>
+</ol>
+</section><footer class="footer-container"><div class="footer-body"><img 
src="/img/dubbo_gray.png"/><img class="apache" src="/img/apache_logo.png"/><div 
class="cols-container"><div class="col col-12"><h3>Disclaimer</h3><p>Apache 
Dubbo is an effort undergoing incubation at The Apache Software Foundation 
(ASF), sponsored by the Incubator. Incubation is required of all newly accepted 
projects until a further review indicates that the infrastructure, 
communications, and decision making proce [...]
+       <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/zh-cn/blog/Guides for upgrading to 2.7.x.json b/zh-cn/blog/Guides 
for upgrading to 2.7.x.json
new file mode 100644
index 0000000..940d461
--- /dev/null
+++ b/zh-cn/blog/Guides for upgrading to 2.7.x.json     
@@ -0,0 +1,6 @@
+{
+  "filename": "Guides for upgrading to 2.7.x.md",
+  "__html": "<h1>升级与可能的兼容性问题总结</h1>\n<p>环境要求:需要<strong>Java 
8</strong>及以上版本。</p>\n<p>2.7.0版本在改造的过程中遵循了一个原则,即<strong>保持与低版本的兼容性,因此从功能层面来说它是与2.6.x及更低版本完全兼容的</strong>。这里所说的兼容性主要是和<a
 
href=\"#%E5%8C%85%E5%90%8D%E6%94%B9%E9%80%A0\">包重命名</a>相关的,接下来会详细说明影响点。另外,虽然功能用法保持向后兼容,但参考本文能帮助您尽快用到2.7.0版本的新特性。</p>\n<h2>升级步骤</h2>\n<ol>\n<li>升级pom到2.7.0(以all-in-one依赖为例)。</li>\n</ol>\n<pre><code
 class=\"language-xml\"><span class=\"hljs-tag\">&lt;<span 
class=\"hljs-name\">properties</span>&gt;</span>\n    <spa [...]
+  "link": "/zh-cn/blog/Guides for upgrading to 2.7.x.html",
+  "meta": {}
+}
\ No newline at end of file
diff --git a/zh-cn/blog/dubbo-heartbeat-design.html 
b/zh-cn/blog/dubbo-heartbeat-design.html
new file mode 100644
index 0000000..f275b8b
--- /dev/null
+++ b/zh-cn/blog/dubbo-heartbeat-design.html
@@ -0,0 +1,358 @@
+<!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, 心跳" />
+       <meta name="description" content="一种心跳,两种设计" />
+       <!-- 网页标签标题 -->
+       <title>Dubbo 现有心跳方案总结以及改进建议</title>
+       <link rel="shortcut icon" href="/img/dubbo.ico"/>
+       <link rel="stylesheet" href="/build/blogDetail.css" />
+</head>
+<body>
+       <div id="root"><div class="blog-detail-page" data-reactroot=""><header 
class="header-container header-container-normal"><div class="header-body"><a 
href="/zh-cn/index.html"><img class="logo" 
src="/img/dubbo_colorful.png"/></a><div class="search search-normal"><span 
class="icon-search"></span></div><span class="language-switch 
language-switch-normal">En</span><div class="header-menu"><img 
class="header-menu-toggle" src="/img/menu_gray.png"/><ul><li class="menu-item 
menu-item-normal"><a h [...]
+<h3>1 前言</h3>
+<p>设计一个好的心跳机制并不是一件容易的事,就我所熟知的几个 RPC 
框架,它们的心跳机制可以说大相径庭,这篇文章我将探讨一下<strong>如何设计一个优雅的心跳机制,主要从 Dubbo 
的现有方案以及一个改进方案来做分析</strong>。</p>
+<h3>2 预备知识</h3>
+<p>因为后续我们将从源码层面来进行介绍,所以一些服务治理框架的细节还需要提前交代一下,方便大家理解。</p>
+<h4>2.1 客户端如何得知请求失败了?</h4>
+<p>高性能的 RPC 框架几乎都会选择使用 Netty 
来作为通信层的组件,非阻塞式通信的高效不需要我做过多的介绍。但也由于非阻塞的特性,导致其发送数据和接收数据是一个异步的过程,所以当存在服务端异常、网络问题时,客户端是接收不到响应的,那么我们如何判断一次
 RPC 调用是失败的呢?</p>
+<p>误区一:Dubbo 调用不是默认同步的吗?</p>
+<p>Dubbo 在通信层是异步的,呈现给使用者同步的错觉是因为内部做了阻塞等待,实现了异步转同步。</p>
+<p>误区二: <code>Channel.writeAndFlush</code> 会返回一个 
<code>channelFuture</code>,我只需要判断 <code>channelFuture.isSuccess</code> 
就可以判断请求是否成功了。</p>
+<p>注意,writeAndFlush 成功并不代表对端接受到了请求,返回值为 true 只能保证写入网络缓冲区成功,并不代表发送成功。</p>
+<p>避开上述两个误区,我们再来回到本小节的标题:客户端如何得知请求失败?<strong>正确的逻辑应当是以客户端接收到失败响应为判断依据</strong>。等等,前面不还在说在失败的场景中,服务端是不会返回响应的吗?没错,既然服务端不会返回,那就只能客户端自己造了。</p>
+<p>一个常见的设计是:客户端发起一个 RPC 请求,会设置一个超时时间 
<code>client_timeout</code>,发起调用的同时,客户端会开启一个延迟 <code>client_timeout</code> 
的定时器</p>
+<ul>
+<li>接收到正常响应时,移除该定时器。</li>
+<li>定时器倒计时完毕,还没有被移除,则认为请求超时,构造一个失败的响应传递给客户端。</li>
+</ul>
+<p>Dubbo 中的超时判定逻辑:</p>
+<pre><code class="language-java"><span class="hljs-function"><span 
class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> 
DefaultFuture <span class="hljs-title">newFuture</span><span 
class="hljs-params">(Channel channel, Request request, <span 
class="hljs-keyword">int</span> timeout)</span> </span>{
+    <span class="hljs-keyword">final</span> DefaultFuture future = <span 
class="hljs-keyword">new</span> DefaultFuture(channel, request, timeout);
+    <span class="hljs-comment">// timeout check</span>
+    timeoutCheck(future);
+    <span class="hljs-keyword">return</span> future;
+}
+<span class="hljs-function"><span class="hljs-keyword">private</span> <span 
class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span 
class="hljs-title">timeoutCheck</span><span class="hljs-params">(DefaultFuture 
future)</span> </span>{
+    TimeoutCheckTask task = <span class="hljs-keyword">new</span> 
TimeoutCheckTask(future);
+    TIME_OUT_TIMER.newTimeout(task, future.getTimeout(), 
TimeUnit.MILLISECONDS);
+}
+<span class="hljs-keyword">private</span> <span 
class="hljs-keyword">static</span> <span class="hljs-class"><span 
class="hljs-keyword">class</span> <span 
class="hljs-title">TimeoutCheckTask</span> <span 
class="hljs-keyword">implements</span> <span 
class="hljs-title">TimerTask</span> </span>{
+    <span class="hljs-keyword">private</span> DefaultFuture future;
+    TimeoutCheckTask(DefaultFuture future) {
+        <span class="hljs-keyword">this</span>.future = future;
+    }
+    <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">(Timeout timeout)</span> </span>{
+        <span class="hljs-keyword">if</span> (future == <span 
class="hljs-keyword">null</span> || future.isDone()) {
+            <span class="hljs-keyword">return</span>;
+        }
+        <span class="hljs-comment">// create exception response.</span>
+        Response timeoutResponse = <span class="hljs-keyword">new</span> 
Response(future.getId());
+        <span class="hljs-comment">// set timeout status.</span>
+        timeoutResponse.setStatus(future.isSent() ? Response.SERVER_TIMEOUT : 
Response.CLIENT_TIMEOUT);
+        timeoutResponse.setErrorMessage(future.getTimeoutMessage(<span 
class="hljs-keyword">true</span>));
+        <span class="hljs-comment">// handle response.</span>
+        DefaultFuture.received(future.getChannel(), timeoutResponse);
+    }
+}
+
+</code></pre>
+<p>主要逻辑涉及的类:<code>DubboInvoker</code>,<code>HeaderExchangeChannel</code>,<code>DefaultFuture</code>
 ,通过上述代码,我们可以得知一个细节,无论是何种调用,都会经过这个定时器的检测,<strong>超时即调用失败,一次 RPC 
调用的失败,必须以客户端收到失败响应为准</strong>。</p>
+<h4>2.2 心跳检测需要容错</h4>
+<p>网络通信永远要考虑到最坏的情况,一次心跳失败,不能认定为连接不通,多次心跳失败,才能采取相应的措施。</p>
+<h4>2.3 心跳检测不需要忙检测</h4>
+<p>忙检测的对立面是空闲检测,我们做心跳的初衷,是为了保证连接的可用性,以保证及时采取断连,重连等措施。如果一条通道上有频繁的 RPC 
调用正在进行,我们不应该为通道增加负担去发送心跳包。<strong>心跳扮演的角色应当是晴天收伞,雨天送伞。</strong></p>
+<h3>3 Dubbo 现有方案</h3>
+<blockquote>
+<p>本文的源码对应 Dubbo  2.7.x 版本,在 apache 孵化的该版本中,心跳机制得到了增强。</p>
+</blockquote>
+<p>介绍完了一些基础的概念,我们再来看看 Dubbo 是如何设计应用层心跳的。Dubbo 
的心跳是双向心跳,客户端会给服务端发送心跳,反之,服务端也会向客户端发送心跳。</p>
+<h4>3.1 连接建立时创建定时器</h4>
+<pre><code class="language-java"><span class="hljs-keyword">public</span> 
<span class="hljs-class"><span class="hljs-keyword">class</span> <span 
class="hljs-title">HeaderExchangeClient</span> <span 
class="hljs-keyword">implements</span> <span 
class="hljs-title">ExchangeClient</span> </span>{
+    <span class="hljs-keyword">private</span> <span 
class="hljs-keyword">int</span> heartbeat;
+    <span class="hljs-keyword">private</span> <span 
class="hljs-keyword">int</span> heartbeatTimeout;
+    <span class="hljs-keyword">private</span> HashedWheelTimer heartbeatTimer;
+    <span class="hljs-function"><span class="hljs-keyword">public</span> <span 
class="hljs-title">HeaderExchangeClient</span><span class="hljs-params">(Client 
client, <span class="hljs-keyword">boolean</span> needHeartbeat)</span> </span>{
+        <span class="hljs-keyword">this</span>.client = client;
+        <span class="hljs-keyword">this</span>.channel = <span 
class="hljs-keyword">new</span> HeaderExchangeChannel(client);
+        <span class="hljs-keyword">this</span>.heartbeat = 
client.getUrl().getParameter(Constants.HEARTBEAT_KEY, dubbo != <span 
class="hljs-keyword">null</span> &amp;&amp; dubbo.startsWith(<span 
class="hljs-string">"1.0."</span>) ? Constants.DEFAULT_HEARTBEAT : <span 
class="hljs-number">0</span>);
+        <span class="hljs-keyword">this</span>.heartbeatTimeout = 
client.getUrl().getParameter(Constants.HEARTBEAT_TIMEOUT_KEY, heartbeat * <span 
class="hljs-number">3</span>);
+        <span class="hljs-keyword">if</span> (needHeartbeat) { &lt;<span 
class="hljs-number">1</span>&gt;
+            <span class="hljs-keyword">long</span> tickDuration = 
calculateLeastDuration(heartbeat);
+            heartbeatTimer = <span class="hljs-keyword">new</span> 
HashedWheelTimer(<span class="hljs-keyword">new</span> NamedThreadFactory(<span 
class="hljs-string">"dubbo-client-heartbeat"</span>, <span 
class="hljs-keyword">true</span>), tickDuration,
+                    TimeUnit.MILLISECONDS, Constants.TICKS_PER_WHEEL); 
&lt;<span class="hljs-number">2</span>&gt;
+            startHeartbeatTimer();
+        }
+    }
+ }
+</code></pre>
+<p>&lt;1&gt; <strong>默认开启心跳检测的定时器</strong></p>
+<p>&lt;2&gt; <strong>创建了一个 <code>HashedWheelTimer</code> 开启心跳检测</strong>,这是 
Netty 所提供的一个经典的时间轮定时器实现,至于它和 jdk 的实现有何不同,不了解的同学也可以关注下,我就不拓展了。</p>
+<p>不仅 <code>HeaderExchangeClient</code> 
客户端开起了定时器,<code>HeaderExchangeServer</code> 
服务端同样开起了定时器,由于服务端的逻辑和客户端几乎一致,所以后续我并不会重复粘贴服务端的代码。</p>
+<blockquote>
+<p>Dubbo 在早期版本版本中使用的是 schedule 方案,在 2.7.x 中替换成了 HashedWheelTimer。</p>
+</blockquote>
+<h4>3.2 开启两个定时任务</h4>
+<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">startHeartbeatTimer</span><span 
class="hljs-params">()</span> </span>{
+    <span class="hljs-keyword">long</span> heartbeatTick = 
calculateLeastDuration(heartbeat);
+    <span class="hljs-keyword">long</span> heartbeatTimeoutTick = 
calculateLeastDuration(heartbeatTimeout);
+    HeartbeatTimerTask heartBeatTimerTask = <span 
class="hljs-keyword">new</span> HeartbeatTimerTask(cp, heartbeatTick, 
heartbeat); &lt;<span class="hljs-number">1</span>&gt;
+    ReconnectTimerTask reconnectTimerTask = <span 
class="hljs-keyword">new</span> ReconnectTimerTask(cp, heartbeatTimeoutTick, 
heartbeatTimeout); &lt;<span class="hljs-number">2</span>&gt;
+
+    heartbeatTimer.newTimeout(heartBeatTimerTask, heartbeatTick, 
TimeUnit.MILLISECONDS);
+    heartbeatTimer.newTimeout(reconnectTimerTask, heartbeatTimeoutTick, 
TimeUnit.MILLISECONDS);
+}
+</code></pre>
+<p>Dubbo 在 <code>startHeartbeatTimer</code> 方法中主要开启了两个定时器: 
<code>HeartbeatTimerTask</code>,<code>ReconnectTimerTask</code></p>
+<p>&lt;1&gt; <code>HeartbeatTimerTask</code> 主要用于定时发送心跳请求</p>
+<p>&lt;2&gt; <code>ReconnectTimerTask</code>  主要用于心跳失败之后处理重连,断连的逻辑</p>
+<p>至于方法中的其他代码,其实也是本文的重要分析内容,先容我卖个关子,后面再来看追溯。</p>
+<h4>3.3 定时任务一:发送心跳请求</h4>
+<p>详细解析下心跳检测定时任务的逻辑 <code>HeartbeatTimerTask#doTask</code>:</p>
+<pre><code class="language-java"><span class="hljs-function"><span 
class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> 
<span class="hljs-title">doTask</span><span class="hljs-params">(Channel 
channel)</span> </span>{
+    Long lastRead = lastRead(channel);
+    Long lastWrite = lastWrite(channel);
+    <span class="hljs-keyword">if</span> ((lastRead != <span 
class="hljs-keyword">null</span> &amp;&amp; now() - lastRead &gt; heartbeat)
+        || (lastWrite != <span class="hljs-keyword">null</span> &amp;&amp; 
now() - lastWrite &gt; heartbeat)) {
+            Request req = <span class="hljs-keyword">new</span> Request();
+            req.setVersion(Version.getProtocolVersion());
+            req.setTwoWay(<span class="hljs-keyword">true</span>);
+            req.setEvent(Request.HEARTBEAT_EVENT);
+            channel.send(req);
+        }
+    }
+}
+</code></pre>
+<p>前面已经介绍过,<strong>Dubbo 
采取的是双向心跳设计</strong>,即服务端会向客户端发送心跳,客户端也会向服务端发送心跳,接收的一方更新 lastRead 字段,发送的一方更新 
lastWrite 字段,超过心跳间隙的时间,便发送心跳请求给对端。这里的 lastRead/lastWrite 
同样会被同一个通道上的普通调用更新,通过更新这两个字段,实现了只在连接空闲时才会真正发送空闲报文的机制,符合我们一开始科普的做法。</p>
+<blockquote>
+<p>注意:不仅仅心跳请求会更新 lastRead 和 lastWrite,普通请求也会。这对应了我们预备知识中的空闲检测机制。</p>
+</blockquote>
+<h4>3.4 定时任务二:处理重连和断连</h4>
+<p>继续研究下重连和断连定时器都实现了什么 <code>ReconnectTimerTask#doTask</code>。</p>
+<pre><code class="language-java"><span class="hljs-function"><span 
class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> 
<span class="hljs-title">doTask</span><span class="hljs-params">(Channel 
channel)</span> </span>{
+    Long lastRead = lastRead(channel);
+    Long now = now();
+    <span class="hljs-keyword">if</span> (lastRead != <span 
class="hljs-keyword">null</span> &amp;&amp; now - lastRead &gt; 
heartbeatTimeout) {
+        <span class="hljs-keyword">if</span> (channel <span 
class="hljs-keyword">instanceof</span> Client) {
+            ((Client) channel).reconnect();
+        } <span class="hljs-keyword">else</span> {
+            channel.close();
+        }
+    }
+}
+</code></pre>
+<p>第二个定时器则负责根据客户端、服务端类型来对连接做不同的处理,当超过设置的心跳总时间之后,客户端选择的是重新连接,服务端则是选择直接断开连接。这样的考虑是合理的,客户端调用是强依赖可用连接的,而服务端可以等待客户端重新建立连接。</p>
+<blockquote>
+<p>细心的朋友会发现,这个类被命名为 ReconnectTimerTask 是不太准确的,因为它处理的是重连和断连两个逻辑。</p>
+</blockquote>
+<h4>3.5 定时不精确的问题</h4>
+<p>在 Dubbo 的 issue 中曾经有人反馈过定时不精确的问题,我们来看看是怎么一回事。</p>
+<p>Dubbo 中默认的心跳周期是 60s,设想如下的时序:</p>
+<ul>
+<li>第 0 秒,心跳检测发现连接活跃</li>
+<li>第 1 秒,连接实际断开</li>
+<li>第 60 秒,心跳检测发现连接不活跃</li>
+</ul>
+<p>由于<strong>时间窗口的问题,死链不能够被及时检测出来,最坏情况为一个心跳周期</strong>。</p>
+<p>为了解决上述问题,我们再倒回去看一下上面的 <code>startHeartbeatTimer()</code> 方法</p>
+<pre><code class="language-java"><span class="hljs-keyword">long</span> 
heartbeatTick = calculateLeastDuration(heartbeat); 
+<span class="hljs-keyword">long</span> heartbeatTimeoutTick = 
calculateLeastDuration(heartbeatTimeout);
+</code></pre>
+<p>其中 <code>calculateLeastDuration</code> 根据心跳时间和超时时间分别计算出了一个 tick 
时间,实际上就是将两个变量除以了 3,使得他们的值缩小,并传入了 <code>HashedWheelTimer</code> 的第二个参数之中</p>
+<pre><code class="language-java">heartbeatTimer.newTimeout(heartBeatTimerTask, 
heartbeatTick, TimeUnit.MILLISECONDS);
+heartbeatTimer.newTimeout(reconnectTimerTask, heartbeatTimeoutTick, 
TimeUnit.MILLISECONDS);
+</code></pre>
+<p>tick 的含义便是定时任务执行的频率。这样,通过减少检测间隔时间,增大了及时发现死链的概率,原先的最坏情况是 60s,如今变成了 
20s。这个频率依旧可以加快,但需要考虑资源消耗的问题。</p>
+<blockquote>
+<p>定时不准确的问题出现在 Dubbo 的两个定时任务之中,所以都做了 tick 操作。事实上,所有的定时检测的逻辑都存在类似的问题。</p>
+</blockquote>
+<h4>3.6 Dubbo 心跳总结</h4>
+<p>Dubbo 对于建立的每一个连接,同时在客户端和服务端开启了 2 个定时器,一个用于定时发送心跳,一个用于定时重连、断连,执行的频率均为各自检测周期的 
1/3。定时发送心跳的任务负责在连接空闲时,向对端发送心跳包。定时重连、断连的任务负责检测 lastRead 
是否在超时周期内仍未被更新,如果判定为超时,客户端处理的逻辑是重连,服务端则采取断连的措施。</p>
+<p>先不急着判断这个方案好不好,再来看看改进方案是怎么设计的。</p>
+<h3>4 Dubbo 改进方案</h3>
+<p>实际上我们可以更优雅地实现心跳机制,本小节开始,我将介绍一个新的心跳机制。</p>
+<h4>4.1 IdleStateHandler 介绍</h4>
+<p>Netty 对空闲连接的检测提供了天然的支持,使用 <code>IdleStateHandler</code> 可以很方便的实现空闲检测逻辑。</p>
+<pre><code class="language-java"><span class="hljs-function"><span 
class="hljs-keyword">public</span> <span 
class="hljs-title">IdleStateHandler</span><span class="hljs-params">(
+            <span class="hljs-keyword">long</span> readerIdleTime, <span 
class="hljs-keyword">long</span> writerIdleTime, <span 
class="hljs-keyword">long</span> allIdleTime,
+            TimeUnit unit)</span> </span>{}
+</code></pre>
+<ul>
+<li>readerIdleTime:读超时时间</li>
+<li>writerIdleTime:写超时时间</li>
+<li>allIdleTime:所有类型的超时时间</li>
+</ul>
+<p><code>IdleStateHandler</code> 这个类会根据设置的超时参数,循环检测 channelRead 和 write 
方法多久没有被调用。当在 pipeline 中加入 <code>IdleSateHandler</code> 之后,可以在此 pipeline 的任意 
Handler 的 <code>userEventTriggered</code> 方法之中检测 <code>IdleStateEvent</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">userEventTriggered</span><span 
class="hljs-params">(ChannelHandlerContext ctx, Object evt)</span> <span 
class="hljs-keyword">throws</span> Exception </span>{
+    <span class="hljs-keyword">if</span> (evt <span 
class="hljs-keyword">instanceof</span> IdleStateEvent) {
+        <span class="hljs-comment">//do something</span>
+    }
+    ctx.fireUserEventTriggered(evt);
+}
+</code></pre>
+<p>为什么需要介绍 <code>IdleStateHandler</code> 呢?其实提到它的空闲检测 + 
定时的时候,大家应该能够想到了,这不天然是给心跳机制服务的吗?很多服务治理框架都选择了借助 <code>IdleStateHandler</code> 
来实现心跳。</p>
+<blockquote>
+<p>IdleStateHandler 内部使用了 eventLoop.schedule(task) 的方式来实现定时任务,使用 eventLoop 
线程的好处是还同时保证了<strong>线程安全</strong>,这里是一个小细节。</p>
+</blockquote>
+<h4>4.2 客户端和服务端配置</h4>
+<p>首先是将 <code>IdleStateHandler</code> 加入 pipeline 中。</p>
+<p><strong>客户端:</strong></p>
+<pre><code class="language-java">bootstrap.handler(<span 
class="hljs-keyword">new</span> ChannelInitializer&lt;NioSocketChannel&gt;() {
+    <span class="hljs-meta">@Override</span>
+    <span class="hljs-function"><span class="hljs-keyword">protected</span> 
<span class="hljs-keyword">void</span> <span 
class="hljs-title">initChannel</span><span 
class="hljs-params">(NioSocketChannel ch)</span> <span 
class="hljs-keyword">throws</span> Exception </span>{
+        ch.pipeline().addLast(<span 
class="hljs-string">"clientIdleHandler"</span>, <span 
class="hljs-keyword">new</span> IdleStateHandler(<span 
class="hljs-number">60</span>, <span class="hljs-number">0</span>, <span 
class="hljs-number">0</span>));
+    }
+});
+</code></pre>
+<p><strong>服务端:</strong></p>
+<pre><code class="language-java">serverBootstrap.childHandler(<span 
class="hljs-keyword">new</span> ChannelInitializer&lt;NioSocketChannel&gt;() {
+    <span class="hljs-meta">@Override</span>
+    <span class="hljs-function"><span class="hljs-keyword">protected</span> 
<span class="hljs-keyword">void</span> <span 
class="hljs-title">initChannel</span><span 
class="hljs-params">(NioSocketChannel ch)</span> <span 
class="hljs-keyword">throws</span> Exception </span>{
+        ch.pipeline().addLast(<span 
class="hljs-string">"serverIdleHandler"</span>,<span 
class="hljs-keyword">new</span> IdleStateHandler(<span 
class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span 
class="hljs-number">200</span>));
+    }
+}
+</code></pre>
+<p>客户端配置了 read 超时为 60s,服务端配置了 write/read 超时为 200s,先在此埋下两个伏笔:</p>
+<ol>
+<li>为什么客户端和服务端配置的超时时间不一致?</li>
+<li>为什么客户端检测的是读超时,而服务端检测的是读写超时?</li>
+</ol>
+<h4>4.3 空闲超时逻辑 — 客户端</h4>
+<p>对于空闲超时的处理逻辑,客户端和服务端是不同的。首先来看客户端</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">userEventTriggered</span><span 
class="hljs-params">(ChannelHandlerContext ctx, Object evt)</span> <span 
class="hljs-keyword">throws</span> Exception </span>{
+    <span class="hljs-keyword">if</span> (evt <span 
class="hljs-keyword">instanceof</span> IdleStateEvent) {
+        <span class="hljs-comment">// send heartbeat</span>
+        sendHeartBeat();
+    } <span class="hljs-keyword">else</span> {
+        <span class="hljs-keyword">super</span>.userEventTriggered(ctx, evt);
+    }
+}
+</code></pre>
+<p>检测到空闲超时之后,采取的行为是向服务端发送心跳包,具体是如何发送,以及处理响应的呢?伪代码如下</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">sendHeartBeat</span><span class="hljs-params">()</span> 
</span>{
+    Invocation invocation = <span class="hljs-keyword">new</span> Invocation();
+    invocation.setInvocationType(InvocationType.HEART_BEAT);
+    channel.writeAndFlush(invocation).addListener(<span 
class="hljs-keyword">new</span> CallbackFuture() {
+        <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">callback</span><span class="hljs-params">(Future 
future)</span> </span>{
+            RPCResult result = future.get();
+            <span class="hljs-comment">//超时 或者 写失败</span>
+            <span class="hljs-keyword">if</span> (result.isError()) {
+                channel.addFailedHeartBeatTimes();
+                <span class="hljs-keyword">if</span> 
(channel.getFailedHeartBeatTimes() &gt;= channel.getMaxHeartBeatFailedTimes()) {
+                    channel.reconnect();
+                }
+            } <span class="hljs-keyword">else</span> {
+                channel.clearHeartBeatFailedTimes();
+            }
+        }
+    });
+}
+</code></pre>
+<p>行为并不复杂,构造一个心跳包发送到服务端,接受响应结果</p>
+<ul>
+<li>响应成功,清空请求失败标记</li>
+<li>响应失败,心跳失败标记+1,如果超过配置的失败次数,则重新连接</li>
+</ul>
+<blockquote>
+<p>不仅仅是心跳,普通请求返回成功响应时也会清空标记</p>
+</blockquote>
+<h4>4.4 空闲超时逻辑 — 服务端</h4>
+<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">userEventTriggered</span><span 
class="hljs-params">(ChannelHandlerContext ctx, Object evt)</span> <span 
class="hljs-keyword">throws</span> Exception </span>{
+    <span class="hljs-keyword">if</span> (evt <span 
class="hljs-keyword">instanceof</span> IdleStateEvent) {
+        channel.close();
+    } <span class="hljs-keyword">else</span> {
+        <span class="hljs-keyword">super</span>.userEventTriggered(ctx, evt);
+    }
+}
+</code></pre>
+<p>服务端处理空闲连接的方式非常简单粗暴,直接关闭连接。</p>
+<h4>4.5 改进方案心跳总结</h4>
+<ol>
+<li>
+<p>为什么客户端和服务端配置的超时时间不一致?</p>
+<p>因为客户端有重试逻辑,不断发送心跳失败 n 次之后,才认为是连接断开;而服务端是直接断开,留给服务端时间得长一点。60 * 3 &lt; 200 
还说明了一个问题,双方都拥有断开连接的能力,但连接的创建是由客户端主动发起的,那么客户端也更有权利去主动断开连接。</p>
+</li>
+<li>
+<p>为什么客户端检测的是读超时,而服务端检测的是读写超时?</p>
+<p>这其实是一个心跳的共识了,仔细思考一下,定时逻辑是由客户端发起的,所以整个链路中不通的情况只有可能是:服务端接收,服务端发送,客户端接收。也就是说,只有客户端的
 pong,服务端的 ping,pong 的检测是有意义的。</p>
+</li>
+</ol>
+<blockquote>
+<p>主动追求别人的是你,主动说分手的也是你。</p>
+</blockquote>
+<p>利用 <code>IdleStateHandler</code> 实现心跳机制可以说是十分优雅的,借助 Netty 
提供的空闲检测机制,利用客户端维护单向心跳,在收到 3 
次心跳失败响应之后,客户端断开连接,交由异步线程重连,本质还是表现为客户端重连。服务端在连接空闲较长时间后,主动断开连接,以避免无谓的资源浪费。</p>
+<h3>5 心跳设计方案对比</h3>
+<table>
+<thead>
+<tr>
+<th style="text-align:center"></th>
+<th style="text-align:center">Dubbo 现有方案</th>
+<th style="text-align:center">Dubbo 改进方案</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td style="text-align:center"><strong>主体设计</strong></td>
+<td style="text-align:center">开启两个定时器</td>
+<td style="text-align:center">借助 IdleStateHandler,底层使用 schedule</td>
+</tr>
+<tr>
+<td style="text-align:center"><strong>心跳方向</strong></td>
+<td style="text-align:center">双向</td>
+<td style="text-align:center">单向(客户端 -&gt; 服务端)</td>
+</tr>
+<tr>
+<td style="text-align:center"><strong>心跳失败判定方式</strong></td>
+<td style="text-align:center">心跳成功更新标记,借助定时器定时扫描标记,如果超过心跳超时周期未更新标记,认为心跳失败。</td>
+<td style="text-align:center">通过判断心跳响应是否失败,超过失败次数,认为心跳失败</td>
+</tr>
+<tr>
+<td style="text-align:center"><strong>扩展性</strong></td>
+<td style="text-align:center">Dubbo 存在 mina,grizzy 
等其他通信层实现,自定义定时器很容易适配多种扩展</td>
+<td style="text-align:center">多通信层各自实现心跳,不做心跳的抽象</td>
+</tr>
+<tr>
+<td style="text-align:center"><strong>设计性</strong></td>
+<td style="text-align:center">编码复杂度高,代码量大,方案复杂,不易维护</td>
+<td style="text-align:center">编码量小,可维护性强</td>
+</tr>
+</tbody>
+</table>
+<p>私下请教过<strong>美团点评的长连接负责人:俞超(闪电侠)</strong>,美点使用的心跳方案和 Dubbo 
改进方案几乎一致,可以说该方案是标准实现了。</p>
+<h3>6 Dubbo 实际改动点建议</h3>
+<p>鉴于 Dubbo 存在一些其他通信层的实现,所以可以保留现有的定时发送心跳的逻辑。</p>
+<ul>
+<li><strong>建议改动点一:</strong></li>
+</ul>
+<p>双向心跳的设计是不必要的,兼容现有的逻辑,可以让客户端在连接空闲时发送单向心跳,服务端定时检测连接可用性。定时时间尽量保证:客户端超时时间 * 3 ≈ 
服务端超时时间</p>
+<ul>
+<li><strong>建议改动点二:</strong></li>
+</ul>
+<p>去除处理重连和断连的定时任务,Dubbo 
可以判断心跳请求是否响应失败,可以借鉴改进方案的设计,在连接级别维护一个心跳失败次数的标记,任意响应成功,清除标记;连续心跳失败 n 
次,客户端发起重连。这样可以减少一个不必要的定时器,任何轮询的方式,都是不优雅的。</p>
+<p>最后再聊聊可扩展性这个话题。其实我是建议把定时器交给更加底层的 Netty 去做,也就是完全使用 
<code>IdleStateHandler</code> ,其他通信层组件各自实现自己的空闲检测逻辑,但是 Dubbo 中 mina,grizzy 
的兼容问题囿住了我的拳脚,但试问一下,如今的 2019 年,又有多少人在使用 mina 和 
grizzy?因为一些不太可能用的特性,而限制了主流用法的优化,这肯定不是什么好事。抽象,功能,可扩展性并不是越多越好,开源产品的人力资源是有限的,框架使用者的理解能力也是有限的,能解决大多数人问题的设计,才是好的设计。哎,谁让我不会
 mina,grizzy,还懒得去学呢[摊手]。</p>
+</section><footer class="footer-container"><div class="footer-body"><img 
src="/img/dubbo_gray.png"/><img class="apache" src="/img/apache_logo.png"/><div 
class="cols-container"><div class="col col-12"><h3>Disclaimer</h3><p>Apache 
Dubbo is an effort undergoing incubation at The Apache Software Foundation 
(ASF), sponsored by the Incubator. Incubation is required of all newly accepted 
projects until a further review indicates that the infrastructure, 
communications, and decision making proce [...]
+       <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/zh-cn/blog/dubbo-heartbeat-design.json 
b/zh-cn/blog/dubbo-heartbeat-design.json
new file mode 100644
index 0000000..1d60ed2
--- /dev/null
+++ b/zh-cn/blog/dubbo-heartbeat-design.json
@@ -0,0 +1,10 @@
+{
+  "filename": "dubbo-heartbeat-design.md",
+  "__html": "<h1>Dubbo 现有心跳方案总结以及改进建议</h1>\n<h3>1 
前言</h3>\n<p>设计一个好的心跳机制并不是一件容易的事,就我所熟知的几个 RPC 
框架,它们的心跳机制可以说大相径庭,这篇文章我将探讨一下<strong>如何设计一个优雅的心跳机制,主要从 Dubbo 
的现有方案以及一个改进方案来做分析</strong>。</p>\n<h3>2 
预备知识</h3>\n<p>因为后续我们将从源码层面来进行介绍,所以一些服务治理框架的细节还需要提前交代一下,方便大家理解。</p>\n<h4>2.1 
客户端如何得知请求失败了?</h4>\n<p>高性能的 RPC 框架几乎都会选择使用 Netty 
来作为通信层的组件,非阻塞式通信的高效不需要我做过多的介绍。但也由于非阻塞的特性,导致其发送数据和接收数据是一个异步的过程,所以当存在服务端异常、网络问题时,客户端是接收不到响应的,那么我们如何判断一次
 RP
 C 调用是失败的呢?</p>\n<p>误区一:Dubbo 调用不是默认同步的吗?</p>\n<p>Dubbo 在通信层是异步的,呈现给使用 [...]
+  "link": "/zh-cn/blog/dubbo-heartbeat-design.html",
+  "meta": {
+    "title": "Dubbo 现有心跳方案总结以及改进建议",
+    "keywords": "Dubbo, 心跳",
+    "description": "一种心跳,两种设计"
+  }
+}
\ No newline at end of file
diff --git a/zh-cn/blog/index.html b/zh-cn/blog/index.html
index 6018696..c2137f1 100644
--- a/zh-cn/blog/index.html
+++ b/zh-cn/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=""><header 
class="header-container header-container-normal"><div class="header-body"><a 
href="/zh-cn/index.html"><img class="logo" 
src="/img/dubbo_colorful.png"/></a><div class="search search-normal"><span 
class="icon-search"></span></div><span class="language-switch 
language-switch-normal">En</span><div class="header-menu"><img 
class="header-menu-toggle" src="/img/menu_gray.png"/><ul><li class="menu-item 
menu-item-normal"><a hre [...]
+       <div id="root"><div class="blog-list-page" data-reactroot=""><header 
class="header-container header-container-normal"><div class="header-body"><a 
href="/zh-cn/index.html"><img class="logo" 
src="/img/dubbo_colorful.png"/></a><div class="search search-normal"><span 
class="icon-search"></span></div><span class="language-switch 
language-switch-normal">En</span><div class="header-menu"><img 
class="header-menu-toggle" src="/img/menu_gray.png"/><ul><li class="menu-item 
menu-item-normal"><a hre [...]
        <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/docs/dev/principals/code-detail.html 
b/zh-cn/docs/dev/principals/code-detail.html
index 9becf7a..f22e689 100644
--- a/zh-cn/docs/dev/principals/code-detail.html
+++ b/zh-cn/docs/dev/principals/code-detail.html
@@ -16,9 +16,9 @@
 <blockquote>
 <p><a 
href="http://javatar.iteye.com/blog/1056664";>http://javatar.iteye.com/blog/1056664</a></p>
 </blockquote>
-<p>最近一直担心 Dubbo 分布式服务框架后续如果维护人员增多或变更,会出现质量的下降, 
我在想,有没有什么是需要大家共同遵守的,根据平时写代码时的一习惯,总结了一下在写代码过程中,尤其是框架代码,要时刻牢记的细节。可能下面要讲的这些,大家都会觉得很简单,很基础,但要做到时刻牢记。在每一行代码中都考虑这些因素,是需要很大耐心的,
 大家经常说,魔鬼在细节中,确实如此。</p>
+<p>最近一直担心如果 Dubbo 分布式服务框架维护人员增多或变更,会出现质量的下降的问题, 
我在想,有没有什么规则是需要大家共同遵守的。根据平时写代码时的一习惯,总结了以下在写代码过程中,尤其是框架代码,要时刻牢记的细节。可能下面要讲的这些,大家都会觉得很简单,很基础,但要做到时刻牢记。在每一行代码中都考虑这些因素,是需要很大耐心的,
 大家经常说,魔鬼在细节中,确实如此。</p>
 <h2>防止空指针和下标越界</h2>
-<p>这是我最不喜欢看到的异常,尤其在核心框架中,我更愿看到信息详细的参数不合法异常。这也是一个健状的程序开发人员,在写每一行代码都应在潜意识中防止的异常。基本上要能确保一次写完的代码,在不测试的情况,都不会出现这两个异常才算合格。</p>
+<p>这是我最不喜欢看到的异常,尤其在核心框架中,我更愿看到信息详细的参数不合法异常。这也是一个编写健壮程序的开发人员,在写每一行代码都应在潜意识中防止的异常。基本上要能确保每一次写完的代码,在不测试的情况下,都不会出现这两个异常才算合格。</p>
 <h2>保证线程安全性和可见性</h2>
 
<p>对于框架的开发人员,对线程安全性和可见性的深入理解是最基本的要求。需要开发人员,在写每一行代码时都应在潜意识中确保其正确性。因为这种代码,在小并发下做功能测试时,会显得很正常。但在高并发下就会出现莫明其妙的问题,而且场景很难重现,极难排查。</p>
 <h2>尽早失败和前置断言</h2>
diff --git a/zh-cn/docs/dev/principals/code-detail.json 
b/zh-cn/docs/dev/principals/code-detail.json
index 00c06cf..5e34f43 100644
--- a/zh-cn/docs/dev/principals/code-detail.json
+++ b/zh-cn/docs/dev/principals/code-detail.json
@@ -1,6 +1,6 @@
 {
   "filename": "code-detail.md",
-  "__html": "<h1>魔鬼在细节</h1>\n<blockquote>\n<p><a 
href=\"http://javatar.iteye.com/blog/1056664\";>http://javatar.iteye.com/blog/1056664</a></p>\n</blockquote>\n<p>最近一直担心
 Dubbo 分布式服务框架后续如果维护人员增多或变更,会出现质量的下降, 
我在想,有没有什么是需要大家共同遵守的,根据平时写代码时的一习惯,总结了一下在写代码过程中,尤其是框架代码,要时刻牢记的细节。可能下面要讲的这些,大家都会觉得很简单,很基础,但要做到时刻牢记。在每一行代码中都考虑这些因素,是需要很大耐心的,
 
大家经常说,魔鬼在细节中,确实如此。</p>\n<h2>防止空指针和下标越界</h2>\n<p>这是我最不喜欢看到的异常,尤其在核心框架中,我更愿看到信息详细的参数不合法异常。这也是一个健状的程序开发人员,在写每一行代码都应在潜意识中防止的异常。基本上要能确�
 �一次写完的代码,在不测试的情况,都不会出现这两个异常才算合格。</p>\ [...]
+  "__html": "<h1>魔鬼在细节</h1>\n<blockquote>\n<p><a 
href=\"http://javatar.iteye.com/blog/1056664\";>http://javatar.iteye.com/blog/1056664</a></p>\n</blockquote>\n<p>最近一直担心如果
 Dubbo 分布式服务框架维护人员增多或变更,会出现质量的下降的问题, 
我在想,有没有什么规则是需要大家共同遵守的。根据平时写代码时的一习惯,总结了以下在写代码过程中,尤其是框架代码,要时刻牢记的细节。可能下面要讲的这些,大家都会觉得很简单,很基础,但要做到时刻牢记。在每一行代码中都考虑这些因素,是需要很大耐心的,
 
大家经常说,魔鬼在细节中,确实如此。</p>\n<h2>防止空指针和下标越界</h2>\n<p>这是我最不喜欢看到的异常,尤其在核心框架中,我更愿看到信息详细的参数不合法异常。这也是一个编写健壮程序的开发人员,在写每一行代码都应在潜意识中防止的异常。基�
 �上要能确保每一次写完的代码,在不测试的情况下,都不会出现这两个异常才算合 [...]
   "link": "/zh-cn/docs/dev/principals/code-detail.html",
   "meta": {}
 }
\ No newline at end of file
diff --git a/zh-cn/docs/dev/principals/robustness.html 
b/zh-cn/docs/dev/principals/robustness.html
index 343ffa0..1c45038 100644
--- a/zh-cn/docs/dev/principals/robustness.html
+++ b/zh-cn/docs/dev/principals/robustness.html
@@ -48,9 +48,9 @@
 <h2>容错-重试-恢复</h2>
 <p>高可用组件要容忍其依赖组件的失败。</p>
 <h3>Dubbo 的服务注册中心</h3>
-<p>目前服务注册中心使用了数据库来保存服务提供者和消费者的信息。注册中心集群不同注册中心也通过数据库来之间同步数据,以感知其它注册中心上提供者。注册中心会内存中保证一份提供者和消费者数据,数据库不可用时,注册中心独立对外正常运转,只是拿不到其它注册中心的数据。当数据库恢复时,重试逻辑会内存中修改的数据写回数据库,并拿到数据库中新数据。</p>
+<p>目前服务注册中心使用了数据库来保存服务提供者和消费者的信息。注册中心集群不同注册中心也通过数据库来进行同步数据,以感知其它注册中心上提供者的变化。注册中心会在内存中保存一份提供者和消费者数据,数据库不可用时,注册中心独立对外提供服务以保证正常运转,只是拿不到其它注册中心的数据。当数据库恢复时,重试逻辑会将内存中修改的数据写回数据库,并拿到数据库中新数据。</p>
 <h3>服务的消费者</h3>
-<p>服务消息者从注册中心拿到提供者列表后,会保存提供者列表到内存和磁盘文件中。这样注册中心宕后消费者可以正常运转,甚至可以在注册中心宕机过程中重启消费者。消费者启动时,发现注册中心不可用,会读取保存在磁盘文件中提供者列表。重试逻辑保证注册中心恢复后,更新信息。</p>
+<p>服务消费者从注册中心拿到提供者列表后,会保存提供者列表到内存和磁盘文件中。这样注册中心宕机后消费者可以正常运转,甚至可以在注册中心宕机过程中重启消费者。消费者启动时,发现注册中心不可用,会读取保存在磁盘文件中提供者列表。重试逻辑保证注册中心恢复后,更新信息。</p>
 <h2>重试延迟策略</h2>
 <p>上一点的子问题。Dubbo 中碰到有两个相关的场景。</p>
 <h3>数据库上的活锁</h3>
diff --git a/zh-cn/docs/dev/principals/robustness.json 
b/zh-cn/docs/dev/principals/robustness.json
index a9f88aa..4b6c1f1 100644
--- a/zh-cn/docs/dev/principals/robustness.json
+++ b/zh-cn/docs/dev/principals/robustness.json
@@ -1,6 +1,6 @@
 {
   "filename": "robustness.md",
-  "__html": "<h1>设计实现的健壮性</h1>\n<blockquote>\n<p><a 
href=\"http://oldratlee.com/380/tech/java/robustness-of-implement.html\";>http://oldratlee.com/380/tech/java/robustness-of-implement.html</a></p>\n</blockquote>\n<p>Dubbo
 作为远程服务暴露、调用和治理的解决方案,是应用运转的经络,其本身实现健壮性的重要程度是不言而喻的。</p>\n<p>这里列出一些 Dubbo 
用到的原则和方法。</p>\n<h2>日志</h2>\n<p>日志是发现问题、查看问题一个最常用的手段。日志质量往往被忽视,没有日志使用上的明确约定。重视 
Log 的使用,提高 Log 
的信息浓度。日志过多、过于混乱,会导致有用的信息被淹没。</p>\n<p>要有效利用这个工具要注意:</p>\n<h3>严格约定WARN、ERROR级别记录的内容</h3>\n<ul>\n<li>WARN
 表示可 [...]
+  "__html": "<h1>设计实现的健壮性</h1>\n<blockquote>\n<p><a 
href=\"http://oldratlee.com/380/tech/java/robustness-of-implement.html\";>http://oldratlee.com/380/tech/java/robustness-of-implement.html</a></p>\n</blockquote>\n<p>Dubbo
 作为远程服务暴露、调用和治理的解决方案,是应用运转的经络,其本身实现健壮性的重要程度是不言而喻的。</p>\n<p>这里列出一些 Dubbo 
用到的原则和方法。</p>\n<h2>日志</h2>\n<p>日志是发现问题、查看问题一个最常用的手段。日志质量往往被忽视,没有日志使用上的明确约定。重视 
Log 的使用,提高 Log 
的信息浓度。日志过多、过于混乱,会导致有用的信息被淹没。</p>\n<p>要有效利用这个工具要注意:</p>\n<h3>严格约定WARN、ERROR级别记录的内容</h3>\n<ul>\n<li>WARN
 表示可 [...]
   "link": "/zh-cn/docs/dev/principals/robustness.html",
   "meta": {}
 }
\ No newline at end of file
diff --git a/zh-cn/docs/developers/developers_dev.html 
b/zh-cn/docs/developers/developers_dev.html
index dc0c7a5..652a9a1 100644
--- a/zh-cn/docs/developers/developers_dev.html
+++ b/zh-cn/docs/developers/developers_dev.html
@@ -139,6 +139,13 @@
 <td>+8</td>
 </tr>
 <tr>
+<td>carryxyh</td>
+<td>Yuhang Xiu</td>
+<td>Netease</td>
+<td>PPMC</td>
+<td>+8</td>
+</tr>
+<tr>
 <td>hyunkun</td>
 <td>YunKun Huang</td>
 <td></td>
@@ -160,13 +167,6 @@
 <td>+8</td>
 </tr>
 <tr>
-<td>carryxyh</td>
-<td>Yuhang Xiu</td>
-<td>Netease</td>
-<td>Committer</td>
-<td>+8</td>
-</tr>
-<tr>
 <td>min</td>
 <td>Minxuan Zhuang</td>
 <td>Alibaba</td>
@@ -208,6 +208,13 @@
 <td>Committer</td>
 <td>+8</td>
 </tr>
+<tr>
+<td>tswstarplanet</td>
+<td>Taosheng Wei</td>
+<td>NetsUnion</td>
+<td>Committer</td>
+<td>+8</td>
+</tr>
 </tbody>
 </table>
 <h3>贡献者</h3>
diff --git a/zh-cn/docs/developers/developers_dev.json 
b/zh-cn/docs/developers/developers_dev.json
index eab2516..cb1077a 100644
--- a/zh-cn/docs/developers/developers_dev.json
+++ b/zh-cn/docs/developers/developers_dev.json
@@ -1,6 +1,6 @@
 {
   "filename": "developers_dev.md",
-  "__html": 
"<h2>开发人员</h2>\n<p>本页面展示了Dubbo的开发团队。请通过提交PR的方式把自己的信息添加到列表上。注:排名不分先后</p>\n<h3>提交者</h3>\n<table>\n<thead>\n<tr>\n<th>Apache
 
ID</th>\n<th>姓名</th>\n<th>组织</th>\n<th>角色</th>\n<th>时区</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>jmclean</td>\n<td>Justin
 
Mclean</td>\n<td>Apache</td>\n<td>Mentor</td>\n<td>+11</td>\n</tr>\n<tr>\n<td>markt</td>\n<td>Mark
 
Thomas</td>\n<td>Apache</td>\n<td>Mentor</td>\n<td>+0</td>\n</tr>\n<tr>\n<td>wave</td>\n<td>Dave
 Fisher</td>\n<td></td>\n<td>Mentor</td>\ [...]
+  "__html": 
"<h2>开发人员</h2>\n<p>本页面展示了Dubbo的开发团队。请通过提交PR的方式把自己的信息添加到列表上。注:排名不分先后</p>\n<h3>提交者</h3>\n<table>\n<thead>\n<tr>\n<th>Apache
 
ID</th>\n<th>姓名</th>\n<th>组织</th>\n<th>角色</th>\n<th>时区</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>jmclean</td>\n<td>Justin
 
Mclean</td>\n<td>Apache</td>\n<td>Mentor</td>\n<td>+11</td>\n</tr>\n<tr>\n<td>markt</td>\n<td>Mark
 
Thomas</td>\n<td>Apache</td>\n<td>Mentor</td>\n<td>+0</td>\n</tr>\n<tr>\n<td>wave</td>\n<td>Dave
 Fisher</td>\n<td></td>\n<td>Mentor</td>\ [...]
   "link": "/zh-cn/docs/developers/developers_dev.html",
   "meta": {}
 }
\ No newline at end of file
diff --git a/zh-cn/docs/user/references/telnet.html 
b/zh-cn/docs/user/references/telnet.html
index 9b05c10..394018d 100644
--- a/zh-cn/docs/user/references/telnet.html
+++ b/zh-cn/docs/user/references/telnet.html
@@ -63,12 +63,16 @@
 <li><code>invoke XxxService.xxxMethod({&quot;prop&quot;: 
&quot;value&quot;})</code>: 调用服务的方法</li>
 <li><code>invoke xxxMethod({&quot;prop&quot;: &quot;value&quot;})</code>: 
调用服务的方法(自动查找包含此方法的服务)</li>
 </ol>
+<h3><code>select</code> <sup class="footnote-ref"><a href="#fn1" 
id="fnref1">[1]</a></sup></h3>
+<ol start="0">
+<li><code>select 1</code>: 当 invoke 命令匹配到多个方法时使用,根据提示列表选择需要调用的方法</li>
+</ol>
 <h3><code>status</code></h3>
 <ol start="0">
 <li><code>status</code>: 显示汇总状态,该状态将汇总所有资源的状态,当全部 OK 时则显示 OK,只要有一个 ERROR 则显示 
ERROR,只要有一个 WARN 则显示 WARN</li>
 <li><code>status -l</code>: 显示状态列表</li>
 </ol>
-<h3><code>log</code> <sup class="footnote-ref"><a href="#fn1" 
id="fnref1">[1]</a></sup></h3>
+<h3><code>log</code> <sup class="footnote-ref"><a href="#fn2" 
id="fnref2">[2]</a></sup></h3>
 <ol start="0">
 <li><code>log debug</code>: 修改 dubbo logger 的日志级别</li>
 <li><code>log 100</code>: 查看 file logger 的最后 100 字符的日志</li>
@@ -85,10 +89,17 @@
 </ol>
 <h3><code>exit</code></h3>
 <p><code>exit</code>: 退出当前 telnet 命令行</p>
+<h3><code>shutdown</code> <sup class="footnote-ref"><a href="#fn1" 
id="fnref1:1">[1:1]</a></sup></h3>
+<ol start="0">
+<li><code>shutdown</code>: 关闭 dubbo 应用</li>
+<li><code>shutdown -t 1000</code>: 延迟 1000 毫秒关闭 dubbo 应用</li>
+</ol>
 <hr class="footnotes-sep">
 <section class="footnotes">
 <ol class="footnotes-list">
-<li id="fn1" class="footnote-item"><p><code>2.0.6</code> 以上版本支持 <a 
href="#fnref1" class="footnote-backref">↩︎</a></p>
+<li id="fn1" class="footnote-item"><p><code>2.7.1</code> 以上版本支持 <a 
href="#fnref1" class="footnote-backref">↩︎</a> <a href="#fnref1:1" 
class="footnote-backref">↩︎</a></p>
+</li>
+<li id="fn2" class="footnote-item"><p><code>2.0.6</code> 以上版本支持 <a 
href="#fnref2" class="footnote-backref">↩︎</a></p>
 </li>
 </ol>
 </section>
diff --git a/zh-cn/docs/user/references/telnet.json 
b/zh-cn/docs/user/references/telnet.json
index e0a7710..86566f5 100644
--- a/zh-cn/docs/user/references/telnet.json
+++ b/zh-cn/docs/user/references/telnet.json
@@ -1,6 +1,6 @@
 {
   "filename": "telnet.md",
-  "__html": "<h1>Telnet 命令参考手册</h1>\n<p>从 <code>2.0.5</code> 版本开始,dubbo 开始支持通过 
telnet 命令来进行服务治理。</p>\n<h2>使用</h2>\n<pre><code class=\"language-sh\">telnet 
localhost 20880\n</code></pre>\n<p>或者:</p>\n<pre><code 
class=\"language-sh\"><span class=\"hljs-built_in\">echo</span> status | nc -i 
1 localhost 20880\n</code></pre>\n<p>status命令所检查的资源也可以扩展,参见:<a 
href=\"../../dev/impls/status-checker.md\">扩展参考手册</a>。</p>\n<h2>命令</h2>\n<p>以下展示了
 dubbo 内建的 telnet 命令的说明和用法,此外,telnet 命令还支持用户自行扩展,参见:<a href [...]
+  "__html": "<h1>Telnet 命令参考手册</h1>\n<p>从 <code>2.0.5</code> 版本开始,dubbo 开始支持通过 
telnet 命令来进行服务治理。</p>\n<h2>使用</h2>\n<pre><code class=\"language-sh\">telnet 
localhost 20880\n</code></pre>\n<p>或者:</p>\n<pre><code 
class=\"language-sh\"><span class=\"hljs-built_in\">echo</span> status | nc -i 
1 localhost 20880\n</code></pre>\n<p>status命令所检查的资源也可以扩展,参见:<a 
href=\"../../dev/impls/status-checker.md\">扩展参考手册</a>。</p>\n<h2>命令</h2>\n<p>以下展示了
 dubbo 内建的 telnet 命令的说明和用法,此外,telnet 命令还支持用户自行扩展,参见:<a href [...]
   "link": "/zh-cn/docs/user/references/telnet.html",
   "meta": {}
 }
\ No newline at end of file

Reply via email to