目录
Dubbo能够做什么
Dubbo架构图
入门案例
在Dubbo中引入注册中心
关于Dubbo Container
Dubbo多协议支持
Dubbo多注册中心的支持
Dubbo启动检查配置
Dubbo集群的访问
Dubbo能够做什么
- 远程调用;
- 目录服务;
- 集群;
- 监控;
Dubbo架构图
官网上也已经说的很清楚了:
节点角色说明
节点 | 角色说明 |
| 暴露服务的服务提供方 |
| 调用远程服务的服务消费方 |
| 服务注册与发现的注册中心 |
| 统计服务的调用次数和调用时间的监控中心 |
| 服务运行容器 |
调用关系说明
- 服务容器负责启动,加载,运行服务提供者。
- 服务提供者在启动时,向注册中心注册自己提供的服务。
- 服务消费者在启动时,向注册中心订阅自己所需的服务。
- 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
- 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
- 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。
入门案例
首先用idea分别创建一个服务端和客户端的工程:
再在服务端工程中创建两个模块server-api和server-provider,api模块主要是对外提供的api,provider是对这些api的一些实现:
删除多余的src目录:
在server-api模块中定义一个接口:
在server-provider中需要实现IHello接口,这个时候在server-provider模块中需要依赖server-api:
、
在server-provider中具体实现IHello:
将dubboserver安装到本地:
在dubboclient客户端中引入server-api的依赖:
客户端获取了依赖后就可以直接使用了:
目前架构图如下:
目前Client只拿到了IHello接口,但是实现类在server-provider中。如果是使用的比如RMI那就需要服务端发布服务,客户端looking获取服务的代理对象然后进行调用。使用Dubbo也是一样的,在server-provider中依赖Dubbo的jar包:
Dubbo是默认基于Spring进行扩展的,所以在依赖了Dubob的jar之后可以看到同时也依赖了Spring的包(后续可以exclusion):
所以我们可以在这里引用Spring的配置文件来对服务进行发布。
server-provider中新增resource作为资源目录:
在resource中新建xml文件:dubbo-server.xml:
<?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">
</beans>
接下来需要基于Dubbo固定的配置完成服务的发布:
<?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">
<!--提供方信息,定义当前项目对外发布的一些内容信息,name尽量保证唯一(这里没有强制唯一),owner表示维护者-->
<dubbo:application name="dubbo-server" owner="dongguabai"/>
<!--注册中心-Dongguabai,N/A表示不需要依赖注册中心-->
<dubbo:registry address="N/A"/>
<!--发布的协议名称(默认dubbo协议)、端口-->
<dubbo:protocol port="20880" name="dubbo"/>
<!--当前创建服务的接口地址;ref指明实现;-->
<dubbo:service interface="dongguabai.dubbo.IHello" ref="helloService"/>
<!--实现Bean-->
<bean id="helloService" class="dongguabai.dubbo.HelloImpl"/>
</beans>
编写一个简单的启动类:
package dongguabai.dubbo;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.io.IOException;
/**
* @author Dongguabai
* @date 2018/11/15 9:52
*/
public class App {
public static void main(String[] args) throws IOException {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("dubbo-server.xml");
context.start();
System.in.read();
}
}
从控制台中可以看到已经发布了一个本地服务:
在消费端如果需要使用Dubbo服务的话,需要引入相关依赖:
同时也需要新增resource作为资源目录:
增加dubbo-cli.xml:
<?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">
<!--提供方信息,定义当前项目对外发布的一些内容信息,name尽量保证唯一(这里没有强制唯一),owner表示维护者-->
<dubbo:application name="dubbo-cli" owner="dongguabai"/>
<!--注册中心-Dongguabai,N/A表示不需要依赖注册中心-->
<dubbo:registry address="N/A"/>
<dubbo:reference interface="dongguabai.dubbo.IHello" id="helloService" url="dubbo://172.30.57.63:20880/dongguabai.dubbo.IHello"/>
</beans>
在dubboclient中远程调用服务:
package dongguabai.dubbo;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.io.IOException;
/**
* @author Dongguabai
* @date 2018/11/15 9:52
*/
public class App {
public static void main(String[] args) throws IOException {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("dubbo-cli.xml");
//获取IHello的远程代理对象
IHello helloService = (IHello) context.getBean("helloService");
String s = helloService.sayHello("张三");
System.out.println(s);
System.in.read();
}
}
运行结果,基于Netty完成远程通信,基于TCP协议完成数据交互,调用成功:
虽然调用成功,但是现有还是有点问题,server和client是通过url去连接的,没有使用注册中心,相当于还是点对点,也没有办法对地址进行管理。
在Dubbo中引入注册中心
Dubbo是支持注册中心的:
官方推荐使用ZooKeeper为注册中心。
在duboserver中引入相关的ZooKeeper的依赖和ZKClient依赖(Dubbo默认使用ZKClient):
修改dubboserver的配置文件,加入注册中心中发布服务:
再启动dubboserver发布服务,进入ZooKeeper客户端:
在dubboclient中添加相应的依赖:
修改dubboclient的配置文件,加入注册中心地址:
<?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">
<!--提供方信息,定义当前项目对外发布的一些内容信息,name尽量保证唯一(这里没有强制唯一),owner表示维护者-->
<dubbo:application name="dubbo-server" owner="dongguabai"/>
<!--注册中心-Dongguabai,N/A表示不需要依赖注册中心-->
<dubbo:registry address="zookeeper://192.168.220.137:2181"/>
<!--当前创建服务的接口地址;ref指明实现;-->
<dubbo:reference interface="dongguabai.dubbo.IHello" id="helloService"/>
</beans>
启动dubboclient:
程序运行成功。
进入ZooKeeper客户端:
Dubbo就是基于ZK的节点来管理协议地址。生成了一个叫/dubbo的namespace。在/dubbo下就是interface。在interface下有四个子节点consumers, configurators, routers, providers。 consumers表示当前正在消费的消费端信息,比如现在dubboclient正在调用这个服务,这时候会在consumers上注册一个地址,可以在监控平台上看到这样一个地址;configurators是配置;routers是路由;providers是提供服务的路径:
其实这就是一个协议地址,Dubbo是基于url驱动的,所以能够看到这个地址后面带了很多内容。我们会通过url将版本信息传过去,这样消费端就知道去调用哪个版本。
在dubboserver停止后,providers的节点内容也消失了:
启动dubboserver,让消费端一直消费,这时候可以看看consumers的节点内容:
那么是不是客户端每次访问都需要访问ZooKeeper呢,不是的,在Dubbo中会缓存地址,比如我们可以在dubboclient的配置文件配置缓存文件:
这个文件中会缓存相应的服务信息,可以看到在H盘下生成了这个文件:
文件内存储了相应的信息:
#Dubbo Registry Cache
#Thu Nov 15 20:58:42 CST 2018
dongguabai.dubbo.IHello=empty\://172.30.57.63/dongguabai.dubbo.IHello?application\=dubbo-server&category\=configurators&dubbo\=2.5.3&interface\=dongguabai.dubbo.IHello&methods\=sayHello&owner\=dongguabai&pid\=19832&revision\=1.0-SNAPSHOT&side\=consumer×tamp\=1542286721769 empty\://172.30.57.63/dongguabai.dubbo.IHello?application\=dubbo-server&category\=routers&dubbo\=2.5.3&interface\=dongguabai.dubbo.IHello&methods\=sayHello&owner\=dongguabai&pid\=19832&revision\=1.0-SNAPSHOT&side\=consumer×tamp\=1542286721769 dubbo\://172.30.57.63\:20880/dongguabai.dubbo.IHello?anyhost\=true&application\=dubbo-server&dubbo\=2.5.3&interface\=dongguabai.dubbo.IHello&methods\=sayHello&owner\=dongguabai&pid\=19032&side\=provider×tamp\=1542286472249
ZK宕掉后就可以从文件中读取内容,Dubbo有一个定时任务去更新缓存。
关于Dubbo Container
Dubbo的启动是不需要依赖于外部的容器(比如Tomcat,Jetty)的,Dubbo提供了一种基于Main的启动:
public class Main {
public static void main(String[] args) throws IOException {
//默认情况下会使用spring容器来启动服务
com.alibaba.dubbo.container.Main.main(
new String[]{"spring","log4j"});
}
}
Dubbo支持Spring、Jetty、Log4j容器,默认情况下会基于Spring容器启动。其实这个Main.main(args)和之前的示例中基于ClassPathXmlApplicationContext启动一样。
main()方法的逻辑也很简单:
会循环args参数往List<Container>中添加Container,直接看看SpringContainer:
也是基于ClassPathXmlApplicationContext来的:
可以看到默认的配置文件的路径是classpath下的META-INF/spring/下,在resource下把这个路径和文件创建好:
接下来启动Dubbo:
可以看到启动成功:
为了方便,增加一个日志配置文件:
log4j.rootLogger=info, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
Dubbo多协议支持
Dubbo能够支持很多种协议,比如RMI,Hessian、WebService、Http、Thrift和默认的Dubbo协议(基于NIO)。支持众多的协议能够让Dubbo平缓的迁移实现服务治理,不需要修改原本的协议服务;也可以让我们针对特定的接口使用特定的协议。
接下来演示指定Hessian协议。
在dubboserver中指定protocol为hessian:
引入Hessian相关的依赖(Hessian是基于Http的一种协议,所以需要Servlet和Servlet容器):
启动dubboserver:
再看看ZooKeeper客户端:
dubboclient想要调用这个服务的话也要添加相应的依赖:
在配置文件中指定protocl为hessian,这时候通信协议是基于hessian来通信。运行dubboclient调用dubboserver,调用成功:
Dubbo还可以针对不同的服务使用不同的协议。
这里在dubboserver中再定义一个接口:
和实现类:
再配置文件中加入相应的配置:
也就是现在在两个不同的接口对应不同的协议,将dubboserver发布,在控制台中可以看到发布了一个基于Dubbo协议和一个基于Hessian协议的服务:
进入ZooKeeper客户端:
其实主要是协议头不一样。
因为新增了服务接口,将dubboserver重新发布:
客户端Reimport即可。
修改客户端配置文件:
运行dubboclient调用dubboserver:
package dongguabai.dubbo;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.io.IOException;
/**
* @author Dongguabai
* @date 2018/11/15 9:52
*/
public class App {
public static void main(String[] args) throws IOException {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("dubbo-cli.xml");
//获取IHello的远程代理对象
IHello helloService = (IHello) context.getBean("helloService");
String s = helloService.sayHello("张三");
IProtocol protocolService = (IProtocol) context.getBean("protocolService");
System.out.println("调用helloService::"+s);
System.out.println("调用protocolService::"+protocolService.sayGood("李四"));
System.in.read();
}
}
控制台出现了异常:
H:\dev\Java\jdk1.8.0_65\bin\java "-javaagent:H:\idea\IntelliJ IDEA 2017.1.5\lib\idea_rt.jar=9576:H:\idea\IntelliJ IDEA 2017.1.5\bin" -Dfile.encoding=UTF-8 -classpath H:\dev\Java\jdk1.8.0_65\jre\lib\charsets.jar;H:\dev\Java\jdk1.8.0_65\jre\lib\deploy.jar;H:\dev\Java\jdk1.8.0_65\jre\lib\ext\access-bridge-64.jar;H:\dev\Java\jdk1.8.0_65\jre\lib\ext\cldrdata.jar;H:\dev\Java\jdk1.8.0_65\jre\lib\ext\dnsns.jar;H:\dev\Java\jdk1.8.0_65\jre\lib\ext\jaccess.jar;H:\dev\Java\jdk1.8.0_65\jre\lib\ext\jfxrt.jar;H:\dev\Java\jdk1.8.0_65\jre\lib\ext\localedata.jar;H:\dev\Java\jdk1.8.0_65\jre\lib\ext\nashorn.jar;H:\dev\Java\jdk1.8.0_65\jre\lib\ext\sunec.jar;H:\dev\Java\jdk1.8.0_65\jre\lib\ext\sunjce_provider.jar;H:\dev\Java\jdk1.8.0_65\jre\lib\ext\sunmscapi.jar;H:\dev\Java\jdk1.8.0_65\jre\lib\ext\sunpkcs11.jar;H:\dev\Java\jdk1.8.0_65\jre\lib\ext\zipfs.jar;H:\dev\Java\jdk1.8.0_65\jre\lib\javaws.jar;H:\dev\Java\jdk1.8.0_65\jre\lib\jce.jar;H:\dev\Java\jdk1.8.0_65\jre\lib\jfr.jar;H:\dev\Java\jdk1.8.0_65\jre\lib\jfxswt.jar;H:\dev\Java\jdk1.8.0_65\jre\lib\jsse.jar;H:\dev\Java\jdk1.8.0_65\jre\lib\management-agent.jar;H:\dev\Java\jdk1.8.0_65\jre\lib\plugin.jar;H:\dev\Java\jdk1.8.0_65\jre\lib\resources.jar;H:\dev\Java\jdk1.8.0_65\jre\lib\rt.jar;H:\idea_demo1\dubboclient\target\classes;H:\maven\repository\dongguabai\dubbo\server-api\1.0-SNAPSHOT\server-api-1.0-SNAPSHOT.jar;H:\maven\repository\com\alibaba\dubbo\2.5.3\dubbo-2.5.3.jar;H:\maven\repository\org\springframework\spring\2.5.6.SEC03\spring-2.5.6.SEC03.jar;H:\maven\repository\commons-logging\commons-logging\1.1.1\commons-logging-1.1.1.jar;H:\maven\repository\org\javassist\javassist\3.15.0-GA\javassist-3.15.0-GA.jar;H:\maven\repository\org\jboss\netty\netty\3.2.5.Final\netty-3.2.5.Final.jar;H:\maven\repository\org\apache\zookeeper\zookeeper\3.4.10\zookeeper-3.4.10.jar;H:\maven\repository\org\slf4j\slf4j-api\1.6.1\slf4j-api-1.6.1.jar;H:\maven\repository\org\slf4j\slf4j-log4j12\1.6.1\slf4j-log4j12-1.6.1.jar;H:\maven\repository\log4j\log4j\1.2.16\log4j-1.2.16.jar;H:\maven\repository\jline\jline\0.9.94\jline-0.9.94.jar;H:\maven\repository\io\netty\netty\3.10.5.Final\netty-3.10.5.Final.jar;H:\maven\repository\com\101tec\zkclient\0.10\zkclient-0.10.jar;H:\maven\repository\com\caucho\hessian\4.0.38\hessian-4.0.38.jar;H:\maven\repository\javax\servlet\servlet-api\2.5\servlet-api-2.5.jar;H:\maven\repository\org\mortbay\jetty\jetty\6.1.26\jetty-6.1.26.jar;H:\maven\repository\org\mortbay\jetty\jetty-util\6.1.26\jetty-util-6.1.26.jar;H:\maven\repository\org\mortbay\jetty\servlet-api\2.5-20081211\servlet-api-2.5-20081211.jar dongguabai.dubbo.App
log4j:WARN No appenders could be found for logger (org.springframework.context.support.ClassPathXmlApplicationContext).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'helloService': FactoryBean threw exception on object creation; nested exception is java.lang.IllegalStateException: Failed to check the status of the service dongguabai.dubbo.IHello. No provider available for the service dongguabai.dubbo.IHello from the url zookeeper://192.168.220.137:2181/com.alibaba.dubbo.registry.RegistryService?application=dubbo-server&dubbo=2.5.3&interface=dongguabai.dubbo.IHello&methods=sayHello&owner=dongguabai&pid=18416&protocol=dubbo&revision=1.0-SNAPSHOT&side=consumer×tamp=1542341313723 to the consumer 172.30.57.63 use dubbo version 2.5.3
at org.springframework.beans.factory.support.FactoryBeanRegistrySupport$1.run(FactoryBeanRegistrySupport.java:127)
at java.security.AccessController.doPrivileged(Native Method)
at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:116)
at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.getObjectFromFactoryBean(FactoryBeanRegistrySupport.java:91)
at org.springframework.beans.factory.support.AbstractBeanFactory.getObjectForBeanInstance(AbstractBeanFactory.java:1288)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:217)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:185)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:164)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:880)
at dongguabai.dubbo.App.main(App.java:15)
Caused by: java.lang.IllegalStateException: Failed to check the status of the service dongguabai.dubbo.IHello. No provider available for the service dongguabai.dubbo.IHello from the url zookeeper://192.168.220.137:2181/com.alibaba.dubbo.registry.RegistryService?application=dubbo-server&dubbo=2.5.3&interface=dongguabai.dubbo.IHello&methods=sayHello&owner=dongguabai&pid=18416&protocol=dubbo&revision=1.0-SNAPSHOT&side=consumer×tamp=1542341313723 to the consumer 172.30.57.63 use dubbo version 2.5.3
at com.alibaba.dubbo.config.ReferenceConfig.createProxy(ReferenceConfig.java:420)
at com.alibaba.dubbo.config.ReferenceConfig.init(ReferenceConfig.java:300)
at com.alibaba.dubbo.config.ReferenceConfig.get(ReferenceConfig.java:138)
at com.alibaba.dubbo.config.spring.ReferenceBean.getObject(ReferenceBean.java:65)
at org.springframework.beans.factory.support.FactoryBeanRegistrySupport$1.run(FactoryBeanRegistrySupport.java:121)
... 9 more
Process finished with exit code 1
显示协议版本不对,原来是两个服务的协议写反了,重新修改后再调用:
Dubbo还可以让一个接口支持两种协议。
在dubboserver配置文件中(其实Dubbo就是使用一个for循环):
再来启动dubboserver,出现了异常:
H:\dev\Java\jdk1.8.0_65\bin\java "-javaagent:H:\idea\IntelliJ IDEA 2017.1.5\lib\idea_rt.jar=9888:H:\idea\IntelliJ IDEA 2017.1.5\bin" -Dfile.encoding=UTF-8 -classpath H:\dev\Java\jdk1.8.0_65\jre\lib\charsets.jar;H:\dev\Java\jdk1.8.0_65\jre\lib\deploy.jar;H:\dev\Java\jdk1.8.0_65\jre\lib\ext\access-bridge-64.jar;H:\dev\Java\jdk1.8.0_65\jre\lib\ext\cldrdata.jar;H:\dev\Java\jdk1.8.0_65\jre\lib\ext\dnsns.jar;H:\dev\Java\jdk1.8.0_65\jre\lib\ext\jaccess.jar;H:\dev\Java\jdk1.8.0_65\jre\lib\ext\jfxrt.jar;H:\dev\Java\jdk1.8.0_65\jre\lib\ext\localedata.jar;H:\dev\Java\jdk1.8.0_65\jre\lib\ext\nashorn.jar;H:\dev\Java\jdk1.8.0_65\jre\lib\ext\sunec.jar;H:\dev\Java\jdk1.8.0_65\jre\lib\ext\sunjce_provider.jar;H:\dev\Java\jdk1.8.0_65\jre\lib\ext\sunmscapi.jar;H:\dev\Java\jdk1.8.0_65\jre\lib\ext\sunpkcs11.jar;H:\dev\Java\jdk1.8.0_65\jre\lib\ext\zipfs.jar;H:\dev\Java\jdk1.8.0_65\jre\lib\javaws.jar;H:\dev\Java\jdk1.8.0_65\jre\lib\jce.jar;H:\dev\Java\jdk1.8.0_65\jre\lib\jfr.jar;H:\dev\Java\jdk1.8.0_65\jre\lib\jfxswt.jar;H:\dev\Java\jdk1.8.0_65\jre\lib\jsse.jar;H:\dev\Java\jdk1.8.0_65\jre\lib\management-agent.jar;H:\dev\Java\jdk1.8.0_65\jre\lib\plugin.jar;H:\dev\Java\jdk1.8.0_65\jre\lib\resources.jar;H:\dev\Java\jdk1.8.0_65\jre\lib\rt.jar;H:\idea_demo1\dubboserver\server-provider\target\classes;H:\idea_demo1\dubboserver\server-api\target\classes;H:\maven\repository\com\alibaba\dubbo\2.5.3\dubbo-2.5.3.jar;H:\maven\repository\org\springframework\spring\2.5.6.SEC03\spring-2.5.6.SEC03.jar;H:\maven\repository\commons-logging\commons-logging\1.1.1\commons-logging-1.1.1.jar;H:\maven\repository\org\javassist\javassist\3.15.0-GA\javassist-3.15.0-GA.jar;H:\maven\repository\org\jboss\netty\netty\3.2.5.Final\netty-3.2.5.Final.jar;H:\maven\repository\org\apache\zookeeper\zookeeper\3.4.10\zookeeper-3.4.10.jar;H:\maven\repository\org\slf4j\slf4j-api\1.6.1\slf4j-api-1.6.1.jar;H:\maven\repository\org\slf4j\slf4j-log4j12\1.6.1\slf4j-log4j12-1.6.1.jar;H:\maven\repository\log4j\log4j\1.2.16\log4j-1.2.16.jar;H:\maven\repository\jline\jline\0.9.94\jline-0.9.94.jar;H:\maven\repository\io\netty\netty\3.10.5.Final\netty-3.10.5.Final.jar;H:\maven\repository\com\101tec\zkclient\0.10\zkclient-0.10.jar;H:\maven\repository\com\caucho\hessian\4.0.38\hessian-4.0.38.jar;H:\maven\repository\javax\servlet\servlet-api\2.5\servlet-api-2.5.jar;H:\maven\repository\org\mortbay\jetty\jetty\6.1.26\jetty-6.1.26.jar;H:\maven\repository\org\mortbay\jetty\jetty-util\6.1.26\jetty-util-6.1.26.jar;H:\maven\repository\org\mortbay\jetty\servlet-api\2.5-20081211\servlet-api-2.5-20081211.jar dongguabai.dubbo.MyMain
log4j:WARN No appenders could be found for logger (com.alibaba.dubbo.common.logger.LoggerFactory).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dongguabai.dubbo.IHello': Cannot resolve reference to bean 'hessian' while setting bean property 'protocols' with key [0]; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'hessian' is defined
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:275)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:104)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveManagedList(BeanDefinitionValueResolver.java:287)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:126)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1245)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1010)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:472)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory$1.run(AbstractAutowireCapableBeanFactory.java:409)
at java.security.AccessController.doPrivileged(Native Method)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:380)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:264)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:261)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:185)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:164)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:308)
at org.springframework.context.support.AbstractApplicationContext.getBeansOfType(AbstractApplicationContext.java:947)
at org.springframework.context.support.AbstractApplicationContext.registerListeners(AbstractApplicationContext.java:701)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:377)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:93)
at com.alibaba.dubbo.container.spring.SpringContainer.start(SpringContainer.java:50)
at com.alibaba.dubbo.container.Main.main(Main.java:80)
at dongguabai.dubbo.MyMain.main(MyMain.java:12)
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'hessian' is defined
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:387)
at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:971)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:246)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:185)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:164)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:269)
... 23 more
Process finished with exit code 1
这样使用的话,就必须要声明协议,在配置文件中添加:
再来发布服务:
在ZooKeeper客户端中,一个接口发布了两个地址,可以看到两个不同的协议:
在客户端中进行调用。修改客户端配置文件:
调用:
调用成功:
Dubbo多注册中心的支持
也就是说在客户端或者服务端可以配置多个注册中心。
修改subboserver配置文件:
服务接口指定注册中心,这样对应的服务只会发布到指定的注册中心。这样的好处就是比如有些网站需要中英文支持,我们可以中文的服务发布到中文的ZK,英文的服务发布到英文的ZK。
启动服务:
注意这两个不同的注册中心就不是一个集群了。
Dubbo启动检查配置
有时候Dubbo服务可能会出现循环依赖的情况,即Client本身也是一个Server。比如商品和用户服务,商品服务可能需要调用用户服务,用户服务也会需要调用商品服务。这就存在了相互调用,也就是循环依赖问题。在启动客户端的时候如果没有服务会出现异常:
在客户端可以配置check="false":
这样客户端就会正常启动了:
这样可以解决循环依赖的问题。
Dubbo集群的访问
之前介绍过了Dubbo可以解决负载均衡的问题,即我们可以对Server端进行水平扩容。即在dubboserver中发布多个服务节点。Dubbo会通过负载均衡算法完成对服务的路由。
这里简单演示一下,定义两个新的配置文件dubbo-cluser1.xml和dubbo-cluser2.xml:
<?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">
<!--提供方信息,定义当前项目对外发布的一些内容信息,name尽量保证唯一(这里没有强制唯一),owner表示维护者-->
<dubbo:application name="dubbo-server" owner="dongguabai"/>
<!--注册中心-Dongguabai,N/A表示不需要依赖注册中心-->
<!--注意要声明id-->
<dubbo:registry id="zk1" address="zookeeper://192.168.220.137:2181"/>
<!--发布的协议名称(默认dubbo协议)、端口-->
<dubbo:protocol port="20881" name="dubbo"/>
<!--当前创建服务的接口地址;ref指明实现;-->
<dubbo:service interface="dongguabai.dubbo.IHello" ref="helloService" protocol="dubbo" registry="zk1"/>
<!--当前创建服务的接口地址;ref指明实现;-->
<dubbo:service interface="dongguabai.dubbo.IProtocol" ref="protocolService" protocol="dubbo" registry="zk1"/>
<!--实现Bean-->
<bean id="helloService" class="dongguabai.dubbo.HelloImpl"/>
<!--实现Bean-->
<bean id="protocolService" class="dongguabai.dubbo.ProtocolImpl"/>
</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">
<!--提供方信息,定义当前项目对外发布的一些内容信息,name尽量保证唯一(这里没有强制唯一),owner表示维护者-->
<dubbo:application name="dubbo-server" owner="dongguabai"/>
<!--注册中心-Dongguabai,N/A表示不需要依赖注册中心-->
<!--注意要声明id-->
<dubbo:registry id="zk1" address="zookeeper://192.168.220.137:2181"/>
<!--发布的协议名称(默认dubbo协议)、端口-->
<dubbo:protocol port="20882" name="dubbo"/>
<!--当前创建服务的接口地址;ref指明实现;-->
<dubbo:service interface="dongguabai.dubbo.IHello" ref="helloService" protocol="dubbo" registry="zk1"/>
<!--当前创建服务的接口地址;ref指明实现;-->
<dubbo:service interface="dongguabai.dubbo.IProtocol" ref="protocolService" protocol="dubbo" registry="zk1"/>
<!--实现Bean-->
<bean id="helloService" class="dongguabai.dubbo.HelloImpl"/>
<!--实现Bean-->
<bean id="protocolService" class="dongguabai.dubbo.ProtocolImpl"/>
</beans>
新建两个启动类App1和App2:
分别启动App1和App2,然后在ZooKeeper客户端发现同一个服务存在了两个地址,只是端口不同:
客户端获取两个地址就能够使用负载均衡的机制完成负载了。
为了看出负载效果,新建一个IHello实现类:
在cluster2中使用HelloImpl2:
在客户端中循环调用:
控制台输出:
可以看到调用的地址会有变化,默认情况Dubbo是基于随机负载。
在Dubbo中定义了一个LoadBalance接口:
会把从远程服务端拿过来的List进行选取。默认实现是RandomLoadBalance:
/*
* Copyright 1999-2011 Alibaba Group.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.rpc.cluster.loadbalance;
import java.util.List;
import java.util.Random;
import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.rpc.Invocation;
import com.alibaba.dubbo.rpc.Invoker;
/**
* random load balance.
*
* @author qianlei
* @author william.liangf
*/
public class RandomLoadBalance extends AbstractLoadBalance {
public static final String NAME = "random";
private final Random random = new Random();
protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) {
int length = invokers.size(); // 总个数
int totalWeight = 0; // 总权重
boolean sameWeight = true; // 权重是否都一样
for (int i = 0; i < length; i++) {
int weight = getWeight(invokers.get(i), invocation);
totalWeight += weight; // 累计总权重
if (sameWeight && i > 0
&& weight != getWeight(invokers.get(i - 1), invocation)) {
sameWeight = false; // 计算所有权重是否一样
}
}
if (totalWeight > 0 && ! sameWeight) {
// 如果权重不相同且权重大于0则按总权重数随机
int offset = random.nextInt(totalWeight);
// 并确定随机值落在哪个片断上
for (int i = 0; i < length; i++) {
offset -= getWeight(invokers.get(i), invocation);
if (offset < 0) {
return invokers.get(i);
}
}
}
// 如果权重相同或权重为0则均等随机
return invokers.get(random.nextInt(length));
}
}
这里会根据权重进行计算,也就是说我们可以根据不同的地址设置不同的权重。最后得到随机的结果值后返回调用服务。
Demo源码地址:https://github.com/Dongguabaiwuyu/DubboDemo
参考资料:
http://dubbo.apache.org/zh-cn/docs/user/preface/architecture.html