Dubbo的使用与基本知识点

Apache Dubbo

在这里插入图片描述

官网地址

Dubbo官网:

英文官网: https://dubbo.apache.org/en/
dubbo2.7英文官网:https://dubbo.apache.org/en/docs/v2.7/
Dubbo的使用与基本知识点_第1张图片

中文官网: https://dubbo.apache.org/zh/
Dubbo2.7版本中文官网: https://dubbo.apache.org/zh/docsv2.7/

Dubbo的使用与基本知识点_第2张图片

介绍

Apache Dubbo 是一款 RPC 服务开发框架,用于解决微服务架构下的服务治理与通信问题,官方提供了 Java、Golang 等多语言 SDK 实现。使用 Dubbo 开发的微服务原生具备相互之间的远程地址发现与通信能力, 利用 Dubbo 提供的丰富服务治理特性,可以实现诸如服务发现、负载均衡、流量调度等服务治理诉求。Dubbo 被设计为高度可扩展,用户可以方便的实现流量拦截、选址的各种定制逻辑。

在Dubbo2.x中需要解决的需求:

  1. 服务过多,服务URL配置管理贼困难,负载均衡器的单点压力大
  2. 服务间依赖极度复杂,整个应用架构关系让人头昏眼花
  3. 服务调用量很大,服务容量问题暴露,机器的数量,加机器的时间无法准确把控

于是乎,引出了dubbo的一个基本的架构:

Dubbo的使用与基本知识点_第3张图片

Dubbo 的几个特性:

健壮性

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

伸缩性

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

升级性

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

Dubbo的使用与基本知识点_第4张图片

节点 角色说明
Deployer 自动部署服务的本地代理
Repository 仓库用于存储服务应用发布包
Scheduler 调度中心基于访问压力自动增减服务提供者
Admin 统一管理控制台
Registry 服务注册与发现的注册中心
Monitor 统计服务的调用次数和调用时间的监控中心

注册中心: Zookeeper

在这里插入图片描述

下载地址: https://zookeeper.apache.org/releases.html#download

我的版本为: zookeeper3.7

下载好了就解压

它的目录如下:

Dubbo的使用与基本知识点_第5张图片

进入 /bin目录下

Dubbo的使用与基本知识点_第6张图片

以管理员身份运行zkServer.cmd (windows下) <= 我执行的是Windows平台下的

执行 bash ./zkServer.sh (linux下)

Dubbo的使用与基本知识点_第7张图片

至此看来,执行的是2181端口

原因是在/conf 目录下有一个zoo.cfg文件(如果没有就将zoo_sample.cfg复制一份,更名为zoo.cfg)

# The number of milliseconds of each tick
tickTime=2000 
# The number of ticks that the initial 
# synchronization phase can take
initLimit=10
# The number of ticks that can pass between 
# sending a request and getting an acknowledgement
syncLimit=5
# the directory where the snapshot is stored.
# do not use /tmp for storage, /tmp here is just 
# example sakes.
dataDir=H:/apache-zookeeper-3.7.0-bin/data
# the port at which the clients will connect
clientPort=2181
# the maximum number of client connections.
# increase this if you need to handle more clients
#maxClientCnxns=60
#
# Be sure to read the maintenance section of the 
# administrator guide before turning on autopurge.
#
# http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance
#
# The number of snapshots to retain in dataDir
#autopurge.snapRetainCount=3
# Purge task interval in hours
# Set to "0" to disable auto purge feature
#autopurge.purgeInterval=1

## Metrics Providers
#
# https://prometheus.io Metrics Exporter
#metricsProvider.className=org.apache.zookeeper.metrics.prometheus.PrometheusMetricsProvider
#metricsProvider.httpPort=7000
#metricsProvider.exportJvmInfo=true

其中的clientPort就是你当前服务的端口值,你改了之后启动的zookeeper端口就发生了改变

运行起来之后打开zkCli.cmd

Dubbo的使用与基本知识点_第8张图片

出现了[zk: localhost:2181(CONNECTED 0)] 则表示已经成功连接上了

Dubbo的使用与基本知识点_第9张图片
测试了一下,说明zookeeper的服务没有问题

注意

Dubbo 2.7.x之后变成了org.apache的顶级项目

原先的java包依赖由com.alibaba变成了org.apache

dubbo 3 与 springboot的整合

Provider服务提供

引入maven依赖

<dependencies>
    <dependency>
        <groupId>org.apache.dubbogroupId>
        <artifactId>dubboartifactId>
        <version>3.1version>
    dependency>
    <dependency>
        <groupId>org.apache.dubbogroupId>
        <artifactId>dubbo-dependencies-zookeeperartifactId>
        <version>3.1version>
        <type>pomtype>
    dependency>
    
    <dependency>
        <groupId>org.apache.curatorgroupId>
        <artifactId>curator-recipesartifactId>
    dependency>
    
    <dependency>
        <groupId>org.apache.curatorgroupId>
        <artifactId>curator-frameworkartifactId>
    dependency>
dependencies>

properties配置文件

dubbo.application.name=dubbo-provider  // dubbo服务应用名称
dubbo.registry.address=zookeeper://127.0.0.1:2181   // 注册中心
dubbo.protocol.port=20884  // dubbo协议端口 写上这个端口号是因为要和注册中心进行数据写入,需要提供指定dubbo服务端口号

定义服务接口

package com.xjk.dubbo.service;

/**
 * @author MSI-NB
 */
public interface DemoDubboService {
    public String test01(String param);
}

实现服务接口

package com.xjk.dubbo.service.impl;

import com.xjk.dubbo.service.DemoDubboService;
import org.apache.dubbo.config.annotation.Service;

/**
 * @author MSI-NB
 */

@Service  
public class DemoDubboServiceImpl implements DemoDubboService {
    @Override
    public String test01(String param) {
        return param+"6666";
    }
}

启动类上添加注解@EnableDubbo

package com.xjk;

import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @author Xjk
 */

@SpringBootApplication
@EnableDubbo  // 开启Dubbo
public class ProviderApplication {

    public static void main(String[] args) {
        SpringApplication.run(ProviderApplication.class,args);
    }
}

consumer服务消费

引入依赖配置

<dependency>
    <groupId>org.apache.dubbogroupId>
    <artifactId>dubbo-spring-boot-starterartifactId>
dependency>

<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-webartifactId>
dependency>

<dependency>
    <groupId>org.apache.curatorgroupId>
    <artifactId>curator-recipesartifactId>
dependency>

<dependency>
    <groupId>org.apache.curatorgroupId>
    <artifactId>curator-frameworkartifactId>
dependency>

Controller

package com.xjk.controller;

import com.xjk.service.DemoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * @author Xjk
 */

@Controller
public class DemoController {

    @Autowired
    private DemoService service;

    @RequestMapping("/demo")
    @ResponseBody
    public String demo(@RequestParam("n") String name){
        return service.test_consumer(name);
    }
}

properties配置文件

dubbo.application.name=demo-consumer
dubbo.registry.address=zookeeper://localhost:2181
server.port=8081

定义服务接口

package com.xjk.service;

public interface DemoService {

    String test_consumer(String param);

}

实现服务接口

package com.xjk.service.impl;

import com.xjk.dubbo.service.DemoDubboService;
import com.xjk.service.DemoService;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.stereotype.Service;

/**
 * @author Xjk
 */

@Service
public class DemoServiceImpl implements DemoService {

    @Reference
    private DemoDubboService demoDubboService;


    @Override
    public String test_consumer(String param) {
        return demoDubboService.test01("hahahah");
    }

}

远程服务调用的接口

package com.xjk.dubbo.service;

/**
 * @author MSI-NB
 */
public interface DemoDubboService {
    String test01(String param);
}

注意点:

  1. Consumer服务消费方的远程服务调用接口

    • Consumer服务消费方的远程服务调用接口 不等于 Consumer服务接口
    • consumer的服务接口的实现是在consumer中,而远程服务调用的接口实现是在provider服务提供方
    • consumer消费方的远程服务调用接口 要与 provider方定义的要提供的服务接口完全一致(包括方法,所在路径,类名… …)
  2. Provider中的注解

    • 在服务提供的接口实现类上的@Service是org.apache.dubbo.config.annotation.Service,不是spring.framework.stereotype

    • 但是不同版本的dubbo的注解有所变化:

      2.7.0 以前的版本 com.alibaba时期 :

      @Reference : com.alibaba.dubbo.config.annotation.Reference

      @Service : com.alibaba.dubbo.config.annotation.Service

      2.7.0~2.7.7 之间的版本

      @Reference : org.apache.dubbo.config.annotation.Reference

      @Service : org.apache.dubbo.config.annotation.Service

      2.7.7 之后的版本

      @DubboReference : org.apache.dubbo.config.annotation.DubboReference

      @DubboService : org.apache.dubbo.config.annotation.DubboService

Dubbo 集群

将Provider的启动类复制4份

每个在启动时修改propertis这个端口 => dubbo.protocol.port=20884

正如之前注释上写的这个端口与zookeeper做连接,所以相同的服务启动时将这个端口修改以模拟不同的服务器

当这四个都运行起来之后,就是相当于起了拥有4台机器的集群

在provider中的实现类中的方法添加一个print,用来观测consumer调用的是哪一个Provider机器

启动Consumer,通过consumer调用provider服务

如下便是我分别启动4个服务提供方和运行消费方执行后的情况,没有出现报错异常:
第一个:

第二个:

第三个:

第四个:

消费方和访问

访问后会发现不同的机器都能被访问到,那么说明集群确实已经搭建起来了~

负载均衡

仔细看了上面的provider中的yaml/properties会发现配置中出现了:

dubbo.provider.loadbalance=roundrobin

或者

dubbo:
	provider:
		loadbalance: roundrobin

这就是配置了集群的负载均衡策略

五种策略模式:

random: 随机(默认)

roundrobin: 轮询

leastactive: 最少活跃调用优先

shortestresponse: 最短响应优先

consistenthash: 一致性 Hash

Random

  • 加权随机,按权重设置随机概率。
  • 在一个截面上碰撞的概率高,但调用量越大分布越均匀,而且按概率使用权重后也比较均匀,有利于动态调整提供者权重。
  • 缺点:存在慢的提供者累积请求的问题,比如:第二台机器很慢,但没挂,当请求调到第二台时就卡在那,久而久之,所有请求都卡在调到第二台上。

RoundRobin

  • 加权轮询,按公约后的权重设置轮询比率,循环调用节点
  • 缺点:同样存在慢的提供者累积请求的问题。

加权轮询过程过程中,如果某节点权重过大,会存在某段时间内调用过于集中的问题。
例如 ABC 三节点有如下权重:{A: 3, B: 2, C: 1}
那么按照最原始的轮询算法,调用过程将变成:A A A B B C

对此,Dubbo 借鉴 Nginx 的平滑加权轮询算法,对此做了优化,调用过程可抽象成下表:

轮前加和权重 本轮胜者 合计权重 轮后权重(胜者减去合计权重)
起始轮 \ \ A(0), B(0), C(0)
A(3), B(2), C(1) A 6 A(-3), B(2), C(1)
A(0), B(4), C(2) B 6 A(0), B(-2), C(2)
A(3), B(0), C(3) A 6 A(-3), B(0), C(3)
A(0), B(2), C(4) C 6 A(0), B(2), C(-2)
A(3), B(4), C(-1) B 6 A(3), B(-2), C(-1)
A(6), B(0), C(0) A 6 A(0), B(0), C(0)

我们发现经过合计权重(3+2+1)轮次后,循环又回到了起点,整个过程中节点流量是平滑的,且哪怕在很短的时间周期内,概率都是按期望分布的。

如果用户有加权轮询的需求,可放心使用该算法。

LeastActive

  • 加权最少活跃调用优先,活跃数越低,越优先调用,相同活跃数的进行加权随机。活跃数指调用前后计数差(针对特定提供者:请求发送数 - 响应返回数),表示特定提供者的任务堆积量,活跃数越低,代表该提供者处理能力越强。
  • 使慢的提供者收到更少请求,因为越慢的提供者的调用前后计数差会越大;相对的,处理能力越强的节点,处理更多的请求。

ShortestResponse

  • 加权最短响应优先,在最近一个滑动窗口中,响应时间越短,越优先调用。相同响应时间的进行加权随机。
  • 使得响应时间越快的提供者,处理更多的请求。
  • 缺点:可能会造成流量过于集中于高性能节点的问题。

这里的响应时间 = 某个提供者在窗口时间内的平均响应时间,窗口时间默认是 30s。

ConsistentHash

  • 一致性 Hash,相同参数的请求总是发到同一提供者。
  • 当某一台提供者挂时,原本发往该提供者的请求,基于虚拟节点,平摊到其它提供者,不会引起剧烈变动。
  • 算法参见:Consistent Hashing | WIKIPEDIA
  • 默认只对第一个参数 Hash,如果要修改,请配置
  • 默认用 160 份虚拟节点,如果要修改,请配置

集群容错

Dubbo的使用与基本知识点_第10张图片

在服务提供方出现了问题的时候就需要通过多种容错方案解决这个问题

在服务消费方的@Reference(cluster=“填写方案”)

  • failover: 失败自动切换,当出现失败,重试其它服务器。通常用于读操作,但重试会带来更长延迟。可通过 retries=“2” 来设置重试次数(不含第一次)。

  • failfast: 快速失败,只发起一次调用,失败立即报错。通常用于非幂等性的写操作,比如新增记录。

  • failsafe: 失败安全,出现异常时,直接忽略。通常用于写入审计日志等操作。

  • failback: 失败自动恢复,后台记录失败请求,定时重发。通常用于消息通知操作。

  • forking: 并行调用多个服务器,只要一个成功即返回。通常用于实时性要求较高的读操作,但需要浪费更多服务资源。可通过 forks=“2” 来设置最大并行数。

  • broadcast: 广播调用所有提供者,逐个调用,任意一台报错则报错。通常用于通知所有提供者更新缓存或日志等本地资源信息。

  • available: 调用目前可用的实例(只调用一个),如果当前没有可用的实例,则抛出异常。通常用于不需要负载均衡的场景。

  • mergeable: 将集群中的调用结果聚合起来返回结果,通常和group一起配合使用。

你可能感兴趣的:(java,dubbo,java,分布式)