Fork me on GitHub

Dubbo

背景

分布式应用系统开发是大数据时代的趋势
随着互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,亟需一个治理系统确保架构有条不紊的演进。


单一应用架构
当网站流量很小时,只需一个应用,将所有功能都部署在一起,以减少部署节点和成本。
此时,用于简化增删改查工作量的 数据访问框架(ORM) 是关键。
垂直应用架构
当访问量逐渐增大,单一应用增加机器带来的加速度越来越小,将应用拆成互不相干的几个应用,以提升效率。
此时,用于加速前端页面开发的 Web框架(MVC) 是关键。
分布式服务架构
当垂直应用越来越多,应用之间交互不可避免,将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心,使前端应用能更快速的响应多变的市场需求。
此时,用于提高业务复用及整合的 分布式服务框架(RPC) 是关键。
流动计算架构
当服务越来越多,容量的评估,小服务资源的浪费等问题逐渐显现,此时需增加一个调度中心基于访问压力实时管理集群容量,提高集群利用率。
此时,用于提高机器利用率的 资源调度和治理中心(SOA) 是关键。

什么是Dubbo

Dubbo是阿里巴巴公司开源的一个高性能优秀的服务框架,使得应用可通过高性能的 RPC 实现服务的输出和输入功能,可以和Spring框架无缝集成。

为什么使用Dubbo(需求)


在大规模服务化之前,应用可能只是通过RMI或Hessian等工具,简单的暴露和引用远程服务,通过配置服务的URL地址进行调用,通过F5等硬件进行负载均衡。

当服务越来越多时,服务URL配置管理变得非常困难,F5硬件负载均衡器的单点压力也越来越大。
此时需要一个服务注册中心,动态的注册和发现服务,使服务的位置透明。
并通过在消费方获取服务提供方地址列表,实现软负载均衡和Failover,降低对F5硬件负载均衡器的依赖,也能减少部分成本。

当进一步发展,服务间依赖关系变得错踪复杂,甚至分不清哪个应用要在哪个应用之前启动,架构师都不能完整的描述应用的架构关系。
这时,需要自动画出应用间的依赖关系图,以帮助架构师理清理关系。

接着,服务的调用量越来越大,服务的容量问题就暴露出来,这个服务需要多少机器支撑?什么时候该加机器?
为了解决这些问题,第一步,要将服务现在每天的调用量,响应时间,都统计出来,作为容量规划的参考指标。
其次,要可以动态调整权重,在线上,将某台机器的权重一直加大,并在加大的过程中记录响应时间的变化,直到响应时间到达阀值,记录此时的访问量,再以此访问量乘以机器数反推总容量。

架构

节点角色说明

  • Provider: 暴露服务的服务提供方。
  • Consumer: 调用远程服务的服务消费方。
  • Registry: 服务注册与发现的注册中心。
  • Monitor: 统计服务的调用次调和调用时间的监控中心。
  • Container: 服务运行容器。

调用关系说明

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

连通性:

注册中心负责服务地址的注册与查找,相当于目录服务,服务提供者和消费者只在启动时与注册中心交互,注册中心不转发请求,压力较小
监控中心负责统计各服务调用次数,调用时间等,统计先在内存汇总后每分钟一次发送到监控中心服务器,并以报表展示
服务提供者向注册中心注册其提供的服务,并汇报调用时间到监控中心,此时间不包含网络开销
服务消费者向注册中心获取服务提供者地址列表,并根据负载算法直接调用提供者,同时汇报调用时间到监控中心,此时间包含网络开销
注册中心,服务提供者,服务消费者三者之间均为长连接,监控中心除外
注册中心通过长连接感知服务提供者的存在,服务提供者宕机,注册中心将立即推送事件通知消费者
注册中心和监控中心全部宕机,不影响已运行的提供者和消费者,消费者在本地缓存了提供者列表
注册中心和监控中心都是可选的,服务消费者可以直连服务提供者

健状性:

监控中心宕掉不影响使用,只是丢失部分采样数据
数据库宕掉后,注册中心仍能通过缓存提供服务列表查询,但不能注册新服务
注册中心对等集群,任意一台宕掉后,将自动切换到另一台
注册中心全部宕掉后,服务提供者和服务消费者仍能通过本地缓存通讯
服务提供者无状态,任意一台宕掉后,不影响使用
服务提供者全部宕掉后,服务消费者应用将无法使用,并无限次重连等待服务提供者恢复

伸缩性:

注册中心为对等集群,可动态增加机器部署实例,所有客户端将自动发现新的注册中心
服务提供者无状态,可动态增加机器部署实例,注册中心将推送新的服务提供者信息给消费者

升级性:

当服务集群规模进一步扩大,带动IT治理结构进一步升级,需要实现动态部署,进行流动计算,现有分布式服务架构不会带来阻力:

  • Deployer: 自动部署服务的本地代理。
  • Repository: 仓库用于存储服务应用发布包。
  • Scheduler: 调度中心基于访问压力自动增减服务提供者。
  • Admin: 统一管理控制台。

部署环境

安装和设置Zookeeper服务

我之前所写的Java相关软件安装中有提到Zookeeper服务的安装与配置;安装完后要启动

安装Dubbo管理Web端

需要服务器上安装JDK与Tomcat(我之前些的Java相关软件安装中有相关安装方法)
我的环境版本为:
服务器: 阿里云Ubuntu 16.04
JDK: 1.8.0_131
Tomcat: apache-tomcat-8.5.24

获取去alibaba dubbo官方github下载源码,我用的是dubbo-dubbo-2.5.6
下载后解压并将dubbo-admin导入到eclipse中,
修改相应的配置:mysql,zookeeper(dubbo.properties)
配置修改完成后,用maven打包(注意打包时BuildPath中用jdk不要用jre,会报错)。打包完整后在dubbo-dubbo-2.5.6\dubbo-admin\target中得到dubbo-admin-2.5.6.war。
将这个war包放置在服务器上的apache-tomcat-8.5.24/webapps下。放之前记得清空webapps下的所有文件。
启动tomcat,并在本地浏览器中访问dubbo-admin: http://192.168.111.101:8080/dubbo-admin-2.5.6

遇到的几个问题:

  1. 打包dubbo-admin的时候报错:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.1:compile
    原因是打包时,BuildPath用的是jre,换成jdk就ok了
  2. 解决第一个问题后,打包继续报错:

    1
    2
    SEVERE [localhost-startStop-1] org.apache.catalina.core.ContainerBase.addChildInternal ContainerBase.addChild: start:
    org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[]]

    原因是包冲突导致的,具体哪些包冲突了我也不知道,只是清空了本地maven仓库中的包,重新自动下载后就ok了。

  3. 打包终于成功了,但是发现端口冲突了,8080端口被占用了,然后将tomcat的端口改成9091了
  4. 端口问题解决了,但是启动tomcat的时候报了: java.net.UnknownHostException: ubuntu1: ubuntu1: Name or service not known
    原因是主机名没有绑定ip地址
    1
    2
    $ vi /etc/hosts
    127.0.1.1 ubuntu1

搞定….

创建项目

为了体现分布式调用,本例中创建了以下两个项目,dubbo-consumer 远程调用 dubbo-provider 提供的服务:
dubbo-provider Dubbo 服务提供者
dubbo-consumer Dubbo 服务消费者

dubbo-provider

使用 Spring Initializr 构建 Dubbo 服务提供者 dubbo-provider 项目

  1. 登录 http://start.spring.io/ 填写如下信息后点击 “Generate Project” 按钮,得到 dubbo-provider 项目骨架
  2. 为 dubbo-provider 项目添加依赖:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    <dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>dubbo</artifactId>
    <version>2.4.10</version>
    <exclusions>
    <exclusion>
    <artifactId>spring</artifactId>
    <groupId>org.springframework</groupId>
    </exclusion>
    </exclusions>
    </dependency>
    <dependency>
    <groupId>org.apache.zookeeper</groupId>
    <artifactId>zookeeper</artifactId>
    <version>3.4.6</version>
    <exclusions>
    <exclusion>
    <artifactId>slf4j-log4j12</artifactId>
    <groupId>org.slf4j</groupId>
    </exclusion>
    </exclusions>
    </dependency>
    <dependency>
    <groupId>com.github.sgroschupf</groupId>
    <artifactId>zkclient</artifactId>
    <version>0.1</version>
    </dependency>
  3. 定义接口:

    1
    2
    3
    4
    5
    6
    7
    package com.yh.dubbo.provider.remote;
    public interface HelloService {
    String sayHello(String name);
    }
  4. 实现接口方法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    package com.yh.dubbo.provider.remote;
    public class HelloServiceImpl implements HelloService {
    @Override
    public String sayHello(String name) {
    return "Hello! " + name;
    }
    }
  5. 在 resource/ 下添加 providers.xml 配置文件,用于向 zookeeper 注册中心注册服务

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    <?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">
    <!-- 配置可参考 http://dubbo.io/User+Guide-zh.htm -->
    <!-- 服务提供方应用名,用于计算依赖关系 -->
    <dubbo:application name="dubbo-provider" owner="dubbo-provider"/>
    <!-- 定义 zookeeper 注册中心地址及协议 -->
    <dubbo:registry protocol="zookeeper" address="192.168.111.101:2181" client="zkclient"/>
    <!-- 定义 Dubbo 协议名称及使用的端口,dubbo 协议缺省端口为 20880,如果配置为 -1 或者没有配置 port,则会分配一个没有被占用的端口 -->
    <dubbo:protocol name="dubbo" port="-1"/>
    <!-- 声明需要暴露的服务接口 -->
    <dubbo:service interface="com.yh.dubbo.provider.remote.HelloService" ref="helloService" timeout="10000"/>
    <!-- 和本地 bean 一样实现服务 -->
    <bean id="helloService" class="com.yh.dubbo.provider.remote.HelloServiceImpl" />
    </beans>
  6. DubboProviderApplication 中使用 providers.xml 配置文件;

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    package com.shawearn.dubbo.provider;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.context.annotation.ImportResource;
    @SpringBootApplication
    @ImportResource(value = {"classpath:providers.xml"}) // 使用 providers.xml 配置;
    public class DubboProviderApplication {
    public static void main(String[] args) {
    SpringApplication.run(DubboProviderApplication.class, args);
    }
    }
  7. application.properties 中指定项目启动时占用的端口号:

    1
    server.port=8011

dubbo-consumer

https://www.cnblogs.com/520playboy/p/6298289.html
http://blog.csdn.net/songjinbin/article/details/26006621
https://www.cnblogs.com/cksvsaaa/p/6019393.html

「真诚赞赏,手留余香」