This is an automated email from the ASF dual-hosted git repository. iluo 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 3d584d7 publish blog 'dubbo-zk' 3d584d7 is described below commit 3d584d7fe0424b435dd014f1379aafe7a7d0ae54 Author: beiwei.ly <beiwei...@alibaba-inc.com> AuthorDate: Fri Aug 3 16:01:17 2018 +0800 publish blog 'dubbo-zk' --- blog/zh-cn/dubbo-zk.md | 339 +++++++++++++++++++++ ...7ba6acec73c8197d.js => 0abb2937d4e2bc4697f3.js} | 2 +- build/0b0bbf419be1d7b49571.js | 6 - ...f8eca3ff7556b8db.js => 197de76506a1ddd84a4b.js} | 0 build/55de20a411cd16ffcaad.js | 6 + ...ed1d026d7ba627aa.js => 87c67c0d7caf73d7e493.js} | 0 ...5d02abb36f898304.js => c5ce7257df274bc595ec.js} | 2 +- build/page.js | 2 +- img/blog/dubbo-in-zk.jpg | Bin 0 -> 31272 bytes img/blog/zk-emsemble.png | Bin 0 -> 86220 bytes img/blog/zk-tree.png | Bin 0 -> 34214 bytes md_json/blog.json | 4 + md_json/docs.json | 8 +- site_config/blog.js | 7 + 14 files changed, 363 insertions(+), 13 deletions(-) diff --git a/blog/zh-cn/dubbo-zk.md b/blog/zh-cn/dubbo-zk.md new file mode 100644 index 0000000..8a69062 --- /dev/null +++ b/blog/zh-cn/dubbo-zk.md @@ -0,0 +1,339 @@ +# 在 Dubbo 应用中使用 Zookeeper + +## Zookeeper 介绍 + +### 基本概念 + +在现代的分布式应用中,往往会出现节点和节点之间的协调问题,其中就包括了:选主、集群管理、分布式锁、分布式配置管理、统一命名服务、状态同步等诉求。[Apache Zookeeper](https://zookeeper.apache.org),正如它的名字所暗示的那样,*动物园管理员*,就是为了解决这些诉求的一个分布式协调服务框架。 + +为了保证高可用,ZooKeeper 本身也可以部署成集群模式,称之为 *ZooKeeper ensemble*。ZooKeeper 集群中始终确保其中的一台为 leader 的角色,并通过 *ZAB (Zookeeper Atomic Broadcast Protocol) [^1]* 协议确保所有节点上的信息的一致。客户端可以访问集群中的任何一台进行读写操作,而不用担心数据出现不一致的现象。 + +![Diagram shows client-server architecture of ZooKeeper](../../img/blog/zk-emsemble.png) +*Image Credit : ebook -Zookeeper-Distributed Process Coordination from O'Reilly* + +Zookeeper 中的数据存储方式与传统的 UNIX 文件系统相似,节点按照树状结构来组织,其中,节点被称之为 *znodes (ZooKeeper data nodes)* + +![zk-tree](../../img/blog/zk-tree.png) +*Image Credit : ebook -Zookeeper-Distributed Process Coordination from O'Reilly* + +### 基本用法 + +可以通过直接下载的方式 [^2]安装并运行 Zookeeper ,在 Mac 上也可以通过 Homebrew [^3] `brew install zookeeper` 来安装,考虑到通用性,本文采用 docker 的方式来运行 Zookeeper。如果没有安装 docker,请先准备好 docker 环境 [^4]。 + +#### 1. 启动 Zookeeper + +执行命令将 Zookeeper 运行在 docker 容器中 + +```shell +docker run --rm --name zookeeper -p 2181:2181 zookeeper +``` + +#### 2. 进入 Zookeeper 容器 + +```shell +docker exec -it zookeeper bash +``` + +在 `bin` 目录下有启动 Zookeeper 的命令 `zkServer` 以及管理控制台 `zkCli` + +```shell +bash-4.4# ls -l bin +total 36 +-rwxr-xr-x 1 zookeepe zookeepe 232 Mar 27 04:32 README.txt +-rwxr-xr-x 1 zookeepe zookeepe 1937 Mar 27 04:32 zkCleanup.sh +-rwxr-xr-x 1 zookeepe zookeepe 1056 Mar 27 04:32 zkCli.cmd +-rwxr-xr-x 1 zookeepe zookeepe 1534 Mar 27 04:32 zkCli.sh +-rwxr-xr-x 1 zookeepe zookeepe 1759 Mar 27 04:32 zkEnv.cmd +-rwxr-xr-x 1 zookeepe zookeepe 2696 Mar 27 04:32 zkEnv.sh +-rwxr-xr-x 1 zookeepe zookeepe 1089 Mar 27 04:32 zkServer.cmd +-rwxr-xr-x 1 zookeepe zookeepe 6773 Mar 27 04:32 zkServer.sh +``` + +#### 3. 通过 zkCli 进入 Zookeeper 管理界面 + +由于是通过 Docker 启动,Zookeeper 进程已经启动,并通过 2181 端口对外提供服务。 + +```shell +bash-4.4# ps +PID USER TIME COMMAND + 1 zookeepe 0:02 /usr/lib/jvm/java-1.8-openjdk/jre/bin/java -Dzookeeper.log.dir=. -Dzookeeper.root + 32 root 0:00 bash + 42 root 0:00 ps +``` + +因此可以直接通过 `zkCli` 来访问 Zookeeper 的控制台来进行管理。 + +```shell +bash-4.4# bin/zkCli.sh -server 127.0.0.1:2181 +Connecting to 127.0.0.1:2181 +... +WATCHER:: + +WatchedEvent state:SyncConnected type:None path:null + +[zk: 127.0.0.1:2181(CONNECTED) 0] help +ZooKeeper -server host:port cmd args + stat path [watch] + set path data [version] + ls path [watch] + delquota [-n|-b] path + ls2 path [watch] + setAcl path acl + setquota -n|-b val path + history + redo cmdno + printwatches on|off + delete path [version] + sync path + listquota path + rmr path + get path [watch] + create [-s] [-e] path data acl + addauth scheme auth + quit + getAcl path + close + connect host:port +``` + +#### 4. zkCli 上的一些基本操作 + +创建 `/hello-zone` 节点: + +```shell +[zk: 127.0.0.1:2181(CONNECTED) 19] create /hello-zone 'world' +Created /hello-zone +``` + +列出 `/` 下的子节点,确认 `hello-zone` 被创建: + +```shell +[zk: 127.0.0.1:2181(CONNECTED) 20] ls / +[zookeeper, hello-zone] +``` + +列出 `/hello-zone` 的子节点,确认为空: + +```shell +[zk: 127.0.0.1:2181(CONNECTED) 21] ls /hello-zone +[] +``` + +获取存储在 `/hello-zone` 节点上的数据: + +```shell +[zk: 127.0.0.1:2181(CONNECTED) 22] get /hello-zone +world +``` + + + +## 在 Dubbo 中使用 Zookeeper + +Dubbo 使用 Zookeeper 用于服务的注册发现和配置管理,在 Zookeeper 中数据的组织由下图所示: + +![dubbo-in-zk](../../img/blog/dubbo-in-zk.jpg) + +首先,所有 Dubbo 相关的数据都组织在 `/duboo` 的根节点下。 + +二级目录是服务名,如 `com.foo.BarService`。 + +三级目录有两个子节点,分别是 `providers` 和 `consumers`,表示该服务的提供者和消费者。 + +四级目录记录了与该服务相关的每一个应用实例的 URL 信息,在 `providers` 下的表示该服务的所有提供者,而在 `consumers` 下的表示该服务的所有消费者。举例说明,`com.foo.BarService` 的服务提供者在启动时将自己的 URL 信息注册到 `/dubbo/com.foo.BarService/providers` 下;同样的,服务消费者将自己的信息注册到相应的 `consumers` 下,同时,服务消费者会订阅其所对应的 `providers` 节点,以便能够感知到服务提供方地址列表的变化。 + +### 准备示例代码 + +本文的代码可以在 https://github.com/dubbo/dubbo-samples/tree/master/dubbo-samples-zookeeper 中找到。 + +#### 1. 接口定义 + +定义一个简单的 `GreetingService` 接口,里面只有一个简单的方法 `sayHello` 向调用者问好。 + +```java +public interface GreetingService { + String sayHello(String name); +} +``` + +#### 2. 服务端:服务实现 + +实现 `GreetingService` 接口,并通过 `@Service` 来标注其为 Dubbo 的一个服务。 + +```java +@Service +public class AnnotatedGreetingService implements GreetingService { + public String sayHello(String name) { + return "hello, " + name; + } +} +``` + +#### 3. 服务端:组装 + +定义 ProviderConfiguration 来组装 Dubbo 服务。 + +```java +@Configuration +@EnableDubbo(scanBasePackages = "com.alibaba.dubbo.samples.impl") +@PropertySource("classpath:/spring/dubbo-provider.properties") +static class ProviderConfiguration {} +``` + +dubbo-provider.properties 是在 Spring 应用中外置配置的方式,内容如下: + +```properties +dubbo.application.name=demo-provider +dubbo.registry.address=zookeeper://$DOCKER_HOST:2181 +dubbo.protocol.name=dubbo +dubbo.protocol.port=20880 +``` + +由于 Zookeeper 运行在 Docker 容器中,需要注意的是: + +* 本文假定 Dubbo 应用运行在宿主机上,也就是 Docker 容器外,需要将 Zookeeper 的地址替换成环境变量 *${DOCKER_HOST}* 所指定的 IP 地址,相关信息请查阅 Docker 官方文档 +* 如果 Dubbo 应用也是 Docker 化的应用,只需要用 Zookeeper 的容器名,在本文中容器名是 **zookeeper** +* 当然,如果不用容器方式启动 Zookeeper,只需要简单的将这里的 *$DOCKER_HOST* 换成 **localhost** 即可 + +#### 4. 服务端:启动服务 + +在 `main` 方法中通过启动一个 Spring Context 来对外提供 Dubbo 服务。 + +```java +public class ProviderBootstrap { + public static void main(String[] args) throws Exception { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ProviderConfiguration.class); + context.start(); + System.in.read(); + } +} +``` + +启动服务端的 `main` 方法,将会看到下面的输出,代表服务端启动成功,并在注册中心(ZookeeperRegistry)上注册了 `GreetingService` 这个服务: + +```sh +[03/08/18 10:50:33:033 CST] main INFO zookeeper.ZookeeperRegistry: [DUBBO] Register: dubbo://192.168.99.1:20880/com.alibaba.dubbo.samples.api.GreetingService?anyhost=true&application=demo-provider&dubbo=2.6.2&generic=false&interface=com.alibaba.dubbo.samples.api.GreetingService&methods=sayHello&pid=12938&side=provider×tamp=1533264631849, dubbo version: 2.6.2, current host: 192.168.99.1 +``` + +通过 Zookeeper 管理终端观察服务提供方的注册信息: + +```sh +$ docker exec -it zookeeper bash +bash-4.4# bin/zkCli.sh -server localhost:218 +Connecting to localhost:2181 +... +Welcome to ZooKeeper! +JLine support is enabled +... +[zk: localhost:2181(CONNECTED) 0] ls /dubbo/com.alibaba.dubbo.samples.api.GreetingService/providers +[dubbo%3A%2F%2F192.168.99.1%3A20880%2Fcom.alibaba.dubbo.samples.api.GreetingService%3Fanyhost%3Dtrue%26application%3Ddemo-provider%26dubbo%3D2.6.2%26generic%3Dfalse%26interface%3Dcom.alibaba.dubbo.samples.api.GreetingService%26methods%3DsayHello%26pid%3D12938%26side%3Dprovider%26timestamp%3D1533264631849] +``` + +可以看到刚刚启动的 Dubbo 的服务在 `providers` 节点下注册了自己的 URL 地址:*dubbo://192.168.99.1:20880/com.alibaba.dubbo.samples.api.GreetingService?anyhost=true&application=demo-provider&dubbo=2.6.2&generic=false&interface=com.alibaba.dubbo.samples.api.GreetingService&methods=sayHello&pid=12938&side=provider×tamp=1533264631849* + +#### 5. 客户端:引用服务 + +通过 `@Reference` 来在客户端声明服务的引用,运行时将会通过该引用发起全程调用,而服务的目标地址将会从 Zookeeper 的 `provider` 节点下查询。 + +```java +@Component("annotatedConsumer") +public class GreetingServiceConsumer { + @Reference + private GreetingService greetingService; + + public String doSayHello(String name) { + return greetingService.sayHello(name); + } +} +``` + +#### 6. 客户端:组装 + +定义 ConsumerConfiguration 来组装 Dubbo 服务。 + +```java +@Configuration +@EnableDubbo(scanBasePackages = "com.alibaba.dubbo.samples.action") +@PropertySource("classpath:/spring/dubbo-consumer.properties") +@ComponentScan(value = {"com.alibaba.dubbo.samples.action"}) +static class ConsumerConfiguration {} +``` + +dubbo-consumer.properties 是在 Spring 应用中外置配置的方式,内容如下: + +```properties +dubbo.application.name=demo-consumer +dubbo.registry.address=zookeeper://$DOCKER_HOST:2181 +dubbo.consumer.timeout=3000 +``` + +与 **3. 服务端:组装** 相同,需要根据自己的运行环境来修改 *dubbo.registry.address* 中定义的 *$DOCKER_HOST*。请参阅步骤 3 的说明部分。 + +#### 7. 客户端:发起远程调用 + +运行 `main` 向已经启动的服务提供方发起一次远程调用。Dubbo 会先向 Zookeeper 订阅服务地址,然后从返回的地址列表中选取一个,向对端发起调用: + +```java +public class ConsumerBootstrap { + public static void main(String[] args) { +public class ConsumerBootstrap { + + public static void main(String[] args) throws IOException { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConsumerConfiguration.class); + context.start(); + GreetingServiceConsumer greetingServiceConsumer = context.getBean(GreetingServiceConsumer.class); + String hello = greetingServiceConsumer.doSayHello("zookeeper"); + System.out.println("result: " + hello); + System.in.read(); + } +} +``` + +运行结果如下: + +```shell +[03/08/18 01:42:31:031 CST] main INFO zookeeper.ZookeeperRegistry: [DUBBO] Register: consumer://192.168.99.1/com.alibaba.dubbo.samples.api.GreetingService?application=demo-consumer&category=consumers&check=false&default.timeout=3000&dubbo=2.6.2&interface=com.alibaba.dubbo.samples.api.GreetingService&methods=sayHello&pid=82406&side=consumer×tamp=1533274951195, dubbo version: 2.6.2, current host: 192.168.99.1 #1 +[03/08/18 01:42:31:031 CST] main INFO zookeeper.ZookeeperRegistry: [DUBBO] Subscribe: consumer://192.168.99.1/com.alibaba.dubbo.samples.api.GreetingService?application=demo-consumer&category=providers,configurators,routers&default.timeout=3000&dubbo=2.6.2&interface=com.alibaba.dubbo.samples.api.GreetingService&methods=sayHello&pid=82406&side=consumer×tamp=1533274951195, dubbo version: 2.6.2, current host: 192.168.99.1 #2 +... +result: hello, zookeeper +``` + +说明: + +1. **Register**: consumer://192.168.99.1/...&**category=consumers**&:消费者向 Zookeeper 注册自己的信息,并放在 `consumers` 节点下 +2. **Subscribe**: consumer://192.168.99.1/...&**category=providers,configurators,routers**&:消费者同时向 Zookeeper 订阅了 `providers`、`configurators`、`routers` 节点,其中 `configurations` 与 Dubbo 配置相关,`routers` 与路由规则相关,值得注意的是 `providers` 节点的订阅,当有新的服务提供方加入后,由于订阅的关系,新的地址列表会推送给订阅方,服务的消费者也因此动态感知到了地址列表的变化。 + +通过 Zookeeper 管理终端观察服务提供方的注册信息: + +```sh +$ docker exec -it zookeeper bash +bash-4.4# bin/zkCli.sh -server localhost:218 +Connecting to localhost:2181 +... +Welcome to ZooKeeper! +JLine support is enabled +... +[zk: localhost:2181(CONNECTED) 4] ls /dubbo/com.alibaba.dubbo.samples.api.GreetingService/consumers +[consumer%3A%2F%2F192.168.99.1%2Fcom.alibaba.dubbo.samples.api.GreetingService%3Fapplication%3Ddemo-consumer%26category%3Dconsumers%26check%3Dfalse%26default.timeout%3D3000%26dubbo%3D2.6.2%26interface%3Dcom.alibaba.dubbo.samples.api.GreetingService%26methods%3DsayHello%26pid%3D82406%26side%3Dconsumer%26timestamp%3D1533274951195] +``` + +可以看到 Dubbo 的服务消费者在 `consumers` 节点下注册了自己的 URL 地址:*consumer://192.168.99.1/com.alibaba.dubbo.samples.api.GreetingService?application=demo-consumer&category=providers,configurators,routers&default.timeout=3000&dubbo=2.6.2&interface=com.alibaba.dubbo.samples.api.GreetingService&methods=sayHello&pid=82406&side=consumer×tamp=1533274951195* + +## 总结 + +本文侧重介绍了如何在 Dubbo 应用中使用 Zookeeper 做为注册中心,当然,本文也提到了 Zookeeper 在 Dubbo 的应用场景下还承担了配置中心和服务治理的职责。本文中的 Zookeeper 是单节点、Standalone 的模式,在生产环境中为了高可用的诉求,往往会组件 Zookeeper 集群,也就是 *Zookeeper ensemble* 模式。 + +通过本文的学习,读者可以掌握到: + +* Zookeeper 的基本概念和基本用法 +* Zookeeper 在 Dubbo 应用中的作用 +* 通过实战了解 Zookeeper 与 Dubbo 的交互 +* Dubbo 在 Zookeeper 中服务注册、消费信息的存储方式 + + + +[^1]: https://www.ixiacom.com/company/blog/apache-zab—zookeeper-atomic-broadcast-protocol +[^2]: https://www.apache.org/dyn/closer.cgi/zookeeper/ +[^3]: https://brew.sh +[^4]: https://www.docker.com/community-edition + diff --git a/build/1cb17ba6acec73c8197d.js b/build/0abb2937d4e2bc4697f3.js similarity index 78% rename from build/1cb17ba6acec73c8197d.js rename to build/0abb2937d4e2bc4697f3.js index 2b2ff4b..bdd543b 100644 --- a/build/1cb17ba6acec73c8197d.js +++ b/build/0abb2937d4e2bc4697f3.js @@ -3,4 +3,4 @@ webpackJsonp([4],[,,,,,,,function(e,t,n){"use strict";function r(e){return e&&e. 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))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 diff --git a/build/0b0bbf419be1d7b49571.js b/build/0b0bbf419be1d7b49571.js deleted file mode 100644 index c94f059..0000000 --- a/build/0b0bbf419be1d7b49571.js +++ /dev/null @@ -1,6 +0,0 @@ -webpackJsonp([1],[,,,,,,,,function(s,n,a){"use strict";function e(s){return s&&s.__esModule?s:{default:s}}function t(s,n){if(!(s instanceof n))throw new TypeError("Cannot call a class as a function")}function l(s,n){if(!s)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!n||"object"!=typeof n&&"function"!=typeof n?s:n}function o(s,n){if("function"!=typeof n&&null!==n)throw new TypeError("Super expression must either be null or a function, not "+ [...] - Copyright (c) 2016 Jed Watson. - Licensed under the MIT License (MIT), see - http://jedwatson.github.io/classnames -*/ -!function(){"use strict";function a(){for(var s=[],n=0;n<arguments.length;n++){var e=arguments[n];if(e){var t=typeof e;if("string"===t||"number"===t)s.push(e);else if(Array.isArray(e))s.push(a.apply(null,e));else if("object"===t)for(var o in e)l.call(e,o)&&e[o]&&s.push(o)}}return s.join(" ")}var l={}.hasOwnProperty;void 0!==s&&s.exports?s.exports=a:(e=[],void 0!==(t=function(){return a}.apply(n,e))&&(s.exports=t))}()},function(s,n,a){"use strict";function e(s,n,e){var t=e.configurable,p= [...] \ No newline at end of file diff --git a/build/de65f8eca3ff7556b8db.js b/build/197de76506a1ddd84a4b.js similarity index 100% rename from build/de65f8eca3ff7556b8db.js rename to build/197de76506a1ddd84a4b.js diff --git a/build/55de20a411cd16ffcaad.js b/build/55de20a411cd16ffcaad.js new file mode 100644 index 0000000..1445dec --- /dev/null +++ b/build/55de20a411cd16ffcaad.js @@ -0,0 +1,6 @@ +webpackJsonp([1],[,,,,,,,,function(s,n,a){"use strict";function e(s){return s&&s.__esModule?s:{default:s}}function t(s,n){if(!(s instanceof n))throw new TypeError("Cannot call a class as a function")}function o(s,n){if(!s)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!n||"object"!=typeof n&&"function"!=typeof n?s:n}function l(s,n){if("function"!=typeof n&&null!==n)throw new TypeError("Super expression must either be null or a function, not "+ [...] + Copyright (c) 2016 Jed Watson. + Licensed under the MIT License (MIT), see + http://jedwatson.github.io/classnames +*/ +!function(){"use strict";function a(){for(var s=[],n=0;n<arguments.length;n++){var e=arguments[n];if(e){var t=typeof e;if("string"===t||"number"===t)s.push(e);else if(Array.isArray(e))s.push(a.apply(null,e));else if("object"===t)for(var l in e)o.call(e,l)&&e[l]&&s.push(l)}}return s.join(" ")}var o={}.hasOwnProperty;void 0!==s&&s.exports?s.exports=a:(e=[],void 0!==(t=function(){return a}.apply(n,e))&&(s.exports=t))}()},function(s,n,a){"use strict";function e(s,n,e){var t=e.configurable,p= [...] \ No newline at end of file diff --git a/build/2796ed1d026d7ba627aa.js b/build/87c67c0d7caf73d7e493.js similarity index 100% rename from build/2796ed1d026d7ba627aa.js rename to build/87c67c0d7caf73d7e493.js diff --git a/build/49955d02abb36f898304.js b/build/c5ce7257df274bc595ec.js similarity index 55% rename from build/49955d02abb36f898304.js rename to build/c5ce7257df274bc595ec.js index ca38086..cff5452 100644 --- a/build/49955d02abb36f898304.js +++ b/build/c5ce7257df274bc595ec.js @@ -3,4 +3,4 @@ webpackJsonp([0],[,,,,,,,,,,function(s,n,a){"use strict";function e(s){return s& Licensed under the MIT License (MIT), see http://jedwatson.github.io/classnames */ -!function(){"use strict";function a(){for(var s=[],n=0;n<arguments.length;n++){var e=arguments[n];if(e){var t=typeof e;if("string"===t||"number"===t)s.push(e);else if(Array.isArray(e))s.push(a.apply(null,e));else if("object"===t)for(var o in e)l.call(e,o)&&e[o]&&s.push(o)}}return s.join(" ")}var l={}.hasOwnProperty;void 0!==s&&s.exports?s.exports=a:(e=[],void 0!==(t=function(){return a}.apply(n,e))&&(s.exports=t))}()},function(s,n,a){"use strict";function e(s,n,e){var t=e.configurable,r= [...] \ No newline at end of file +!function(){"use strict";function a(){for(var s=[],n=0;n<arguments.length;n++){var e=arguments[n];if(e){var t=typeof e;if("string"===t||"number"===t)s.push(e);else if(Array.isArray(e))s.push(a.apply(null,e));else if("object"===t)for(var o in e)l.call(e,o)&&e[o]&&s.push(o)}}return s.join(" ")}var l={}.hasOwnProperty;void 0!==s&&s.exports?s.exports=a:(e=[],void 0!==(t=function(){return a}.apply(n,e))&&(s.exports=t))}()},function(s,n,a){"use strict";function e(s,n,e){var t=e.configurable,r= [...] \ No newline at end of file diff --git a/build/page.js b/build/page.js index b91cc45..63766c6 100644 --- a/build/page.js +++ b/build/page.js @@ -1 +1 @@ -!function(n){function o(t){if(e[t])return e[t].exports;var r=e[t]={i:t,l:!1,exports:{}};return n[t].call(r.exports,r,r.exports,o),r.l=!0,r.exports}var t=window.webpackJsonp;window.webpackJsonp=function(o,e,a){for(var i,d,l=0,c=[];l<o.length;l++)d=o[l],r[d]&&c.push(r[d][0]),r[d]=0;for(i in e)Object.prototype.hasOwnProperty.call(e,i)&&(n[i]=e[i]);for(t&&t(o,e,a);c.length;)c.shift()()};var e={},r={5:0};o.e=function(n){function t(){d.onerror=d.onload=null,clearTimeout(l);var o=r[n];0!==o&&(o [...] \ No newline at end of file +!function(n){function o(t){if(e[t])return e[t].exports;var r=e[t]={i:t,l:!1,exports:{}};return n[t].call(r.exports,r,r.exports,o),r.l=!0,r.exports}var t=window.webpackJsonp;window.webpackJsonp=function(o,e,a){for(var i,d,l=0,c=[];l<o.length;l++)d=o[l],r[d]&&c.push(r[d][0]),r[d]=0;for(i in e)Object.prototype.hasOwnProperty.call(e,i)&&(n[i]=e[i]);for(t&&t(o,e,a);c.length;)c.shift()()};var e={},r={5:0};o.e=function(n){function t(){d.onerror=d.onload=null,clearTimeout(l);var o=r[n];0!==o&&(o [...] \ No newline at end of file diff --git a/img/blog/dubbo-in-zk.jpg b/img/blog/dubbo-in-zk.jpg new file mode 100644 index 0000000..f715e52 Binary files /dev/null and b/img/blog/dubbo-in-zk.jpg differ diff --git a/img/blog/zk-emsemble.png b/img/blog/zk-emsemble.png new file mode 100644 index 0000000..cd51fb2 Binary files /dev/null and b/img/blog/zk-emsemble.png differ diff --git a/img/blog/zk-tree.png b/img/blog/zk-tree.png new file mode 100644 index 0000000..fc9c031 Binary files /dev/null and b/img/blog/zk-tree.png differ diff --git a/md_json/blog.json b/md_json/blog.json index 46823e9..2b9d325 100644 --- a/md_json/blog.json +++ b/md_json/blog.json @@ -21,6 +21,10 @@ "__html": "<h2>第二届Dubbo开发者沙龙在上海成功举办</h2>\n<p>第二届Dubbo开发者沙龙在上海成功举办,超过700位开发者报名,现场参与人数300+,通过阿里云天池、云栖社区、大咖说引导线上直播观看次数10000+</p>\n<p>分享嘉宾及PPT:</p>\n<ul>\n<li>朱勇: Dubbo开源现状与未来规划 (中文) <a href=\"https://github.com/dubbo/awesome-dubbo/blob/master/slides/meetup/201806%40Shanghai/dubbo-status-and-roadmap.pdf\">slides</a></li>\n<li>小马哥: Dubbo Cloud Native 之路的实践与思考 (中文) <a href=\"https://github.com/dubbo/awesome-dubbo/blob/master/slides/meetup/201806%40Shanghai/dubbo-cloud-native-practices-an [...] }, { + "filename": "dubbo-zk.md", + "__html": "<h1>在 Dubbo 应用中使用 Zookeeper</h1>\n<h2>Zookeeper 介绍</h2>\n<h3>基本概念</h3>\n<p>在现代的分布式应用中,往往会出现节点和节点之间的协调问题,其中就包括了:选主、集群管理、分布式锁、分布式配置管理、统一命名服务、状态同步等诉求。<a href=\"https://zookeeper.apache.org\">Apache Zookeeper</a>,正如它的名字所暗示的那样,<em>动物园管理员</em>,就是为了解决这些诉求的一个分布式协调服务框架。</p>\n<p>为了保证高可用,ZooKeeper 本身也可以部署成集群模式,称之为 <em>ZooKeeper ensemble</em>。ZooKeeper 集群中始终确保其中的一台为 leader 的角色,并通过 <em>ZAB (Zookeeper Atomic Broadcast Protocol) <sup class=\"footnote-ref\"><a href=\"#fn1\" id=\"fnref1\ [...] + }, + { "filename": "dubbo2-js.md", "__html": "<h1>从跨语言调用到dubbo2.js</h1>\n<blockquote>\n<p><a href=\"https://github.com/dubbo/dubbo2.js\">dubbo2.js</a> 是 <a href=\"https://www.qianmi.com/\">千米网</a> 贡献给 dubbo 社区的一款 nodejs dubbo 客户端,它提供了 nodejs 对原生 dubbo 协议的支持,使得 nodejs 和 java 这两种异构语言的 rpc 调用变得便捷,高效。</p>\n</blockquote>\n<h2>微服务跨语言调用</h2>\n<p>微服务架构已成为目前互联网架构的趋势,关于微服务的讨论,几乎占据了各种技术大会的绝大多数版面。国内使用最多的服务治理框架非阿里开源的 dubbo 莫属,千米网也选择了 dubbo 作为微服务治理框架。另一方面,和大多数互联网公司一样,千米的开发语言是多样的,大多数后端业务由 java 支撑,而每个业务线有各自开发语言的选择权,便出现了 nodejs,pyth [...] }, diff --git a/md_json/docs.json b/md_json/docs.json index 93ea2b2..913d377 100644 --- a/md_json/docs.json +++ b/md_json/docs.json @@ -626,11 +626,11 @@ }, { "filename": "user/references/xml/dubbo-protocol.md", - "__html": "<style>\ntable {\n width: 100%;\n max-width: 65em;\n border: 1px solid #dedede;\n margin: 15px auto;\n border-collapse: collapse;\n empty-cells: show;\n}\ntable th,\ntable td {\n height: 35px;\n border: 1px solid #dedede;\n padding: 0 10px;\n}\ntable th {\n font-weight: bold;\n text-align: center !important;\n background: rgba(158,188,226,0.2);\n white-space: nowrap;\n}\ntable tbody tr:nth-child(2n) {\n background: rgba(158,188,226,0.12);\n}\ntable td:nth-c [...] + "__html": "<style>\ntable {\n width: 100%;\n max-width: 65em;\n border: 1px solid #dedede;\n margin: 15px auto;\n border-collapse: collapse;\n empty-cells: show;\n}\ntable th,\ntable td {\n height: 35px;\n border: 1px solid #dedede;\n padding: 0 10px;\n}\ntable th {\n font-weight: bold;\n text-align: center !important;\n background: rgba(158,188,226,0.2);\n white-space: nowrap;\n}\ntable tbody tr:nth-child(2n) {\n background: rgba(158,188,226,0.12);\n}\ntable td:nth-c [...] }, { "filename": "user/references/xml/dubbo-provider.md", - "__html": "<style>\ntable {\n width: 100%;\n max-width: 65em;\n border: 1px solid #dedede;\n margin: 15px auto;\n border-collapse: collapse;\n empty-cells: show;\n}\ntable th,\ntable td {\n height: 35px;\n border: 1px solid #dedede;\n padding: 0 10px;\n}\ntable th {\n font-weight: bold;\n text-align: center !important;\n background: rgba(158,188,226,0.2);\n white-space: nowrap;\n}\ntable tbody tr:nth-child(2n) {\n background: rgba(158,188,226,0.12);\n}\ntable td:nth-c [...] + "__html": "<style>\ntable {\n width: 100%;\n max-width: 65em;\n border: 1px solid #dedede;\n margin: 15px auto;\n border-collapse: collapse;\n empty-cells: show;\n}\ntable th,\ntable td {\n height: 35px;\n border: 1px solid #dedede;\n padding: 0 10px;\n}\ntable th {\n font-weight: bold;\n text-align: center !important;\n background: rgba(158,188,226,0.2);\n white-space: nowrap;\n}\ntable tbody tr:nth-child(2n) {\n background: rgba(158,188,226,0.12);\n}\ntable td:nth-c [...] }, { "filename": "user/references/xml/dubbo-reference.md", @@ -1244,11 +1244,11 @@ }, { "filename": "user/references/xml/dubbo-protocol.md", - "__html": "<style>\ntable {\n width: 100%;\n max-width: 65em;\n border: 1px solid #dedede;\n margin: 15px auto;\n border-collapse: collapse;\n empty-cells: show;\n}\ntable th,\ntable td {\n height: 35px;\n border: 1px solid #dedede;\n padding: 0 10px;\n}\ntable th {\n font-weight: bold;\n text-align: center !important;\n background: rgba(158,188,226,0.2);\n white-space: nowrap;\n}\ntable tbody tr:nth-child(2n) {\n background: rgba(158,188,226,0.12);\n}\ntable td:nth-c [...] + "__html": "<style>\ntable {\n width: 100%;\n max-width: 65em;\n border: 1px solid #dedede;\n margin: 15px auto;\n border-collapse: collapse;\n empty-cells: show;\n}\ntable th,\ntable td {\n height: 35px;\n border: 1px solid #dedede;\n padding: 0 10px;\n}\ntable th {\n font-weight: bold;\n text-align: center !important;\n background: rgba(158,188,226,0.2);\n white-space: nowrap;\n}\ntable tbody tr:nth-child(2n) {\n background: rgba(158,188,226,0.12);\n}\ntable td:nth-c [...] }, { "filename": "user/references/xml/dubbo-provider.md", - "__html": "<style>\ntable {\n width: 100%;\n max-width: 65em;\n border: 1px solid #dedede;\n margin: 15px auto;\n border-collapse: collapse;\n empty-cells: show;\n}\ntable th,\ntable td {\n height: 35px;\n border: 1px solid #dedede;\n padding: 0 10px;\n}\ntable th {\n font-weight: bold;\n text-align: center !important;\n background: rgba(158,188,226,0.2);\n white-space: nowrap;\n}\ntable tbody tr:nth-child(2n) {\n background: rgba(158,188,226,0.12);\n}\ntable td:nth-c [...] + "__html": "<style>\ntable {\n width: 100%;\n max-width: 65em;\n border: 1px solid #dedede;\n margin: 15px auto;\n border-collapse: collapse;\n empty-cells: show;\n}\ntable th,\ntable td {\n height: 35px;\n border: 1px solid #dedede;\n padding: 0 10px;\n}\ntable th {\n font-weight: bold;\n text-align: center !important;\n background: rgba(158,188,226,0.2);\n white-space: nowrap;\n}\ntable tbody tr:nth-child(2n) {\n background: rgba(158,188,226,0.12);\n}\ntable td:nth-c [...] }, { "filename": "user/references/xml/dubbo-reference.md", diff --git a/site_config/blog.js b/site_config/blog.js index 83e83fa..3b5e104 100644 --- a/site_config/blog.js +++ b/site_config/blog.js @@ -52,6 +52,13 @@ export default { postsTitle: '所有文章', list: [ { + title: '在 Dubbo 应用中使用 Zookeeper', + author: '@beiwei30', + dateStr: 'August 3rd, 2018', + desc: '介绍了 Zookeeper 的基本概念、用法,以及如何在 Dubbo 应用中使用 Zookeeper 作为注册中心。', + link: '/blog/dubbo-zk.md', + }, + { title: '通过QoS对服务进行动态控制', author: 'Huxing Zhang', dateStr: 'August 2nd, 2018',