摘要: “没有最好的技术,只有最合适的技术。”我想这句话也同样适用于微服务领域,没有最好的服务框架,只有最适合自己的服务改造。在 dubbo 的未来规划中,除了保持自身技术上的领先性,关注性能、大流量、大规模集群领域的挑战外,围绕 dubbo 核心来发展生态,将 dubbo 打造成一个服务化改造的整体方案也是重点之一。
“没有最好的技术,只有最合适的技术。”我想这句话也同样适用于微服务领域,没有最好的服务框架,只有最适合自己的服务改造。在 dubbo 的未来规划中,除了保持自身技术上的领先性,关注性能、大流量、大规模集群领域的挑战外,围绕 dubbo 核心来发展生态,将 dubbo 打造成一个服务化改造的整体方案也是重点之一。从本期开始,我们将推出“服务化改造”系列文章,通过在一些外围系统和服务化基础组件上的开发实践,分享dubbo 生态下的服务化改造收获和总结。
» 8月26日,aliware open source 将首次在成都举办 apache dubbo 的meetup活动,dubbo 、sentinel和 nacos 的小哥哥和小姐姐都会在现场进行技术分享,欢迎成都的朋友报名参加我们的活动喔,搜索“阿里巴巴中间件”公众号,后台发送“成都meetup”,获取报名链接。
一、改造背景在现代的分布式应用中,往往会出现节点和节点之间的协调问题,其中就包括了:选主,集群管理,分布式锁,分布式配置管理,统一命名服务,状态同步等诉求。apache zookeeper,正如它的名字所暗示的那样,动物园管理员,就是为了解决这些诉求的一个分布式协调服务框架。
为了保证系统的高可用,zookeeper本身也可以部署成集群模式,称之为zookeeper ensemble。zookeeper集群中始终确保其中的一台为leader的角色,并通过zab(zookeeper atomic broadcast protocol)[1] 协议确保所有节点上的信息的一致。客户端可以访问集群中的任何一台进行读写操作,而不用担心数据出现不一致的现象。
o'reilly的ebook-zookeeper-distributed process coordination
zookeeper中的数据存储方式与传统的unix文件系统相似,节点按照树状结构来组织,其中,节点被称之为znodes(zookeeper数据节点)
o'reilly的ebook-zookeeper-distributed process coordination
二、基本用法可以通过直接下载的方式[2] 安装并运行zookeeper,在mac上也可以通过homebrew [3] brew install zookeeper 来安装,考虑到通用性,本文采用docker的方式来运行zookeeper。如果没有安装docker,请先准备好docker环境 [4]。
1、启动 zookeeper
执行命令将 zookeeper,运行在docker容器中。
docker run --rm --name zookeeper -p 2181:2181 zookeeper2、进入 zookeeper 容器
docker exec -it zookeeper bash在bin 目录下有启动 zookeeper 的命令 zkserver 以及管理控制台 zkcli
bash-4.4# ls -l bintotal 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端口对外提供服务。
bash-4.4# pspid user time command1 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 的控制台来进行管理。
bash-4.4# bin/zkcli.sh -server 127.0.0.1:2181connecting to 127.0.0.1:2181...watcher::watchedevent state:syncconnected type:none path:null[zk: 127.0.0.1:2181(connected) 0] helpzookeeper -server host:port cmd args stat path [watch]set path data [version]ls path [watch]delquota [-n|-b] pathls2 path [watch]setacl path aclsetquota -n|-b val path historyredo cmdnoprintwatches on|offdelete path [version]sync pathlistquota pathrmr pathget path [watch]create [-s] [-e] path data acladdauth scheme authquitgetacl pathcloseconnect host:port4.zkcli上的一些基本操作
创建 /hello-zone 节点:
[zk: 127.0.0.1:2181(connected) 19] create /hello-zone 'world'created /hello-zone列出 / 下的子节点,确认 hello-zone 被创建:
[zk: 127.0.0.1:2181(connected) 19] create /hello-zone 'world'created /hello-zone列出 /hello-zone的子节点,确认为空:
[zk: 127.0.0.1:2181(connected) 21] ls /hello-zone[]获取存储在 /hello-zone节点上的数据:
[zk: 127.0.0.1:2181(connected) 22] get /hello-zoneworld三、在 dubbo 中使用zookeeperdubbo使用 zookeeper 用于服务的注册发现和配置管理,在zookeeper中数据的组织由下图所示:
首先,所有dubbo相关的数据都组织在 /duboo 的根节点下。
二级目录是服务名,如 com.foo.barservice。
三级目录有两个子节点,分别 providers 和 consumers,表示该服务的提供者和消费者。
四级目录记录了与该服务相关的每一个应用实例的url信息,在 providers 下的表示该服务的所有提供者,而在 consumers 下的表示该服务的所有消费者。举例说明,com.foo.barservice 的服务提供者在启动时将自己的url信息注册到 /dubbo/com.foo.barservice/providers 下;同样的,服务消费者将自己的信息注册到相应的 consumers 下,同时,服务消费者会订阅其所对应的 providers 节点,以便能够感知到服务提供方地址列表的变化。
四、准备示例代码本文代码可以在以下链接中找到。
1、接口定义
一个定义简单的 greetingservice 接口,只有里面一个简单的方法 sayhello 向调用者问好。
public interface greetingservice {string sayhello(string name);}2、服务端:服务实现
实现 greetingservice接口,并通过 @service 来标注其为dubbo的一个服务。
@servicepublic class annotatedgreetingservice implements greetingservice {public string sayhello(string name) { return hello, + name;}}3、服务端:组装
定义 providerconfiguration 来组装dubbo服务。
@configuration@enabledubbo(scanbasepackages = com.alibaba.dubbo.samples.impl)@propertysource(classpath:/spring/dubbo-provider.properties)static class providerconfiguration {}dubbo-provider.properties是在spring应用中外置配置的方式,内容如下:
dubbo.application.name=demo-providerdubbo.registry.address=zookeeper://$docker_host:2181dubbo.protocol.name=dubbodubbo.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服务。
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 这个服务:
[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管理终端观察服务提供方的注册信息:
$ docker exec -it zookeeper bashbash-4.4# bin/zkcli.sh -server localhost:218connecting to localhost:2181...welcome to zookeeper!jline support is enabled...[zk: localhost:2181(connected) 0] ls[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 0.2&通用=假接口=com.alibaba.dubbo.samples.api.greetingservice&方法= sayhello的&pid = 12938&侧=提供商时间戳=1533264631849
5、客户端:引用服务
通过 @reference 来在客户端声明服务的引用,运行时将会通过该引用发起全程调用,而服务的目标地址将会从zookeeper的provider 节点下查询。
@component(annotatedconsumer)public class greetingserviceconsumer {@referenceprivate greetingservice greetingservice;public string dosayhello(string name) { return greetingservice.sayhello(name);}}6、客户端:组装
定义consumerconfiguration来组装dubbo服务。
@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应用中外置配置的方式,内容如下:
dubbo.application.name=demo-consumerdubbo.registry.address=zookeeper://$docker_host:2181dubbo.consumer.timeout=3000与服务端:组装相同,需要根据自己的运行环境来修改dubbo.registry.address中定义的$ docker_host。请参阅步骤3的说明部分。
7、客户端:发起远程调用
运行 main 向已经启动的服务提供方发起一次远程调用。dubbo会先向zookeeper订阅服务地址,然后从返回的地址列表中选取一个,向对端发起调用:
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();}}运行结果如下:
[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
说明:注册:消费者://192.168.99.1/...& category= consumers&:消费者向zookeeper注册自己的信息,并放在 consumers 节点下
订阅:消费者://192.168.99.1/...& 类别=提供商,配置器,路由器:消费者同时向动物园管理员订阅了providers、configurators、routers 节点,其中 configurations 与多宝配置相关,routers 与路由规则相关,值得注意的英文 providers 节点的订阅,当有新的服务提供方加入后,由于订阅的关系,新的地址列表会推送给订阅方,服务的消费者也因此动态感知到了地址列表的变化。
通过zookeeper管理终端观察服务提供方的注册信息:
$ docker exec -it zookeeper bashbash-4.4# bin/zkcli.sh -server localhost:218connecting 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中服务注册,消费信息的存储方式
当然,自从阿里巴巴开源 nacos 后,dubbo生态中又多了一项动态服务发现的选项,nacos + dubbo的组合正进一步释放 dubbo 在云原生及servicemesh时代中,在大规模微服务治理、流量治理、服务集成与服务共享等服务平台能力建设上的威力。- 链接
参考链接:
[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
原文链接
本文为云栖社区原创内容,未经允许不得转载。
10W led驱动芯片CY2525D呈现更多精彩
龙芯3a5000和3a3000的区别
额温枪的原理及构造
点成分享 | 带你了解移液器的原理及其分类
Airpods2有什么新功能
服务化改造实践(一)| Dubbo + ZooKeeper
Diodes公司的双向8通道电位转换器提供宽电压范围及弹性输出选项
天才少年稚晖君官宣智元人形机器人「远征 A1」即将发布
CVE漏洞—PHPCMS2008 /type.php代码注入高危漏洞预警
VI 编辑器的命令、模式和选项介绍
人工智能在未来三年内将深刻地改变人类活动方式
基于FX1N-40MT芯片的交流伺服定剪系统的设计
关于国内外四款数据可视化软件的介绍
双十一临近彩电行业价格战愈演愈烈
vivoZ5评测 全能ACE向旗舰看齐
INTEST公司成功入选湖北省第五批专精特新中小企业
一些能够实现5G基站和网络的关键RF通信技术
电子芯闻早报:中国自主芯片逆袭,VR很火热
功率放大金属颗粒材质识别应用案例
华为p50芯片制造公司排名