Dubbo介绍、Zookeeper注册中心实例
SOA服务治理
面向服务的架构(Service-OrientedArchitecture,SOA)自提出到被普遍认可和接受,再到目前应用普及和成熟已有近20年时间,在领域的应用经历了WebService接口、企业服务总线(ESB)、服务管控等不同发展阶段。目前云计算、流程银行等新概念又给了SOA更广泛的发展空间。国际权威机构Gartner认为,SOA是大型企业信息现代化的根本。
RPC需要解决的问题:
- 通讯问题 : 主要是通过在客户端和服务器之间建立TCP连接,远程过程调用的所有交换的数据都在这个连接里传输。连接可以是按需连接,调用结束后就断掉,也可以是长连接,多个远程过程调用共享同一个连接。
- 寻址问题 : A服务器上的应用怎么告诉底层的RPC框架,如何连接到B服务器(如主机或IP地址)以及特定的端口,方法的名称名称是什么,这样才能完成调用。比如基于Web服务协议栈的RPC,就要提供一个endpoint URI,或者是从UDDI服务上查找。如果是RMI调用的话,还需要一个RMI Registry来注册服务的地址。
- 序列化 与 反序列化 : 当A服务器上的应用发起远程过程调用时,方法的参数需要通过底层的网络协议如TCP传递到B服务器,由于网络协议是基于二进制的,内存中的参数的值要序列化成二进制的形式,也就是序列化(Serialize)或编组(marshal),通过寻址和传输将序列化的二进制发送给B服务器。
同理,B服务器接收参数要将参数反序列化。B服务器应用调用自己的方法处理后返回的结果也要序列化给A服务器,A服务器接收也要经过反序列化的过程。
Dubbo是什么?
Dubbo是一个分布式服务框架,致力于提供高性能和透明化的**RPC远程服务调用方案**,以及**SOA服务治理方案**。
简单的说,dubbo就是个服务框架,如果没有分布式的需求,其实是不需要用的,只有在分布式的时候,才有dubbo这样的分布式服务框架的需求,并且本质上是个服务调用的东东,说白了就是个远程服务调用的分布式框架(告别Web Service模式中的WSdl,以服务者与消费者的方式在dubbo上注册)。
其核心部分包含
1. 远程通讯:
提供对多种基于长连接的NIO框架抽象封装,包括多种线程模型,序列化,以及“请求-响应”模式的信息交换方式。
2. 集群容错:
提供基于接口方法的透明远程过程调用,包括多协议支持,以及软负载均衡,失败容错,地址路由,动态配置等集群支持。
3. 自动发现
基于注册中心目录服务,使服务消费方能动态的查找服务提供方,使地址透明,使服务提供方可以平滑增加或减少机器。
Dubbo能做什么?
- 透明化的远程方法调用,就像调用本地方法一样调用远程方法,只需简单配置,没有任何API侵入。
- 软负载均衡及容错机制,可在内网替代F5等硬件负载均衡器,降低成本,减少单点。
- 服务自动注册与发现,不再需要写死服务提供方地址,注册中心基于接口名查询服务提供者的IP地址,并且能够平滑添加或删除服务提供者。
Dubbo架构
- Provider: 暴露服务的服务提供方。
- Consumer: 调用远程服务的服务消费方。
- Registry: 服务注册与发现的注册中心。
- Monitor: 统计服务的调用次数和调用时间的监控中心。
调用流程
- 0.服务容器负责启动,加载,运行服务提供者。
- 1.服务提供者在启动时,向注册中心注册自己提供的服务。
- 2.服务消费者在启动时,向注册中心订阅自己所需的服务。
- 3.注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
- 4.服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
- 5.服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心
Zookeeper用作注册中心的原理
Dubbo的Provider,Consumer在启动时都会创建一个注册中心,注册中心可以选择Zookeeper,Redis。常用的是Zookeeper,我们这篇博客主要讲的就是Dubbo与Zookeeper的注册交互过程。
Dubbo里默认使用zkclient来操作zookeeper服务器,其对zookeeper原始客户单做了一定的封装,操作zookeeper时能便捷一些,比如不需要手动处理session超时,不需要重复注册watcher等等。
简单来讲,zookeeper可以充当一个服务注册表(Service Registry),让多个服务提供者形成一个集群,让服务消费者通过服务注册表获取具体的服务访问地址(ip+端口)去访问具体的服务提供者。如下图所示:
具体来说,zookeeper就是个分布式文件系统,每当一个服务提供者部署后都要将自己的服务注册到zookeeper的某一路径上: /\{service\}/\{version\}/\{ip:port\}, 比如我们的HelloWorldService部署到两台机器,那么zookeeper上就会创建两条目录:分别为/HelloWorldService/1.0.0/100.19.20.01:16888 /HelloWorldService/1.0.0/100.19.20.02:16888。
在zookeeper中,进行服务注册,实际上就是在zookeeper中创建了一个znode节点,该节点存储了该服务的IP、端口、调用方式(协议、序列化方式)等。该节点承担着最重要的职责,它由服务提供者(发布服务时)创建,以供服务消费者获取节点中的信息,从而定位到服务提供者真正网络拓扑位置以及得知如何调用。RPC服务注册、发现过程简述如下:
- 服务提供者启动时,会将其服务名称,ip地址注册到配置中心。
- 服务消费者在第一次调用服务时,会通过注册中心找到相应的服务的IP地址列表,并缓存到本地,以供后续使用。当消费者调用服务时,不会再去请求注册中心,而是直接通过负载均衡算法从IP列表中取一个服务提供者的服务器调用服务。
- 当服务提供者的某台服务器宕机或下线时,相应的ip会从服务提供者IP列表中移除。同时,注册中心会将新的服务IP地址列表发送给服务消费者机器,缓存在消费者本机。
- 当某个服务的所有服务器都下线了,那么这个服务也就下线了。
- 同样,当服务提供者的某台服务器上线时,注册中心会将新的服务IP地址列表发送给服务消费者机器,缓存在消费者本机。
- 服务提供方可以根据服务消费者的数量来作为服务下线的依据。
感知服务的下线&上线
zookeeper提供了“心跳检测”功能,它会定时向各个服务提供者发送一个请求(实际上建立的是一个 socket 长连接),如果长期没有响应,服务中心就认为该服务提供者已经“挂了”,并将其剔除,比如100.19.20.02这台机器如果宕机了,那么zookeeper上的路径就会只剩/HelloWorldService/1.0.0/100.19.20.01:16888。
服务消费者会去监听相应路径(/HelloWorldService/1.0.0),一旦路径上的数据有任务变化(增加或减少),zookeeper都会通知服务消费方服务提供者地址列表已经发生改变,从而进行更新。
更为重要的是zookeeper 与生俱来的容错容灾能力(比如leader选举),可以确保服务注册表的高可用性。
使用 zookeeper 作为注册中心时,客户端订阅服务时会向 zookeeper 注册自身;主要是方便对调用方进行统计、管理。但订阅时是否注册 client 不是必要行为,和不同的注册中心实现有关,例如使用 consul 时便没有注册。
ZooKeeper与Dubbo服务集群架构图
重试的动作包括:
- Provider向zookeeper注册自身的url,生成一个临时的znode
- Provider从Dubbo容器中退出,停止提供RPC调用。也就是移除zookeeper内自身url对应的znode
- Consumer订阅 “ /dubbo/…Service/providers” 目录的子节点,生成ChildListener
- Consumer从Dubbo容器中退出,移除之前创建的ChildListener
为什么如此设置? 主要是和zookeeper的通信机制有关的。当zookeeper的Client和Server连接断开,或者心跳超时,那么Server会将相应Client注册的临时节点删除,当然注册的Listener也相应删除。
而Provider和Consumer注册的URL就属于临时节点,当连接断开时,Dubbo注册了zookeeper的StateListener,也就是状态监听器,当Dubbo里的zookeeper Client和Server重新连接上时,将之前注册的的URL添加入这几个失败集合中,然后重新注册和订阅。
实例Dubbo分布式服务治理(zookeeper注册中心)
消费者配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<dubbo:application name="sayhello-consumer"/>
<dubbo:registry address="zookeeper://192.168.199.132:2181" />
<dubbo:reference id="sayhello" interface="com.youfan.service.SayHelloService"/>
</beans>
提供者配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<!-- 注册中心 -->
<dubbo:registry address="zookeeper://192.168.199.132:2181" />
<!-- 用dubbo协议在20880端口暴露服务 -->
<dubbo:protocol name="dubbo" port="20881"></dubbo:protocol>
<!-- 应用名 -->
<dubbo:application name="dubbo-service-sayhello"/>
<!-- 向外提供的接口以及实现类 -->
<dubbo:service interface="com.youfan.service.SayHelloService" ref="sayhelloImpl"/>
<bean id="sayhelloImpl" class="com.youfan.service.impl.SayHelloServiceImpl"/>
</beans>
在VMware中启动ookeeper:
zookeeper的conf文件目录下:
zkServer.sh start
停止:
zkServer.sh stop
状态:
zkServer.sh status
进入zookeeper中:
zkCli.sh
注意关闭防火墙:
service iptables stop
永久关闭:chkconfig iptables off 查看端口:netstat -ntlp
消费者测试代码:
public class ConsumerTest {
public static void main(String[] args) throws Exception {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
new String[]{"application-context-consumer.xml"});
context.start();
// obtain proxy object for remote invocation
SayHelloService sayHelloService = (SayHelloService) context.getBean("sayhello");
// execute remote invocation
String hello = sayHelloService.sayhello("laobai");
// show the result
System.out.println(hello);
}
}
提供者代码:
public class ProvideTest {
public static void main(String[] args) throws Exception {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
new String[] {"application-context-provide.xml"});
context.start();
// press any key to exit
System.in.read();
}
}
总结:
- Provider和Consumer向Zookeeper注册临时节点,当连接断开时删除相应的注册节点。
- Consumer订阅Providers节点的子节点,实时感知Provider的变化情况,实时同步自身的Invoker对象
还没有评论,来说两句吧...