初识Dubbo

目录

Dubbo能够做什么

Dubbo架构图

入门案例

在Dubbo中引入注册中心

关于Dubbo Container

Dubbo多协议支持

Dubbo多注册中心的支持

Dubbo启动检查配置

Dubbo集群的访问


Dubbo能够做什么

  1. 远程调用;
  2. 目录服务;
  3. 集群;
  4. 监控;

Dubbo架构图

官网上也已经说的很清楚了:

dubbo-architucture

节点角色说明

节点角色说明
Provider暴露服务的服务提供方
Consumer调用远程服务的服务消费方
Registry服务注册与发现的注册中心
Monitor统计服务的调用次数和调用时间的监控中心
Container服务运行容器

调用关系说明

  1. 服务容器负责启动,加载,运行服务提供者。
  2. 服务提供者在启动时,向注册中心注册自己提供的服务。
  3. 服务消费者在启动时,向注册中心订阅自己所需的服务。
  4. 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
  5. 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
  6. 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。

入门案例

首先用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(具体可参看:https://blog.csdn.net/Dongguabai/article/details/83589191)那就需要服务端发布服务,客户端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&timestamp\=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&timestamp\=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&timestamp\=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&timestamp=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&timestamp=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

https://blog.csdn.net/Dongguabai/article/details/83547212

dubbox 修改了kryo序列问题 at com.alibaba.dubbo.remoting.exchange.support.DefaultFuture.returnFromResponse(DefaultFuture.java:190) at com.alibaba.dubbo.remoting.exchange.support.DefaultFuture.get(DefaultFuture.java:110) at com.alibaba.dubbo.remoting.exchange.support.DefaultFuture.get(DefaultFuture.java:84) at com.alibaba.dubbo.rpc.protocol.dubbo.DubboInvoker.doInvoke(DubboInvoker.java:96) at com.alibaba.dubbo.rpc.protocol.AbstractInvoker.invoke(AbstractInvoker.java:144) at com.alibaba.dubbo.rpc.listener.ListenerInvokerWrapper.invoke(ListenerInvokerWrapper.java:74) at com.alibaba.dubbo.monitor.support.MonitorFilter.invoke(MonitorFilter.java:75) at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91) at com.alibaba.dubbo.rpc.protocol.dubbo.filter.FutureFilter.invoke(FutureFilter.java:53) at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91) at com.alibaba.dubbo.rpc.filter.ConsumerContextFilter.invoke(ConsumerContextFilter.java:48) at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91) at com.alibaba.dubbo.rpc.protocol.InvokerWrapper.invoke(InvokerWrapper.java:53) at com.alibaba.dubbo.rpc.cluster.support.FailoverClusterInvoker.doInvoke(FailoverClusterInvoker.java:77) at com.alibaba.dubbo.rpc.cluster.support.AbstractClusterInvoker.invoke(AbstractClusterInvoker.java:227) at com.alibaba.dubbo.rpc.cluster.support.wrapper.MockClusterInvoker.invoke(MockClusterInvoker.java:72) at com.alibaba.dubbo.rpc.proxy.InvokerInvocationHandler.invoke(InvokerInvocationHandler.java:52) at com.alibaba.dubbo.common.bytecode.proxy1.test(proxy1.java)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值