决定放弃了Dubbo的学习,转战Spring Cloud。

在用3.0的版本+springboot的时候,很多问题不能解决。

招聘中对Dubbo技能要求也不是很高

基础理论

  • 《分布式系统原理与范型》定义:“分布式系统是若干独立计算机的集合,这些计算机对于用户来说就像单个相关系统”

  • 分布式系统(distributed system)是建立在网络之上的软件系统。

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

单一应用架构

  • 当网站流量很小时,只需一个应用,将所有功能都部署在一起,以减少部署节点和成本。

  • 此时,用于简化增删改查工作量的数据访问框架(ORM)是关键。

  • 适用于小型网站,小型管理系统,将所有功能都部署到一个功能里,简单易用。

  • 缺点

    • 性能扩展比较难
    • 协同开发问题
    • 不利于升级维护

垂直应用架构

  • 当访问量逐渐增大,单一应用增加机器带来的加速度越来越小,提升效率的方法之一是将应用拆成互不相干的几个应用,以提升效率。

  • 此时,用于加速前端页面开发的Web框架(MVC)是关键。

  • 通过切分业务来实现各个模块独立部署,降低了维护和部署的难度,团队各司其职更易管理,性能扩展也更方便,更有针对性。

  • 缺点: 公用模块无法重复利用,开发性的浪费

分布式服务架构

  • 当垂直应用越来越多,应用之间交互不可避免,将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心,使前端应用能更快速的响应多变的市场需求。

  • 此时,用于提高业务复用及整合的分布式服务框架(RPC)是关键。

流动计算架构

  • 当服务越来越多,容量的评估,小服务资源的浪费等问题逐渐显现,此时需增加一个调度中心基于访问压力实时管理集群容量,提高集群利用率。

  • 此时,用于提高机器利用率的资源调度和治理中心(SOA)[ Service Oriented Architecture]是关键。

演进原因

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

  • 存在问题:

    • 当服务越来越多时,服务URL配置管理变得非常困难,F5硬件负载均衡器的单点压力也越来越大

    • 当进一步发展,服务间依赖关系变得错踪复杂,甚至分不清哪个应用要在哪个应用之前启动,架构师都不能完整的描述应用的架构关系。

    • 接着,服务的调用量越来越大,服务的容量问题就暴露出来,这个服务需要多少机器支撑?什么时候该加机器

  • 因此,针对这些问题,机构进行演进出现了以下为最基本的几个需求。

  1. 服务注册中心
  • 能够动态地注册和发现服务,使服务的位置透明。并通过在消费方获取服务提供方地址列表,实现软负载均衡和失败重启,降低对 F5 硬件负载均衡器的依赖,也能减少部分成本。
  1. 应用管理中心

    • 画出应用间的依赖关系图,描述应用间的架构关系。
  2. 服务监控

    • 监控服务的调用情况,对系统的服务提供机器容量等进行监控、分析、调控。将服务现在每天的调用量,响应时间,都统计出来,作为容量规划的参考指标。
    • 其次,要可以动态调整权重,在线上,将某台机器的权重一直加大,并在加大的过程中记录响应时间的变化,直到响应时间到达阈值,记录此时的访问量,再以此访问量乘以机器数反推总容量。

RPC

什么叫RPC

  • RPC【Remote Procedure Call】是指远程过程调用,是一种进程间通信方式,他是一种技术的思想,而不是规范。

  • 它允许程序调用另一个地址空间(通常是共享网络的另一台机器上)的过程或函数,而不用程序员显式编码这个远程调用的细节。

  • 即程序员无论是调用本地的还是远程的函数,本质上编写的调用代码基本相同。

  • RPC 概念是在上世纪 80 年代由 Brue Jay Nelson(布鲁·杰伊·纳尔逊)提出。使用 PRC 可以 将本地的调用扩展到远程调用(分布式系统的其他服务器)。

  • RPC 的特点

    1. 简单:使用简单,建立分布式应用更容易。
    2. 高效:调用过程看起来十分清晰,效率高。
    3. 通用:进程间通讯的方式,有通用的规则。

RPC基本原理

  • RPC两个核心模块:通讯,序列化。

    1. 调用方 client 要使用右侧 server 的功能(方法),发起对方法的调用
    2. client stub 是 PRC 中定义的存根,看做是 client 的助手。stub 把要调用的方法参数进行序 列化,方法名称和其他数据包装起来。
    3. 通过网络 socket(网络通信的技术),把方法调用的细节内容发送给右侧的 server
    4. server 端通过 socket 接收请求的方法名称,参数等数据,传给 stub。
    5. server 端接到的数据由 serverstub(server 的助手)处理,调用 server 的真正方法,处理业务
    6. server 方法处理完业务
    7. 把处理的结果对象(Object)交给了助手
    8. 助手把 Object 进行序 列化,对象转为二进制数据。
    9. server 助手二进制数据交给网络处理程序 通过网络将二进制数据,发送给 client。
    10. client 接数据,交给 client 助手。 client 助手,接收数据通过反序列化为 java 对象(Object)
    11. (Object)作为远程方法调用结果。

  • rpc 通讯是基于 tcp 或 udp 协议

  • 序列化方式(xml/json/二进制)

dubbo概述

  • Apache Dubbo (incubating) |ˈdʌbəʊ| 是一款高性能、轻量级的开源Java RPC框架,它提供了三大核心能力:
    • 面向接口的远程方法调用
    • 智能容错和负载均衡
    • 服务自动注册和发现
  • Dubbo 是一个分布式服务框架,致力于提供高性能和透明化的 RPC 远程服务调用方案、服务治理方案。
  • 官网:http://dubbo.apache.org/

基本概念

  • Dubbo实现架构如下:

  • 节点角色说明:

    节点 角色说明
    Provider (服务提供者) 暴露服务的服务提供方,服务提供者在启动时,向注册中心注册自己提供的服务。
    Consumer (服务消费者) 调用远程服务的服务消费方,服务消费者在启动时,向注册中心订阅自己所需的服务,服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
    Registry (注册中心) 服务注册与发现的注册中心, 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者
    Monitor (监控中心) 统计服务的调用次数和调用时间的监控中心 ,服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心
    Container 服务运行容器
  • 调用关系说明

    • 服务容器负责启动,加载,运行服务提供者。
    • 服务提供者在启动时,向注册中心注册自己提供的服务。
    • 服务消费者在启动时,向注册中心订阅自己所需的服务。
    • 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
    • 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
    • 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。
  • 在2.6版本之前是阿里维护, 捐赠给Apache基金会后版本变成2.7,包名变化比较大。

dubbo 支持的协议

  • 支持多种协议:dubbo , hessian , rmi , http, webservice , thrift , memcached , redis。 dubbo 官方推荐使用 dubbo 协议。dubbo 协议默认端口 20880

  • 使用 dubbo 协议,spring 配置文件加入:

    1
    <dubbo:protocol name="dubbo" port="20880" />
  • dubbo 协议采用单一长连接和 NIO 异步通讯,适合于小数据量大并发的服务调用,以及服务消费者机器数远大于服务提供者机器数的情况。不适合传送大数据量的服务,比如传文件,传视频等,除非请求量很低。也可以在同一个工程中配置多个协议,不同服务可以使用不同的协议,例如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    <!-- 多协议配置 -->
    <dubbo:protocol name="dubbo" port="20880" />
    <dubbo:protocol name="rmi" port="1099" />
    <!-- 使用dubbo协议暴露服务 -->
    <dubbo:service interface="pers.fulsun.api.HelloService" ref="helloService"
    protocol="dubbo" />
    <!-- 使用rmi协议暴露服务 -->
    <dubbo:service interface="pers.fulsun.api.DemoService" ref="demoService"
    protocol="rmi" />

Dubbo的直连使用

假设:某电商平台系统需求,用户浏览商品;选择商品下订单,订单系统需要获取用户信息中的送货地址;向支付系统请求完成付款。

服务 功能
网站系统 展示商品,修改用户信息
订单系统 生成订单,获取用户地址
用户系统 用户信息(地址,收件人,联系方式等

直连方式 dubbo

点对点的直连项目:消费者直接访问服务提供者,没有注册中心。消费者必须指定服务提供者的访问地址(url)。消费者直接通过 url 地址访问固定的服务提供者。这个 url 地址是不变的。

1
用户访问 ------>【商品网站服务】访问-----> 【订单服务】

编写服务提供者

  • 创建服务提供者:订单服务, 项目名称:001-link-userservice-provider

  • maven pom.xml

    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
    28
    29
    30
    31
    32
    <!--Spring依赖-->
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>4.3.16.RELEASE</version>
    </dependency>
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>4.3.16.RELEASE</version>
    </dependency>

    <!--dubbo依赖-->
    <dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>dubbo</artifactId>
    <version>2.6.2</version>
    </dependency>

    <build>
    <plugins>
    <!--JDK1.8编译插件-->
    <plugin>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.1</version>
    <configuration>
    <source>1.8</source>
    <target>1.8</target>
    </configuration>
    </plugin>
    </plugins>
    </build>
  • 创建用户实体类:User

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    package com.wkcto.dubbo.model;

    import java.io.Serializable;

    public class User implements Serializable {
    private Integer id;

    private String username;

    private Integer age;

    // ...get ...set
    }
  • 新建用户服务接口 UserService

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    package com.wkcto.dubbo.service;

    import com.wkcto.dubbo.model.User;

    public interface UserService {

    /**
    * 根据用户标识获取用户信息
    * @param id
    * @return
    */
    User queryUserById(Integer id);
    }
  • 新建接口的实现类:UserServiceImpl

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    package com.wkcto.dubbo.service.impl;

    import com.wkcto.dubbo.model.User;
    import com.wkcto.dubbo.service.UserService;

    public class UserServiceImpl implements UserService {

    @Override
    public User queryUserById(Integer id) {

    User user = new User();
    user.setId(id);
    user.setUsername("lisi");
    user.setAge(23);
    return user;
    }
    }

  • 创建 dubbo 配置文件 dubbo-userservice-provider.xml

    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
    <?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://dubbo.apache.org/schema/dubbo"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">

    <!--服务提供者声明名称:必须保证服务名称的唯一性,它的名称是dubbo内部使用的唯一标识-->
    <dubbo:application name="001-link-userservice-provider"/>

    <!--访问服务协议的名称及端口号,dubbo官方推荐使用的是dubbo协议,端口号默认为20880-->
    <!--
    name:指定协议的名称
    port:指定协议的端口号(默认为20880)
    -->
    <dubbo:protocol name="dubbo" port="20880"/>

    <!--
    暴露服务接口->dubbo:service
    interface:暴露服务接口的全限定类名
    ref:接口引用的实现类在spring容器中的标识
    registry:如果不使用注册中心,则值为:N/A
    -->
    <dubbo:service interface="com.wkcto.dubbo.service.UserService" ref="userServer" registry="N/A"/>

    <!--将接口的实现类加载到spring容器中-->
    <bean id="userServer" class="com.wkcto.dubbo.service.impl.UserServiceImpl"/>

    </beans>
  • 测试配置文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    package com.wkcto.dubbo.service;

    import java.io.IOException;

    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;

    import com.alibaba.dubbo.config.ApplicationConfig;

    public class UserApplication {
    public static void main(String[] args) throws Exception {
    String configLocation = "dubbo-userservice-provider.xml";
    ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(configLocation);
    ctx.start();
    // 阻塞操作 , 应用一直运行
    System.in.read();
    }
    }
  • 安装本地 jar 到 maven 仓库

    服务接口中的方法要给消费者使用,消费者项目需要知道接口名称和接口中的方法名称、参数等。这些信息服务提供者才知道。需要把服务接口项目的类文件打包为 jar, 安装到 maven 仓库,仓库中的提供者 jar 可以被消费者 使用。 可以在 maven 窗口执行 install

创建服务消费者

  • 新建 java project 项目名称:002-link-consumer

  • maven pom.xml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    <dependencies>
    <!--Spring依赖-->
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>4.3.16.RELEASE</version>
    </dependency>

    <!--dubbo依赖-->
    <dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>dubbo</artifactId>
    <version>2.6.2</version>
    </dependency>

    <!--依赖服务提供者-->
    <dependency>
    <groupId>com.wkcto.dubbo</groupId>
    <artifactId>001-link-userservice-provider</artifactId>
    <version>1.0.0</version>
    </dependency>
    </dependencies>
  • 创建获取用户接口

    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
    package com.wkcto.dubbo.web;

    import com.wkcto.dubbo.model.User;
    import com.wkcto.dubbo.service.UserService;
    import com.wkcto.dubbo.service.impl.UserServiceImpl;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseBody;

    public class UserController {

    private UserService userService;

    public void setUserService(UserService userService) {
    this.userService = userService;
    }

    public void userDetail( Integer id) {

    User user = this.userService.queryUserById(id);
    System.out.println(user);
    }

    }

  • 创建 dubbo 配置文件 dubbo-consumer.xml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    <?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://dubbo.apache.org/schema/dubbo"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">

    <!--声明服务消费者的名称:保证唯一性-->
    <dubbo:application name="002-link-consumer"/>

    <!--
    引用远程服务接口:
    id:远程服务接口对象名称
    interface:调用远程接口的全限定类名
    url:访问服务接口的地址
    registry:不使用注册中心,值为:N/A
    -->
    <dubbo:reference id="userService"
    interface="com.wkcto.dubbo.service.UserService"
    url="dubbo://localhost:20880"
    registry="N/A"/>

    <bean id="userController" class="com.wkcto.dubbo.web.UserController">
    <property name="userService" ref="userService"/>
    </bean>
    </beans>
  • 执行消费者

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    package com.wkcto.dubbo.web;

    import org.springframework.context.support.ClassPathXmlApplicationContext;

    public class ConsumeApplication {
    public static void main(String[] args) {
    ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("dubbo-consumer.xml");
    UserController userController = ctx.getBean("userController", UserController.class);
    userController.userDetail(1);
    }
    }

dubbo 服务化最佳实践

分包

建议将服务接口、服务模型、服务异常等均放在公共包中。

粒度

服务接口尽可能大粒度,每个服务方法应代表一个功能,而不是某功能的一个步骤,否则将面临分布式事务问题,Dubbo 暂未提供分布式事务支持。

服务接口建议以业务场景为单位划分,并对相近业务做抽象,防止接口数量爆炸。

不建议使用过于抽象的通用接口,如:Map query(Map),这样的接口没有明确语义,会给后期维护带来不便。

版本

每个接口都应定义版本号,为后续不兼容升级提供可能,如: <dubbo:service interface="com.xxx.XxxService" version="1.0" />

建议使用两位版本号,要变更服务版本。先升级一半提供者为新版本,再将消费者全部升为新版本,然后将剩下的一半提供者升为新版本。

改造 dubbo 项目

抽象分散在多个项目中的公共接口,实体类,异常,工具类到一个项目中,在其他项目 如服务提供者,消费者共用公共的资源。

实现目标

用户访问电商网站浏览商品—选择商品购买
用户访问电商网站—查看用户信息(收件人地址)

创建公共资源项目

服务提供者,消费者,网站等多个服务中共用,重复使用的类单独定义在一个项目。

  • 创建公共的 maven java project ,项目名称:003-link-interface

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.wkcto.dubbo</groupId>
    <artifactId>003-link-interface</artifactId>
    <version>1.0.0</version>


    </project>
  • 复制之前 001-link-userservice-provider 项目的接口文件,实体类文件

  • 安装 jar 到 maven 仓库:使用 idea 的 maven 窗口执行 install

创建用户信息服务

  • 新建 web project 004-link-userservice-provider

  • maven pom.xml

    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
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    <groupId>com.wkcto.dubbo</groupId>
    <artifactId>004-link-userservice-provider</artifactId>
    <version>1.0.0</version>
    <packaging>war</packaging>

    <dependencies>

    <!--Spring依赖-->
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>4.3.16.RELEASE</version>
    </dependency>
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>4.3.16.RELEASE</version>
    </dependency>

    <!--dubbo依赖-->
    <dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>dubbo</artifactId>
    <version>2.6.2</version>
    </dependency>

    <!--接口工程-->
    <dependency>
    <groupId>com.wkcto.dubbo</groupId>
    <artifactId>003-link-interface</artifactId>
    <version>1.0.0</version>
    </dependency>

    </dependencies>

    <build>
    <plugins>
    <!--JDK1.8编译插件-->
    <plugin>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.1</version>
    <configuration>
    <source>1.8</source>
    <target>1.8</target>
    </configuration>
    </plugin>
    </plugins>
    </build>
  • 创建 UserInfoServiceImpl 实现类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    package com.wkcto.dubbo.service.impl;

    import com.wkcto.dubbo.model.User;
    import com.wkcto.dubbo.service.UserService;

    public class UserServiceImpl implements UserService {

    @Override
    public User queryUserById(Integer id) {
    User user = new User();
    user.setId(id);
    user.setUsername("zhangsan");
    return user;
    }

    @Override
    public Integer queryAllUserCount() {
    return 52;
    }
    }
  • dubbo 配置文件 dubbo-userservice-provider.xml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    <?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://dubbo.apache.org/schema/dubbo"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">

    <!--声明dubbo服务提供者的名称:保证唯一性-->
    <dubbo:application name="004-link-userservice-provider"/>

    <!--设置dubbo使用的协议和端口号-->
    <!--
    name:dubbo使用协议的名称
    port:dubbo服务的端口号
    -->
    <dubbo:protocol name="dubbo" port="20880"/>

    <!--
    暴露服务接口
    -->
    <dubbo:service interface="com.wkcto.dubbo.service.UserService" ref="userService" registry="N/A"/>

    <!--加载业务接口的实现类到spring容器中-->
    <bean id="userService" class="com.wkcto.dubbo.service.impl.UserServiceImpl"/>

    </beans>
  • web.xml 注册 spring 监听器 src/main/webapp/WEB-INF/web.xml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <?xml version="1.0" encoding="UTF-8"?>
    <web-app id="WebApp_ID" version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_0.xsd">

    <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:dubbo-userservice-provider.xml</param-value>
    </context-param>
    <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    </web-app>

创建消费服务

  • 新建 web project 项目名称:005-link-consumer

  • maven pom.xm

    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
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    <groupId>com.wkcto.dubbo</groupId>
    <artifactId>005-link-consumer</artifactId>
    <version>1.0.0</version>

    <packaging>war</packaging>

    <dependencies>
    <!--Spring依赖-->
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>4.3.16.RELEASE</version>
    </dependency>
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>4.3.16.RELEASE</version>
    </dependency>

    <!--dubbo依赖-->
    <dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>dubbo</artifactId>
    <version>2.6.2</version>
    </dependency>

    <!--接口工程-->
    <dependency>
    <groupId>com.wkcto.dubbo</groupId>
    <artifactId>003-link-interface</artifactId>
    <version>1.0.0</version>
    </dependency>
    </dependencies>

    <build>
    <plugins>
    <!--JDK1.8编译插件-->
    <plugin>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.1</version>
    <configuration>
    <source>1.8</source>
    <target>1.8</target>
    </configuration>
    </plugin>
    </plugins>
    </build>
  • 创建 UserController

    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
    28
    29
    30
    package com.wkcto.dubbo.web;

    import com.wkcto.dubbo.model.User;
    import com.wkcto.dubbo.service.UserService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;

    @Controller
    public class UserController {

    @Autowired
    private UserService userService;

    @RequestMapping(value = "/userDetail")
    public String userDetail(Model model,Integer id) {

    //根据用户标识获取用户详情
    User user = userService.queryUserById(id);

    //获取用户总人数
    Integer allUserCount = userService.queryAllUserCount();

    model.addAttribute("user",user);
    model.addAttribute("allUserCount",allUserCount);

    return "userDetail";
    }
    }
  • dubbo 配置文件 dubbo-consumer.xml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <?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://dubbo.apache.org/schema/dubbo"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">

    <!--声明服务消费者名称:保证唯一性-->
    <dubbo:application name="005-link-consumer"/>

    <!--引用远程接口服务-->
    <dubbo:reference id="userService"
    interface="com.wkcto.dubbo.service.UserService"
    url="dubbo://localhost:20880"
    registry="N/A"/>
    </beans>
  • 新建 spring 配置文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    <?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:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!--扫描组件-->
    <context:component-scan base-package="com.wkcto.dubbo.web"/>

    <!--配置注解驱动-->
    <mvc:annotation-driven/>

    <!--视图解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/"/>
    <property name="suffix" value=".jsp"/>
    </bean>
    </beans>
  • web.xml DispatcherServlet src/main/webapp/WEB-INF/web.xml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    <?xml version="1.0" encoding="UTF-8"?>
    <web-app id="WebApp_ID" version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_0.xsd">

    <servlet>
    <servlet-name>dispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.xml,classpath:dubbo-consumer.xml</param-value>
    </init-param>
    </servlet>
    <servlet-mapping>
    <servlet-name>dispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
    </servlet-mapping>

    </web-app>
  • 编写响应文件 src/main/webapp/userDetail.jsp

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
    <title>用户详情</title>
    </head>
    <body>
    <h3>用户详情</h3>
    <div>用户标识:${user.id}</div>
    <div>用户姓名:${user.username}</div>
    <div>用户总人数:${allUserCount}</div>
    </body>
    </html>

测试服务

  1. 启动用户信息服务

  2. 启动消费服务,访问 /userDetail 接口

dubbo 常用标签

Dubbo 中常用标签。分为三个类别:公用标签,服务提供者标签,服务消费者标签

公用标签

<dubbo:application/><dubbo:registry/>

配置应用信息

<dubbo:application name=”服务的名称”/>

配置注册中心

<dubbo:registry address=”ip:port” protocol=”协议”/>

包扫描

服务提供者和服务消费者都需要配置,表示包扫描,作用是扫描指定包 (包括子包) 下的类。

如果不使用包扫描,也可以通过如下配置dubbo:service, dubbo:reference的方式来发布服务:

1
2
3
4
5
6
7
<dubbo:annotation package="com.lxs.service.impl" />

<bean id="helloService" class="pers.fulsun.service.impl.HelloServiceImpl" />
<dubbo:service interface="pers.fulsun.api.HelloService" ref="helloService" />

<!-- 生成远程服务代理,可以和本地bean一样使用helloService -->
<dubbo:reference id="helloService" interface=pers.fulsun.api.HelloService" />

一个配置项 (dubbo:servicedubbo:reference) 只能发布或者引用一个 服务,如果有多个服务,这种方式就比较繁琐了。推荐使用包扫描方式。

服务提供者标签

配置暴露的服务
<dubbo:service interface=”服务接口名” ref=”服务实现对象 bean”>

服务消费者

配置服务消费者引用远程服务
<dubbo:reference id=”服务引用 bean 的 id” interface=”服务接口名”/>

注册中心-Zookeepe

注册中心概述

对于服务提供方,它需要发布服务,而且由于应用系统的复杂性,服务的数量、类型也不断膨胀;对于服务消费方,它最关心如何获取到它所需要的服务,而面对复杂的应用系统,需要管理大量的服务调用。

而且,对于服务提供方和服务消费方来说,他们还有可能兼具这两种角色,即需要提供服务,有需要消费服务。 通过将服务统一管理起来,可以有效地优化内部应用对服务发布使用的流程和管理。

服务注册中心可以通过特定协议来完成服务对外的统一。Dubbo 提供的注册中心有如下几种类型可供选:

  • Multicast 注册中心:组播方式
  • Redis 注册中心:使用 Redis 作为注册中心
  • Simple 注册中心:就是一个 dubbo 服务。作为注册中心。提供查找服务的功能。
  • Zookeeper 注册中心:使用 Zookeeper 作为注册中心,推荐使用 Zookeeper 注册中心。

注册中心工作方式

Zookeeper 是 Apache Hadoop 的子项目,是一个树型的目录服务,支持变更推送,适合作为 Dubbo 服务的注册中心,工业强度较高,可用于生产环境,并推荐使用。

流程说明:

  • 服务提供者 (Provider) 启动时:向 /dubbo/com.foo.BarService/providers 目录下写入自己的 URL 地址
  • 服务消费者 (Consumer) 启动时:订阅 /dubbo/com.foo.BarService/providers 目录下的提供者 URL 地址。并向 /dubbo/com.foo.BarService/consumers 目录下写入自己的 URL 地址
  • 监控中心 (Monitor) 启动时:订阅 /dubbo/com.foo.BarService 目录下的所有提供者和消费者 URL 地址

改造dubbo使用Zookeeper

  • 新建项目 006-zk-interface 007-zk-userservice-provider 008-zk-consumer ,内容同上

  • provider consumer 项目加入 zookeepeer 相关 jar: org.apache.curator curator-framework 4.1.0

    1
    2
    3
    4
    5
    6
    <!--zookeeper依赖-->
    <dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-framework</artifactId>
    <version>4.1.0</version>
    </dependency>
  • 修改dubbo配置文件 dubbo-zk-userservice-provider.xml dubbo-zk-consumer.xml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    <?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://dubbo.apache.org/schema/dubbo"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">

    <!--声明dubbo服务提供者的名称:保证唯一性-->
    <dubbo:application name="007-zk-userservice-provider"/>

    <!--声明dubbo使用的协议名称和端口号-->
    <dubbo:protocol name="dubbo" port="20880"/>

    <!--现在要使用zookeeper注册中心-->
    <!--指定注册中心地址和端口号-->
    <dubbo:registry address="zookeeper://localhost:2181"/>

    <!--暴露服务接口-->
    <dubbo:service interface="com.bjpowernode.dubbo.service.UserService" ref="userServiceImpl"/>

    <!--加载接口实现类-->
    <bean id="userServiceImpl" class="com.bjpowernode.dubbo.service.impl.UserServiceImpl"/>
    </beans>

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    <?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://dubbo.apache.org/schema/dubbo"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">

    <!--声明dubbo服务消费者名称:保证唯一性-->
    <dubbo:application name="008-zk-consumer"/>

    <!--指定注册中心-->
    <dubbo:registry address="zookeeper://localhost:2181"/>

    <!--引用远程接口服务-->
    <dubbo:reference id="userService" interface="com.bjpowernode.dubbo.service.UserService"/>

    </beans>
  • 运行应用

    1. 先启动注册中心

    2. 再启动 tomcat 服务器

    3. 访问 008-zk-consumer 的 /userDetail

注册中心的高可用

高可用性(High Availability):通常来描述一个系统经过专门的设计,从而减少不能提供服务的时间,而保持其服务的高度可用性。

Zookeeper 是高可用的,健壮的。但是Zookeeper 宕机,正在运行中的 dubbo 服务仍然可以正常访问。ps(如果生产者还活着的话)

  • 生产者启动后,把自身的信息写入到zookeeper中,让zookeeper以心跳机制查询生产者是否活着。然后消费者启动时,向zookeeper获取生产者的信息,保存在内存中, 如果zookeeper活着,会实时更新 。当调用消费者进行消费的时候,是根据获取到的 地址,以及 状态 直接进行 RPC 调用。

  • zoookeeper宕机了!无论是消费者还是生产者,这时候在控制台都疯狂报错,因为它们都在不断地尝试连接zookeeper。但是消费者是根据内存中保存的生产者的信息进行通信的,而在zookeeper宕机之前,这份信息已经保存在在内存里面,所以,即使这时候zookpper宕机了,消费者还是能与生产者通信。

  • 一般情况下,如果zookeeper还活着,因为有心跳检测机制,能检测到生产者是宕机了,那么它就会直接通知消费者,让消费者修改内存信息,这样消费者就不会去连接宕掉的服务。如果两台生产者也有一台在zookeeper宕机之后宕机了,要是发生这种情况,首先看负载均衡配置了哪一种,如果分发的调用是访问好的生产者,那自然没问题。如果是访问到了坏的生产者,那么消费者会立即修改内存里面的生产者的 状态位,并且立即访问好的那一台。

演示操作:

  1. 先启动 zookeeper, dubbo 服务提供者,dubbo 服务消费者。
  2. 测试正常访问胸
  3. 停止 zookeeper
  4. 测试消费者仍然可以访问提供者

dubbo的配置

配置原则

在服务提供者配置访问参数。因为服务提供者更了解服务的各种参数。

关闭检查

dubbo 缺省会在启动时检查依赖的服务是否可用,不可用时会抛出异常,阻止 Spring 初始化完成,以便上线时,能及早发现问题

默认 check=true。通过 check=”false”关闭检查,
比如,测试时,有些服务不关心,或者出现了循环依赖,必须有一方先启动。

1
2
3
4
 # 例 1:关闭某个服务的启动时检查
<dubbo:reference interface="com.foo.BarService" check="false" />
例 2:关闭注册中心启动时检查 默认启动服务时检查注册中心存在并已运行。注册中心不启动会报错。
<dubbo:registry check="false" />

重试次数

消费者访问提供者,如果访问失败,则切换重试访问其它服务器,但重试会带来更长延迟。访问时间变长,用户的体验较差。多次重新访问服务器有可能访问成功。可通过 retries=”2” 来设置重试次数(不含第一次)。

1
2
3
4
重试次数配置如下:
<dubbo:service retries="2" />

<dubbo:reference retries="2" />

超时时间

由于网络或服务端不可靠,会导致调用出现一种不确定的中间状态(超时)。为了避免超时导致客户端资源(线程)挂起耗尽,必须设置超时时间。timeout:调用远程服务超时时间(毫秒)

  • dubbo 消费端 指定接口超时配置

    1
    <dubbo:reference interface="com.foo.BarService" timeout="2000" />
  • dubbo 服务端指定接口超时配置

    1
    <dubbo:server interface="com.foo.BarService" timeout="2000" />

版本号

  • 每个接口都应定义版本号,为后续不兼容升级提供可能。当一个接口有不同的实现,项目早期使用的一个实现类, 之后创建接口的新的实现类。区分不同的接口实现使用version。特别是项目需要把早期接口的实现全部换位新的实现类,也需要使用 version.
  • 可以用版本号从早期的接口实现过渡到新的接口实现,版本号不同的服务相互间不引用。可以按照以下的步骤进行版本迁移:
    1. 在低压力时间段,先升级一半提供者为新版本
    2. 再将所有消费者升级为新版本
    3. 然后将剩下的一半提供者升级为新版本

负载均衡

负载均衡(Load Balance):其实就是将请求分摊到多个操作单元上进行执行,从而共同完成工作任务。

在集群负载均衡时,Dubbo 提供了多种均衡策略(包括随机、轮询、最少活跃调用数、一致性 Hash),缺省为 random 随机调用。

算法 特性 备注 配置值
Weighted Random LoadBalance 加权随机 默认算法,默认权重相同 random (默认)
RoundRobin LoadBalance 加权轮询 借鉴于 Nginx 的平滑加权轮询算法,默认权重相同, roundrobin
LeastActive LoadBalance 最少活跃优先 + 加权随机 背后是能者多劳的思想 leastactive
Shortest-Response LoadBalance 最短响应优先 + 加权随机 更加关注响应速度 shortestresponse
ConsistentHash LoadBalance 一致性哈希 确定的入参,确定的提供者,适用于有状态请求 consistenthash
P2C LoadBalance Power of Two Choice 随机选择两个节点后,继续选择 “连接数” 较小的那个节点。 p2c
Adaptive LoadBalance 自适应负载均衡 在 P2C 算法基础上,选择二者中 load 最小的那个节点 adaptive

配置负载均衡策略,既可以在服务提供者一方配置,也可以在服务消费者一方配置,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import com.alibaba.dubbo.config.annotation.Reference;

@RestController
@RequestMapping("/demo")
public class HelloController {

@Reference(check = false, loadbalance = "roundrobin")
private HelloService helloService;

@RequestMapping("/hello")
public String sayHello(String name){
//远程调用
String result = helloService.sayHello(name);
System.out.println(result);
return result;
}
}

启动多个服务提供者来观察 Dubbo 负载均衡效果, 在一台机器上启动多个服务提供者,所以需要修改 tomcat 的端口号和 Dubbo 服务的 端口号来防止端口冲突。

服务端负载均衡

1
2
3
4
5
6
@Service(loadbalance = "random")
public class HelloServiceImpl implements HelloService {
public String sayHello(String name) {
return "hello " + name;
}
}

Dubbo 快速入门

Dubbo 作为一个 RPC 框架,其最核心的功能就是要实现跨网络的远程调用。这里是要创建两个应用,一个作为服务的提供方,一个作为服务的消费方。通过 Dubbo 来实现服务消费方远程调用服务提供方的方法。

服务提供方开发

创建 maven 工程(打包方式为 war)dubbodemo_provider,在 pom.xml 文件中导入如下坐标

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
<modelVersion>4.0.0</modelVersion>
<packaging>war</packaging>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<spring.version>5.0.5.RELEASE</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- dubbo相关 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.6.0</version>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.7</version>
</dependency>
<dependency>
<groupId>com.github.sgroschupf</groupId>
<artifactId>zkclient</artifactId>
<version>0.1</version>
</dependency>
<dependency>
<groupId>javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.12.1.GA</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<!-- 指定端口 -->
<port>8081</port>
<!-- 请求路径 -->
<path>/</path>
</configuration>
</plugin>
</plugins>
</build>

配置 web.xml 文件: 右键项目add framework support(添加框架支持),选择WEB Application , 文件目录IdeaProjects\dubbodemo_provider\web\WEB-INF\web.xml

1
2
3
4
5
6
7
8
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:applicationContext*.xml</param-value>
</context-param>

<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

创建服务接口

1
2
3
public interface HelloService {
public String sayHello(String name);
}

创建服务实现类, 类上使用的 Service 注解是 Dubbo 提供的,用于对外发布服务

1
2
3
4
5
6
7
8
import com.alibaba.dubbo.config.annotation.Service;

@Service
public class HelloServiceImpl implements HelloService {
public String sayHello(String name) {
return "hello " + name;
}
}

在 src/main/resources 下创建 applicationContext-service.xml

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
<?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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">

<!-- 当前应用名称,用于注册中心计算应用间依赖关系,注意:消费者和提供者应用名不要一样 -->
<dubbo:application name="dubbodemo_provider" />
<!-- 连接服务注册中心zookeeper ip为zookeeper所在服务器的ip地址-->
<dubbo:registry address="zookeeper://127.0.0.1:2181"/>
<!-- 注册 协议和port -->
<dubbo:protocol name="dubbo" port="20881"></dubbo:protocol>
<!-- 扫描指定包,加入@Service注解的类会被发布为服务 -->
<dubbo:annotation package="pers.fulsun.service.impl" />
</beans>

插件选择 tomcat7:run启动服务, 在 Zookeeper 查看

1
2
127.0.0.1:2181	$	ls /dubbo/pers.fulsun.service.HelloService/providers
[dubbo%3A%2F%2F192.168.1.5%3A20881%2Fpers.fulsun.service.HelloService%3Fanyhost%3Dtrue%26application%3Ddubbodemo_provider%26dubbo%3D2.6.0%26generic%3Dfalse%26interface%3Dpers.fulsun.service.HelloService%26methods%3DsayHello%26pid%3D1768%26side%3Dprovider%26timestamp%3D1686155530214]

服务消费方开发

创建 maven 工程(打包方式为 war)dubbodemo_consumer,pom.xml 配置和上面服务提供者相同,只需要将 Tomcat 插件的端口号改为 8082 即可。

配置 web.xml 文件

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
28
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:applicationContext*.xml</param-value>
</context-param>

<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext-web.xml</param-value>
</init-param>
</servlet>

<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>

将服务提供者工程中的 HelloService 接口复制到当前工程, 编写 Controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import com.alibaba.dubbo.config.annotation.Reference;

@RestController
@RequestMapping("/demo")
public class HelloController {

@Reference
private HelloService helloService;

@RequestMapping("/hello")
public String sayHello(String name){
//远程调用
String result = helloService.sayHello(name);
System.out.println(result);
return result;
}

}

在 src/main/resources 下创建 applicationContext-web.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">

<!-- 当前应用名称,用于注册中心计算应用间依赖关系,注意:消费者和提供者应用名不要一样 -->
<dubbo:application name="dubbodemo_consumer" />
<!-- 连接服务注册中心zookeeper ip为zookeeper所在服务器的ip地址-->
<dubbo:registry address="zookeeper://10.0.0.102:2181"/>
<!-- 扫描指定包,加入@Service注解的类会被发布为服务 -->
<dubbo:annotation package="com.lxs.controller"/>

</beans>

测试运行

运行测试 tomcat7:run 启动,先启动 provider 再启动 consumer 在浏览器输入 http://localhost:8082/demo/hello?name=huh , 查看浏览器输出结果

在 zookeeper 中查看

监控中心

什么是监控中心

  • dubbo 的使用,其实只需要有注册中心,消费者,提供者这三个就可以使用了,但是并不能看到有哪些消费者和提供者,为了更好的调试,发现问题,解决问题,因此引入 dubbo-admin。通过 dubbo-admin 可以对消费者和提供者进行管理。可以在 dubbo 应用部署做动态的调整,进行服务的管理。

  • dubbo-admin

    • 图形化的服务管理页面;安装时需要指定注册中心地址,即可从注册中心中获取到所有的提供者/消费者进行配置管理
  • dubbo-monitor-simple

    • 简单的监控中心;

发布配置中心(新版本)

  • 访问github 地址,下载即可

  • 解压dubbo-admin-0.6.0.zip, 修改 dubbo-admin-0.6.0\dubbo-admin-server\src\main\resources\application.properties 配置文件

    1
    2
    3
    4
    5
    server.port=38080
    admin.registry.address=zookeeper://127.0.0.1:2181
    dubbo.registry.address=${admin.registry.address}
    admin.root.user.name=root
    admin.root.user.password=root
  • 进入dubbo-admin-0.6.0 根目录下,使用命令 mvn clean package 进行clean 打包

    1
    mvn clean package -Dmaven.test.skip=true
  • 打包成功之后,将打好的jar包(只需dubbo-admin-server-0.3.0.jar)拷贝的指定目录,当然不拷贝也行,启动服务

    1
    java -jar dubbo-admin-server-0.3.0.jar
  • 启动浏览器输入:http://127.0.0.1:38080/

发布配置中心(旧版本)

  • 下载监控中心,https://github.com/apache/incubator-dubbo-ops,这里下载的是源代码,需要手工编译打包。

  • application.properties 文件,内容如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    server.port=7001
    spring.velocity.cache=false
    spring.velocity.charset=UTF-8
    spring.velocity.layout-url=/templates/default.vm
    spring.messages.fallback-to-system-locale=false
    spring.messages.basename=i18n/message
    spring.root.password=root
    spring.guest.password=guest

    dubbo.registry.address=zookeeper://127.0.0.1:2181
  • 运行 dubbo-admin 应用

    1. 先启动注册中心
    2. 执行提供者项目
    3. java -jar dubbo-admin-0.0.1-SNAPSHOT.jar 启动 dubbo 管理后台
    4. 在浏览器地址栏输入 http://localhost:7001 访问监控中心-控制台。