Springboot调用Dubbo服务实践

2021-08-12 10:53:20 浏览数 (1)

Springboot整合Dubbo

  • 一 .介绍
    • 背景
    • 什么是Dubbo和Zookeeper
  • 二. 调用实例搭建与测试
    • 框架搭建
      • 父项目
      • api模块
      • provider模块
      • consumer模块
    • 访问测试
  • 三 监控与管理
    • Dubbo Monitor
    • Dubbo Admin
  • 四 Dubbo 配置负载均衡
    • 什么是负载均衡
    • Dubbo 的内置负载均衡策略
      • Random (随机)
      • RoundRobin (轮询)
      • LeastActive (最少活跃)
      • ConsistentHash (一致性哈希)
    • 负载均衡测试案例搭建
      • 项目多启动修改
      • 指定负载均衡策略
        • 1. Consumer 注解配置
        • 2. Consumer配置文件配置
        • 3. Provider 注解配置
        • 4. Provider 配置文件配置
      • 指定权重配置
        • 1. 轮询策略配置权重
        • 2. 随机策略配置权重
  • 五 项目打包
    • 基于 SpringBoot 整合 Dubbo 的打包方式
    • 基于 Assembly 插件打包

一 .介绍

该博文所用到的所有软件包将会在底部以百度云形式分享

背景

在微服务/SpringCloud项目中, 我们通常会用到注册中心来注册服务和发布服务, 例如SpringCloud Netflix的 Eureka 和SpringCloud Alibaba的Nacos. 我们暂且不论他们的优劣, 而是来讨论另一个同样重要的问题 : 在单体架构或者soa(面向服务架构)的项目甚至是SpringBoot项目中我们该如何实现服务的发布和消费呢 —— 使用Dubbo zookeeper, 作为注册中心来实现服务的注册和发布

什么是Dubbo和Zookeeper

  1. Dubbo

Dobbo技术, 他是一个高性能的服务框架 ,用于实现服务的输入和输出(服务注册和服务发现)。 它是基于面向服务的架构(SOA)与远程过程调用(RPC)的技术而研发的.

注意这里的dubbo只是一个框架,至于你架子上放什么是完全取决于你的,就像一个汽车骨架,你需要配你的轮子引擎。这个框架中要完成调度必须要有一个分布式的注册中心,储存所有服务的元数据,你可以用zk(zookeeper),也可以用别的, 但是官方推荐用zk。关于dubbo介绍

  1. Zookeeper

zookeeper技术, 它是一种分布式的开源的程序协调服务 .它的存储结构是树形结构, 包含四种类型的节点:持久化节点, 持久化顺序节点,临时节点和临时编号节点. 它的主要作用分为 :配置管理,名字服务,分布式锁与集群管理等

zookeeper用来注册服务和进行负载均衡,哪一个服务由哪一个机器来提供必需让调用者知道,简单来说就是ip地址和服务名称的对应关系。 zookeeper通过心跳机制可以检测挂掉的机器并将挂掉机器的ip和服务对应关系从列表中删除。至于支持高并发,简单来说就是横向扩展,在不更改代码 的情况通过添加机器来提高运算能力。通过添加新的机器向zookeeper注册服务,服务的提供者多了能服务的客户就多了。 关于zk介绍

  1. zookeeper和dubbo的关系
  • Dubbo的将注册中心进行抽象,使得它可以外接不同的存储媒介给注册中心提供服务,有ZooKeeper,Memcached,Redis等。
  • 引入了ZooKeeper作为存储媒介,也就把ZooKeeper的特性引进来。 首先是负载均衡,单注册中心的承载能力是有限的,在流量达到一定程度的时 候就需要分流,负载均衡就是为了分流而存在的,一个ZooKeeper群配合相应的Web应用就可以很容易达到负载均衡; 其次是资源同步,单单有负载均衡还不够,节点之间的数据和资源需要同步,ZooKeeper集群就天然具备有这样的功能; 命名服务,将树状结构用于维护全局的服务地址列表,服务提供者在启动 的时候,向ZK上的指定节点/dubbo/${serviceName}/providers目录下写入自己的URL地址,这个操作就完成了服务的发布。 其他特性还有Mast选举,分布式锁等。
  • 注意: 一般使用dubbo都会使用zookeeper的, 因为zk集群能为我们提供服务的动态发布和集群间的负载均衡以及集群横向扩展等功能

二. 调用实例搭建与测试

代码地址 : https://gitee.com/TimePause/springboot_dubbo_project

项目整体结构

框架搭建

如果直接使用gitee上面的代码, 需要 1. 手动创建父项目(空目录即可) 2. 然后点击右上角 File ->Project Structure -> 点击 -> Import Modules-> 添加api,provider,consumer模块

父项目

父项目(springboot-dubbo), 可以创建pom项目用于对jar进行管理, 也可以新建一个空项目/空目录, 在空目录下创建子模块项目. 这里是直接创建空的父项目

  • 步骤1: 退出原有项目: File->close project, 进入图1页面
  • 步骤2: 创建空的父项目: 点击Create New Project->选择Empty Project(图2)-> 填入项目名和目录地址

图1

图2

api模块

api模块(springboot-dubbo-api)作用规定服务接口样式, 用于其他模块实现和重写

步骤:

provider模块

provider模块(springboot-dubbo-provider)的作用是用于创建用于注册和发布的服务

步骤:

注意: 需要我们注意 dubbo.scan.base-packages 这个参数, 用于扫描服务接口实现类所在包地址. 我们要根据自己实际情况来配置

consumer模块

consumer模块(springboot-dubbo-consumer)用于消费Ddubbo服务

步骤:

访问测试

浏览器输入下面url进行访问

代码语言:javascript复制
http://localhost:8080/getMsg/我成功啦

页面反馈访问结果如下图, 说明服务消费者消费发布的服务成功!!!


三 监控与管理

Dubbo Monitor

Dubbo Admin为Dubbo框架监控提供了一个图形化界面, 方便我们对Dubbo进行监控 主要功能包括: 监控注册的服务, 注册中心, 日志, 软件运行环境等信息

使用步骤

Dubbo Monitor主页功能展示

Menu Name

Menu Desc

Home

主页, 显示所有功能列表(图1)

Applications

显示dubbo服务角色关系(提供者, 消费者, 依赖情况, 使用情况), 图2

Services

显示注册中心注册的服务(图3)

Hosts

显示提供者和消费者所在主机及相关信息(图4)

Registries

显示注册中心状态和注册服务信息(图5)

Servers

显示导出的业务服务器(图6)

Status

显示系统状态(图7)

Log

显示Dubbo Admin日志(图8)

System

显示系统环境信息(图9)

图1

图2

图3

图4

图5

图6

图7

图9

Dubbo Admin

Dubbo Admin为Dubbo框架管理提供了一个图形化界面, 方便我们对Dubbo进行管理 其主要功能包含:路由规则、动态配置、服务降级、访问控制、权重调整、负载均衡等管理功能。

使用步骤

  1. 修改配置文件 修改连接zk/zk集群地址以及dubbo admin图形化界面端口 修改后保存即可生效, 如果保存失败了, 建议重启电脑
  1. 打开cmd, 然后输入你所在的盘跳转到文件所在盘 eg: d: , 在通过cd 文件所在目录 跳转到该jar目录, 最后通过java -jar dubbo-admin-server.jar 运行(也可上传至linux服务器上通过java -jar运行)
  2. 访问 dubbo admin实际上是一个SpringBoot打包后的jar 因此访问的端口取决与是否在第1步修改了其访问端口, 如果没有修改默认为 8080, 如果按照第1步的配置, 则访问的地址为: http://localhost:9999/ (默认以中文显示,通俗易懂)

四 Dubbo 配置负载均衡

什么是负载均衡

负载均衡(Load Balance),是指将负载(工作任务,访问请求)进行平衡、分摊到多个操作单元(服务器,组件)上进行执行。

最常见的负载均衡场景

  • 常见场景是我们在网站上下载某软件时, 为我们提供的各种下载通道 负载依赖用户手动选择下载通道. 这一种古老的方式,通过入口提供不同线路、不同服务器链接的方式,来实现负载均衡
  • 各种软件或者框架中配置 Nginx 负载均衡, Dubbo负载均衡, SpringCloud Ribbon,Feign调用时的负载均衡, Dubbo Spring Cloud配置负载均衡, emq 消息队列配置消息消费的负载均衡

注意: Dubbo Spring Cloud 构建在原生的 Spring Cloud 之上,其服务治理方面的能力可 认为是 Spring Cloud Plus,不仅完全覆盖 Spring Cloud 原生特性,而且提供更为稳定和成熟 的实现

负载均衡解决方案分类及特征

  • 集中式负载均衡 即在客户端和服务端之间使用独立的负载均衡设施(可以是硬件,如 F5, 也可以是软件, 如 nginx), 由该设施负责把访问请求通过某种策略转发至服务端
  • 进程内负载均衡 将负载均衡逻辑集成到服务组件中,服务组件从服务注册中心获知有哪些地址可用,然后根据指定的负载均衡策略选择出一个合适的服务来调用。

集中式负载均衡方式

  • 基于硬件的负载均衡 硬件负载均衡解决方案是直接在服务器和外部网络间安装负载均衡设备,这种设备通常称之为负载均衡器,由专门的设备完成专门的任务,独立于操作系统,整体性能得到大大提高,加上多样化的负载均衡策略,智能化的流量管理,可达到最佳的负载均衡需求。 常见的主流产品: F5 BIG-IP 负载均衡器(LTM),思科 IOS 路由器以及Radware 的 AppDirector 系列
  • DNS 轮询 大多域名注册商都支持 DNS 轮询,DNS 服务器将解析请求按照配置顺序,逐一分配到不同的 IP 上,这样就完成了简单的负载均衡。
  • 反向代理负载均衡 使用代理服务器,可以将请求转发给内部的服务器。Nginx 是比较常见的服务反向代理 技术。在 Nginx 中是支持对代理的服务的负载均衡处理的

进程内负载均衡方式

  • 基于注册中心 / 消息队列的集中式负载均衡 将负载均衡逻辑集成到服务组件中,服务组件从服务注册中心获知有哪些地址可用,然 后根据指定的负载均衡策略选择出一个合适的服务来调用

Dubbo 的内置负载均衡策略

需要注意的是, 在后续进行配置时, 配置的策略名称就是下面的标题名称, 但是要注意的是在填写dubbo配置参数时所有字母都要小写

Random (随机)

随机访问集群中节点。访问概率和权重有关。是 Dubbo 的默认负载均衡策略。 权重(weight):占有比例。集群中每个项目部署的服务器的性能可能是不同,性能好的服务器权重应该高一些

RoundRobin (轮询)

访问频率和权重有关, 如果未配置权重, 则访问则是一一访问

LeastActive (最少活跃)

最少活跃调用数,相同活跃数的随机。 如果某个机器性能越差,那么接收的请求越少,越不活跃,此时就会给不活跃的性能差的机器分配更少的请求

ConsistentHash (一致性哈希)

一致性 Hash 算法,相同参数的请求一定分发到同一个 Provider 如果需要某一类请求都到一个节点,那么可以使用一致性 Hash 策略

负载均衡测试案例搭建

在基于第二章的基础上进行配置, 添加多个服务提供者, 并且在每个服务上面添加标记然后启动, 通过多次访问消费者接口来进行消费和测试 代码地址 : https://gitee.com/TimePause/springboot_dubbo_project

项目多启动修改

  1. 为了能够让idea能够启动多个服务提供者项目, 需要修改idea的启动配置
  1. 复制启动配置 复制后修改启动项名称, 这里复制了两个 SpringbootDubboProviderApplication-2, SpringbootDubboProviderApplication-3
  1. 修改复制后的启动配置 需要注意的是, 原有的无需配置, 二在复制后的配置中, 需要重新配置连接的dubbo端口–dubbo.protocol.port=20881 , --dubbo.protocol.port=20882 如果是多个参数, 中间以空格隔开, eg: --server.port=8082 --dubbo.protocol.port=20882
  1. 在编辑好启动项参数后, 依次进行启动 但是在启动时, 为了我们能够区分消费者到底消费的是哪个服务, 我们需要在提供的服务接口上面打印一句话. 每次启动一个服务前就修改下打印的内容
  1. 启动服务消费者, 进行访问测试 在浏览器多次刷新服务消费者接口http://localhost:8080/getMsg/testLoadBalance 可以看到每个服务的负载情况(因为没有配置, 默认策略为随机, 当次数足够多时, 最终访问的频率会趋向于一致)

指定负载均衡策略

1. Consumer 注解配置

除非配置权重, 否则无需向provider配置其他参数即可使策略生效

随机策略配置 在provider项目的@Reference注解中添加loadbalance 参数, 指定负载均衡参数@Reference(loadbalance = "random ")

代码语言:javascript复制
package com.njhrt.consumer.service.impl;

import com.njhrt.service.ProviderService;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.stereotype.Service;

/**
 * 消费服务业务层
 * 注意: 这里@Service 导入的是springframework的包而不是Dubbo
 * 区别:
 *     服务提供者(provider): @Service使用的是dubbo包下的
 *     服务消费者(consumer): @Service使用的是springframework包下的
 * @author caohaiyang
 */
@Service
public class ConsumerServiceImpl implements ProviderService {

    /**
     * 使用的是dubbo包下的@Reference
     *      dubbo服务级别
     *         1. 权重随机算法的 RandomLoadBalance、
     *         2. 基于最少活跃调用数算法的 LeastActiveLoadBalance、
     *         3. 基于 hash 一致性的 ConsistentHashLoadBalance,
     *         4. 以及基于加权轮询算法的 RoundRobinLoadBalance。
     * 对应负载均衡策略参数: random,leastactive,consistenthash,roundrobin
     */
    @Reference(loadbalance = "random ")
    private ProviderService providerService;

    @Override
    public String showMsg(String msg) {
        return this.providerService.showMsg(msg);
    }

}

轮询策略配置

在provider项目的@Reference注解中添加loadbalance 参数, 指定负载均衡参数@Reference(loadbalance = "roundrobin")

代码语言:javascript复制
package com.njhrt.consumer.service.impl;

import com.njhrt.service.ProviderService;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.stereotype.Service;

/**
 * 消费服务业务层
 * 注意: 这里@Service 导入的是springframework的包而不是Dubbo
 * 区别:
 *     服务提供者(provider): @Service使用的是dubbo包下的
 *     服务消费者(consumer): @Service使用的是springframework包下的
 * @author caohaiyang
 */
@Service
public class ConsumerServiceImpl implements ProviderService {

    /**
     * 使用的是dubbo包下的@Reference
     *      dubbo服务级别
     *         1. 权重随机算法的 RandomLoadBalance、
     *         2. 基于最少活跃调用数算法的 LeastActiveLoadBalance、
     *         3. 基于 hash 一致性的 ConsistentHashLoadBalance,
     *         4. 以及基于加权轮询算法的 RoundRobinLoadBalance。
     * 对应负载均衡策略参数: random,leastactive,consistenthash,roundrobin
     */
    @Reference(loadbalance = "roundrobin")
    private ProviderService providerService;

    @Override
    public String showMsg(String msg) {
        return this.providerService.showMsg(msg);
    }

}
2. Consumer配置文件配置

除非配置权重, 否则无需向provider配置其他参数即可使策略生效

在 SpringBoot 的配置文件中可以配置全局的负载均衡。Consumer 中所有调用 Provider 集群的业务层都会使用该负载均衡策略。

与注解配置方式区别:

  • 注解配置方式: 局部,只针对当前业务层生效。
  • 配置文件方式: 全局,对所有业务层生效。
  • 全局配置(配置文件)的优先级低于局部配置(注解配置 )
代码语言:javascript复制
#配置负载均衡策略  random, roundrobin, leastactive, consistenthash
dubbo.consumer.loadbalance=random 
代码语言:javascript复制
#配置负载均衡策略  random, roundrobin, leastactive, consistenthash
dubbo.consumer.loadbalance=roundrobin
3. Provider 注解配置

在Provider配置负载均衡策略之后, Consumer也无需配置负载策略即可使策略生效

在 Provider的@Service 注解中配置负载均衡策略, 如需配置权重, 直接在注解后配置即可 @Service(loadbalance = "random",weight = 4)

代码语言:javascript复制
@Service(loadbalance = "random")
public class ProviderServiceImpl implements ProviderService {

    @Override
    public String showMsg(String msg) {
        //System.out.println("调用测试duboo负载均衡服务1");
        //System.out.println("调用测试duboo负载均衡服务2");
        System.out.println("调用测试duboo负载均衡服务3");
        return "hello springboot duboo! " msg;
    }
4. Provider 配置文件配置

在Provider配置负载均衡策略之后, Consumer也无需配置负载策略即可使策略生效

直接在SpringBoot的配置文件application.properties中配置

代码语言:javascript复制
#全局配置(配置文件)的优先级低于局部配置(注解配置)
dubbo.provider.loadbalance=.loadbalance=roundrobin
dubbo.provider.weight=2

指定权重配置

这里使用的是 Provider 注解配置的权重, 当然我们也可以使用 Provider 配置文件配置权重

1. 轮询策略配置权重

如果我们将等量的请求分配给性能较差的服务器,这显然是不合理的。因此,这个时候我们需要对轮询过程进行加权,以调控每台服务器的负载。经过加权后,每台服务器能够得到的请求数比例,接近或等于他们的权重比

配置方式

通过 Provider 的@Service 注解配置权重 @Service(weight = 权重数)

代码语言:javascript复制
@Service(weight = 4)
public class ProviderServiceImpl implements ProviderService {

    @Override
    public String showMsg(String msg) {
        //System.out.println("调用测试duboo负载均衡服务1");
        //System.out.println("调用测试duboo负载均衡服务2");
        System.out.println("调用测试duboo负载均衡服务3");
        return "hello springboot duboo! " msg;
    }
}
2. 随机策略配置权重

随机获取一个[0, totalWeight)之间的数, offset = offset - weight,如果 offset 小于 0,则选中. 很明显 weight 大的更容易让 offset 的值小于 0。 举个例子 有 4 权重分别为(1,2, 3, 4), totalWeight = 10, 假如 offset = 6, 6 - 1 = 5, 5 大于 0, 继续 5 - 2 = 3 大于 0,3 - 3 = 0, 0 - 4 小于 0 ,所以选择权重为 4 的 invoker, 这里可以发现只要 offset >= 6 则选择权重为 4 的 invoker, 正好是 40%。 权重的值是可以随便配置的, 系统会自动计算权重和

配置方式

通过 Provider 的@Service 注解配置权重 @Service(weight = 权重数)

代码语言:javascript复制
@Service(weight = 4)
public class ProviderServiceImpl implements ProviderService {

    @Override
    public String showMsg(String msg) {
        //System.out.println("调用测试duboo负载均衡服务1");
        //System.out.println("调用测试duboo负载均衡服务2");
        System.out.println("调用测试duboo负载均衡服务3");
        return "hello springboot duboo! " msg;
    }
}

五 项目打包

在项目打包时, 需要明确:

  1. SpringBoot项目中, 可以使用其自带的打包插件进行打包
  2. 在基于Maven或者是Maven Spring项目中, 需要手动添加Assembly进行打包

基于 SpringBoot 整合 Dubbo 的打包方式

基于 Assembly 插件打包

Assembly 插件 Assembly是Maven打包插件,他的作用是可以帮助我们对jar项目做打包处理。 在Spring 整合 dubbo 的项目中,需要使用 Assembly 打包插件来对项目做打包处理。

打包步骤


麻烦看到这里动手点点赞吧! 你们的点赞是我继续下去的动力~~~

链接:https://pan.baidu.com/s/1CNDFJWaMtHjYL1FjzRfEew 提取码:pg4l 复制这段内容后打开百度网盘手机App,操作更方便哦–来自百度网盘超级会员V4的分享

0 人点赞