服务化改造实践(一):Dubbo + ZooKeeper
source link: https://mp.weixin.qq.com/s/m0cdOpep15LrTL7h-qNM8g?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
“没有最好的技术,只有最合适的技术。”我想这句话也同样适用于微服务领域, 没有最好的服务框架,只有最适合自己的服务改造 。在 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 zookeeper
2、进入 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 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 的控制台来进行管理。
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] 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
节点:
[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-zone world
三、在 Dubbo 中使用ZooKeeper
Dubbo使用 ZooKeeper 用于服务的注册发现和配置管理,在 ZooKeeper 中数据的组织由下图所示:
首先,所有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
向调用者问好。
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-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服务。
public class ProviderBootstrap { public static void main(String[] args) throws Exception { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ProviderConfiguration.class); context.start(); System.in.read(); }}
服务启动端的的 main
方法,将会看到下面的输出,代表服务端启动成功,并在注册中心( ZooKeeper Registry)注册上了 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 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 0.2&通用=假接口=com.alibaba.dubbo.samples.api.GreetingService&方法= sayHello的&PID = 12938&侧=提供商时间戳=1533264631849
5、客户端:引用服务
通过 @Reference
来在客户端声明服务的引用,运行时将会通过该引用发起全程调用,而服务的目标地址将会从 ZooKeeper 的 provider
节点下查询。
@Component("annotatedConsumer")public class GreetingServiceConsumer { @Reference private 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-consumer dubbo.registry.address=zookeeper://$DOCKER_HOST:2181 dubbo.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✓=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
#说明:
a. 注册:消费者://192.168.99.1/...& category= consumers &:消费者向 ZooKeeper 注册自己的信息,并放在 consumers
节点下
b. 订阅:消费者://192.168.99.1/...& 类别=提供商,配置器,路由器:消费者同时向动物园管理员订阅了 providers
、 configurators
、 routers
节点,其中 configurations
与多宝配置相关, routers
与路由规则相关,值得注意的英文 providers
节点的订阅,当有新的服务提供方加入后,由于订阅的关系,新的地址列表会推送给订阅方,服务的消费者也因此动态感知到了地址列表的变化。
通过 ZooKeeper 管理终端观察服务提供方的注册信息:
$ 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= provider,configurators,routers&default。超时= 3000&达博= 2.6.2&接口= com.alibaba.dubbo.samples.api.GreetingService&方法=sayHello的&PID =82406&侧=消费者的时间戳=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
今日推文
点击下方图片即可阅读
» 阿里巴巴发布 Nacos v0.1.0版本,回顾自研 10 年路
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK