RPC框架与Dubbo完整使用

Posted 有且仅有

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了RPC框架与Dubbo完整使用相关的知识,希望对你有一定的参考价值。

本文并不是RPC 的原理解析性文章,而是一个RPC 快速入门,还有一个完整的Java Dubbo 框架用例。

一、RPC

  1. 什么是RPC?

    RPC, Remote Procedure Call 即远程过程调用。见名知意:从远程主机调用一个过程/函数。

    RPC 的目标是:使得本程序调用其它远程主机上的函数,好像调用本程序内的函数一样简单,并且屏蔽编程语言的差异性。

    要实现上述目标首先需要设计一种通信协议,这被称为:RPC协议(RPC Protocol)

    • RPC协议 不是某一个具体的协议,而是一个类型名,代表一类用作RPC的协议。

    • RPC协议是在网络应用层协议,广义上可以跨越平台、语言进行应用间通讯(说广义是因为可以开发一个协议但只支持单个语言)。

  2. 为什么要用RPC?

    这是由系统开发到一定阶段后的强烈需求驱动的。

    1. 当我们的系统逻辑简单、用户不多、流量不大时,我们只需要一个单一应用。即此时我们用不着RPC。

    2. 随着我们的系统业务增多、访问量增大,我们会发现一台单机运行此系统已经无法应付压力。此时,我们可以将系统根据业务拆分成几个互不关联的子系统,分别部署在各自机器上,以划清逻辑并减小压力。此时,我们也可以不需要RPC,因为应用之间是互不关联的。

    3. 当我们的业务越来越多、子系统也越来越多时,我们就会发现有些功能已经不能简单划分开来或者划分不出来。此时,一种方案是将公共业务逻辑抽离出来,将之组成独立的Service应用 。而原有的、新增的应用都可以与那些独立的Service应用 交互,以此来组合完成完整的业务功能。此时可以看到,我们急需一种高效的应用程序间的通讯手段来完成这种需求。所以,RPC大显身手的时候来了!

    其实#3描述的场景也是服务化 微服务 分布式系统架构 的基础场景。即RPC框架就是实现以上结构的有力方式。

  3. 有哪些RPC框架?

    有很多实现了RPC 功能的框架,它们被称为RPC框架:有CORBARThriftDubbo 等等。它们有两类:

    • 跨语言的。
    • 单一语言的,如果你的分布式系统上的应用都是Java应用,显然我们不应该使用跨语言的RPC 来多一层抽象中转浪费效率。

    就Java 来说,其本身提供的RMI 就是一种RPC,但是其毕竟太原始,需要自己去添加很多机制才能上生产环境,所以我们得寻求成熟可用的三方框架来用。今天,就是介绍下最近使用的Dubbo 框架

二、Dubbo

  1. 什么是Dubbo?

    Dubbo 是阿里巴巴为Java 开发的RPC 框架,据网上评价来看非常不错。在Dubbo 开源后很多公司都使用其来构建自己的分布式架构。

    由于Dubbo官方文档已经把一切都说的很详细了,我就不没意思的摘抄了,放上官网地址

    今天我主要来做一个使用实例。

三、Dubbo 使用实例

官网上也有详细使用方法,那我为什么还要写个使用实例?

是因为,似乎到2012年,Dubbo 已经比较稳定的完成了所有开发,所以现在Dubbo 其实是在一个松散的维护状态下的。有些文档内容已经失效:地址无法访问,一些错误没有明确说明。所以参照官网会有一些问题,我这里就是解决了某些问题而完成的一个实例,放在这里供大家参考。

概设

建议大家先去看文档,有一个整体概念再做实例。

我的整体架构是这样的:

  • 使用Dubbo 来服务化(基于Spring)。

  • 使用Zookeeper集群 作为Dubbo服务 的注册中心 (Zookeeper简介与安装)。

  • 使用Dubbo 提供的一个JavaWeb 项目作为Dubbo服务 管理控制台。

  • 创建了一个服务提供者项目(pom父项目) :dubbo-practice-provider

  • 创建了一个服务消费者项目(pom父项目) :dubbo-practice-consumer

    另外说一点,这两个只是练习项目,实际上一个项目可以既是提供者也是消费者。

步骤

  1. 首先,要确保Zookeeper的安装和配置正确,可以直接按照我另一篇文章Zookeeper简介与安装来做。

  2. 然后,我们需要一个Dubbo服务管理控制台:

    本身这个项目的war 包,Dubbo在其文档中是给出了下载地址的,但是地址已经失效了。所以,现在只能去其GitHub地址上自己下载源码下来打包了。

    1. 使用Eclipse,用其自带的git插件下载dubbo项目整体,地址是:https://github.com/alibaba/dubbo.git

    2. 先将dubbo项目 转为Maven项目,然后单独将其中的子Maven项目dubbo-admin 导出来,这就是一个JavaWeb项目。

    3. 但是这个项目,别直接Maven打包,因为它有一些依赖问题需要修改,打开其pom.xml文件:

      <!-- 修改了两点。
          1. 原本的version是${project.parent.version},其值在pom.xml上方有配置,实际上就是2.5.4-SNAPSHOT,但是经过查看发现在MAVEN库中,Dubbo团队只更新到了2.5.3。这个2.5.4-SNAPSHOT实际上是当前我们下载的这个源码的版本,我们不想自己打包使用这个版本。所以就使用MAVEN上的2.5.3.
          2. 另一个是增加了<exclusions>spring,这是因为dubbo缺省会依赖Spring,版本为2.5.6.SEC03。但是下面一个依赖配置com.alibaba.citrus.citrus-webx-all却也缺省依赖Spring,版本为3.2.16.RELEASE。    
      -->
      <dependency>
          <groupId>com.alibaba</groupId>
          <artifactId>dubbo</artifactId>
          <version>2.5.3</version>
          <exclusions>
              <exclusion>
                  <groupId>org.springframework</groupId>
                  <artifactId>spring</artifactId>
              </exclusion>
          </exclusions>
      </dependency>

      如果使用Spring的2.5.6.SEC03版本直接打包,就会有如下错误:

      ERROR context.ContextLoader - Context initialization failed
      org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'uriBrokerService': Cannot create inner bean '(inner bean)' of type [com.alibaba.citrus.service.uribroker.impl.URIBrokerServiceImpl$URIBrokerInfo] while setting bean property 'brokers' with key [0]; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name '(inner bean)#25': Cannot create inner bean 'server' of type [com.alibaba.citrus.service.uribroker.uri.GenericURIBroker] while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'server': Error setting property values; nested exception is org.springframework.beans.NotWritablePropertyException: Invalid property 'URIType' of bean class [com.alibaba.citrus.service.uribroker.uri.GenericURIBroker]: Bean property 'URIType' is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter?
      at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveInnerBean(BeanDefinitionValueResolver.java:230)
      at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:122)
      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)
      
    4. 接着,如果此项目你不打算部署到与任意一个Zookeeper一个机器的话,就需要修改/dubbo-admin/src/main/webapp/WEB-INF/dubbo.properties文件,在其中指定你的Zookeeper地址(要保证这些机器能互相通讯)。

    5. 没有要修改的了。可以使用Maven的package命令打包了。之后部署war项目,可以按照官网的部署方式,也就是将之部署为ROOT应用,官网地址点这里

  3. 服务提供者项目

    源码地址:dubbo-practice-provider
    其中有两个子项目:

    • dubbo-practice-provider-api:暴漏接口和JavaBeans,让实现项目引用然后去实现、让消费者引用然后调用。这个比较简单,一看就懂就不展开讲了。
    • dubbo-practice-provider-impl:上面api项目的实现项目,是一个普通Java项目;

    实现者项目dubbo-practice-provider-impl的主要内容就是Dubbo如何暴漏一个服务的使用了,说一下:

    1. 首先是依赖关系,pom.xml

      
      <!-- 上一个API项目 -->
      <dependency>
          <groupId>dubbo-practice-provider-api</groupId>
          <artifactId>dubbo-practice-provider-api</artifactId>
          <version>0.0.1-SNAPSHOT</version>
      </dependency>
      <!-- 本项目用的Spring,版本4.2.2.RELEASE -->
      <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-context</artifactId>
          <version>${spring.version}</version>
      </dependency>
      <!-- dubbo,版本2.5.3 -->
      <dependency>
          <groupId>com.alibaba</groupId>
          <artifactId>dubbo</artifactId>
          <version>${dubbo.version}</version>
      </dependency>
      <!-- dubbo使用的zookeeper,版本3.4.8 -->
      <dependency>
          <groupId>org.apache.zookeeper</groupId>
          <artifactId>zookeeper</artifactId>
          <version>${zookeeper.version}</version>
      </dependency>
      <!-- zookeeper的一种客户端zkclient,版本0.1 -->
      <dependency>
          <groupId>com.github.sgroschupf</groupId>
          <artifactId>zkclient</artifactId>
          <version>${zkclient.version}</version>
      </dependency>
    2. 其次是dubbo配置,配置在Spring配置文件中,我放在/META-INF/spring/spring-dubbo.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">
      
      <!-- 提供方应用信息,用于计算依赖关系 -->
      <dubbo:application name="dubbo-practice-provider" />
      
      <!-- 使用Zookeeper集群注册中心暴露服务地址 -->
      <dubbo:registry protocol="zookeeper" address="192.168.157.130:2181,192.168.157.129:2181" />
      
      <!-- 用dubbo协议在20880端口暴露服务,一个项目需要一个端口 -->
      <dubbo:protocol name="dubbo" port="20880" />
      
      <!-- Service 提供者 -->
      <!-- 声明需要暴露的服务接口,interface指定接口,ref指定真正的实现者(SpringBean的id) -->
      <dubbo:service interface="com.ddup.dubbo.service.api.PersonService" ref="personService" />
      
      </beans>
    3. 最后,做好之后就可以运行了,我写了一个简单的启动服务类/dubbo-practice-provider-impl/src/main/java/com/ddup/dubbo/service/impl/DubboContainerStart.java,运行这个就行了,不要关。
  4. 服务消费者项目

    源码地址:dubbo-practice-consumer
    主要就是Dubbo服务的调用了,见/META-INF/spring/spring-dubbo.xml

    <!-- 消费方应用名,用于计算依赖关系,不是匹配条件,不要与提供方一样 -->
    <dubbo:application name="dubbo-practice-consumer" />
    
    <!-- 使用与提供者一样的Zookeeper集群注册中心,来获取服务提供者信息 -->
    <dubbo:registry protocol="zookeeper" address="192.168.157.130:2181,192.168.157.129:2181" />
    
    <!-- 生成远程服务代理,可以和本地bean一样使用personService,init是否饥饿式初始化这个引用 -->
    <dubbo:reference id="personService" interface="com.ddup.dubbo.service.api.PersonService" init="true" />

    然后,运行/dubbo-practice-consumer/src/main/java/com/ddup/dubbo/consumer/SpringStart.java,鹅妹子嘤!!!可以看到,调用成功啦!

  5. 在上面#2准备的管理控制台上,现在你就可以看到服务了,能看到服务者以及每个服务的消费者等等信息;

    登录
    这里写图片描述

    查看Dubbo服务
    这里写图片描述


以上,我们已经完成了一个Dubbo 的实例了。


TIPS:

  1. dubbo-admin项目的tomcat启动后无法访问:

    打开catalina.out查看错误

    [root@localhost logs]# vim catalina.out

    如果发现如下错误,是因为Zookeeper没有成功启动,可以去检查Zookeeper的状态。

    INFO velocity.VelocityEngine - SpringResourceLoaderAdapter : initialization starting.
    INFO velocity.VelocityEngine - SpringResourceLoaderAdapter : set path '/templates/common/'
    INFO velocity.VelocityEngine - SpringResourceLoaderAdapter : initialization complete.
    INFO rule.ExtensionMappingRule - Initialized extension.input:ExtensionMappingRule with cache disabled
    INFO rule.ExtensionMappingRule - Initialized extension.output:ExtensionMappingRule with cache disabled
    INFO rule.DirectModuleMappingRule - Initialized action:DirectModuleMappingRule with cache disabled
    INFO rule.DirectModuleMappingRule - Initialized screen.notemplate:DirectModuleMappingRule with cache disabled
    INFO rule.FallbackModuleMappingRule - Initialized screen:FallbackModuleMappingRule with cache enabled
    INFO rule.DirectTemplateMappingRule - Initialized screen.template:DirectTemplateMappingRule with cache disabled
    INFO rule.FallbackTemplateMappingRule - Initialized layout.template:FallbackTemplateMappingRule with cache enabled
    INFO rule.DirectModuleMappingRule - Initialized control.notemplate:DirectModuleMappingRule with cache disabled
    INFO rule.FallbackModuleMappingRule - Initialized control:FallbackModuleMappingRule with cache enabled
    INFO rule.DirectTemplateMappingRule - Initialized control.template:DirectTemplateMappingRule with cache disabled
    INFO zkclient.ZkEventThread - Starting ZkClient event thread.
    
  2. Provider的服务与Consumer引用时的一些问题:

    1. 关闭启动时检查
      Dubbo默认会在启动时检查依赖的服务是否可用,不可用会抛出异常,阻止Spring初始化完成。如果对有些服务不关心,或者出现了循环依赖,必须有一方先启动时,可以关闭启动时检查。方式如下:

      <dubbo:reference interface="com.xxx.XxxService" check="false" />
    2. 引用默认还是延迟初始化的,只有引用被注入到其它Bean,或者被getBean()获取时,才会初始化。如果需要饥饿加载,即Dubbo启动时就立即生成动态代理实例,则可以配置:

      <dubbo:reference interface="com.xx.XxxService" init="true" />

一篇我觉得不错的文章推荐:深入浅出 RPC - 浅出篇


2017.07.31更新:Dubbo官网声明官方要重新开始重点维护此项目了!


转载注明出处:http://blog.csdn.net/u010297957/article/details/51702076

以上是关于RPC框架与Dubbo完整使用的主要内容,如果未能解决你的问题,请参考以下文章

Dubbo3高级特性「框架与服务」RPC全链路调用追踪参数传递(OpenTracing)

RPC 服务框架 Dubbo 将正式得到官方维护与支持

分布式与微服务系列分布式RPC框架Apache Dubbo服务

Dubbo简介与使用

Dubbo RPC远程调用框架

RPC框架Dubbo从理解到使用