SpringBoot整合Dubbo & Zookeeper

1、环境准备

(1)软件下载

链接:https://pan.baidu.com/s/1z8ehuDRX7A85jj6AyMA-rg 
提取码:hs3s 

(2)软件启动

cd ~/software/zookeeper-3.4.11/bin 目录
双击运行 zkServer.cmd 即可启动zk
双击运行 zkCli.cmd 可进入zk客户端,对zk进行操作

cd ~/software 目录
打开cmd窗口,使用jar -jar dubbo-admin-0.0.1-SNAPSHOT.jar 命令运行dubbo网页监控
在浏览器 http://127.0.0.1:7001/即可访问,账号:root 密码:root

2、整合步骤

(1)父工程

新建maven项目
在这里插入图片描述

(2)服务提供者

在maven项目下新建module
在这里插入图片描述
新建的module要选择为SpringBoot工程,输入如下信息
!](https://img-blog.csdnimg.cn/20210518212912763.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2ODExMTYw,size_16,color_FFFFFF,t_70)

在父工程的pom文件中引入子工程

<modules>
    <module>dubbo-base</module>
</modules>

在父工程中新建一个接口
在这里插入图片描述
在服务提供者中引入依赖

<dependency>
			<groupId>com.hpu</groupId>
			<artifactId>dubbo-base</artifactId>
			<version>0.0.1-SNAPSHOT</version>
		</dependency>

		<dependency>
			<groupId>com.alibaba.boot</groupId>
			<artifactId>dubbo-spring-boot-starter</artifactId>
			<version>0.2.0</version>
		</dependency>

增加配置信息

#当前服务/应用的名字
dubbo.application.name=user-service-provider
#注册中心的协议和地址
dubbo.registry.protocol=zookeeper
dubbo.registry.address=127.0.0.1:2181
#通信规则(通信协议和接口)
dubbo.protocol.name=dubbo
dubbo.protocol.port=20880
#连接监控中心
dubbo.monitor.protocol=registry

开启dubbo

@SpringBootApplication
@EnableDubbo
public class DubboProviderApplication {

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

}

实现dubbo-base的方法,注意:这里的@service来自于import com.alibaba.dubbo.config.annotation.Service;

@Service
public class HelloDubboImpl implements HelloDubbo {
    @Override
    public String test() {
        return "hello dubbo!";
    }
}

启动测试,看到如下信息就代表成功了
在这里插入图片描述

(3)服务消费者

同样方式创建 Springboot项目

实现dubbo-base中定义的接口,这里的@Service注解是import org.springframework.stereotype.Service

@Service
public class ConsumerImpl implements HelloDubboService{

    @Reference
    private HelloDubboService helloDubboService;

    @Override
    public String test(){
        return helloDubboService.test();
    }

}

引入依赖

<dependency>
			<groupId>com.hpu</groupId>
			<artifactId>dubbo-base</artifactId>
			<version>0.0.1-SNAPSHOT</version>
		</dependency>

		<dependency>
			<groupId>com.alibaba.boot</groupId>
			<artifactId>dubbo-spring-boot-starter</artifactId>
			<version>0.2.0</version>
		</dependency>

添加配置

server.port=8081

dubbo.application.name=order-service-consumer
dubbo.registry.address=zookeeper://127.0.0.1:2181
dubbo.monitor.protocol=registry

在主启动类中添加注解

@SpringBootApplication
@EnableDubbo
public class DubboConsumerApplication {

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

}

启动服务消费者
在这里插入图片描述

浏览器上测试一下,成功!
在这里插入图片描述

在dubbo控制台同样可以看到
在这里插入图片描述

3、使用细节

  • 启动时检查

Dubbo消费者在启动时会检查服务提供者所提供的服务是否可用,默认为True

基于注解配置方式:

@Reference(check = false)
UserService userService;

基于配置方式(通过SpringBoot配置文件):

dubbo.consumer.check=false

上面的定义都是全局的,也可以单独定义对某一个服务提供者不检查

  • 服务超时

整体优先级是:服务提供者 < 服务消费者,全局配置 < 接口配置 < 方法配置(dubbo中其他配置同样遵循这个原则
基于注解的方式:

@Reference(timeout = 3000)

基于配置的方式:

dubbo.consumer.timeout=3000

测试的时候可以在提供者中设置线程睡眠5秒钟,消费者超时时间设置为3秒,就可以看到超时效果了

  • 重试机制

同样是两种配置方式

dubbo.consumer.retries=3
@Reference(retries = 3)
private HelloDubboService helloDubboService;
  • 多版本(灰度发布)

当一个接口实现,出现不兼容升级时,可以用版本号过度,版本号不同的服务之间互不引用。比如服务提供者中一个接口有两个实现,一个新版本,一个老版本。版本号在 @service注解 上可以通过version进行指定,然后在消费者 @Reference 指定要调用的版本即可。

提供者

@Service(version = "2.0.0")
public class ProviderImpl implements HelloDubboService {
    @Override
    public String test() throws InterruptedException {
        System.out.println("我是新版本...........");
        return "hello dubbo!";
    }
}
@Service(version = "1.0.0")
public class ProviderImpl implements HelloDubboService {
    @Override
    public String test() throws InterruptedException {
        System.out.println("我是老版本...........");
        return "hello dubbo!";
    }
}

消费者

@Service
public class ConsumerImpl implements HelloDubboService{

    @Reference(check = false,timeout = 2000,retries = 3,version = "1.0.0")
    private HelloDubboService helloDubboService;

    @Override
    public String test() throws InterruptedException {

        return helloDubboService.test();
    }

}

注意:@Reference(version = “*”)代表随机选择新老版本接口

  • 本地存根

远程服务后,客户端通常只剩下接口,而实现全在服务器端,但是提供方有些时候想在客户端也执行部分逻辑,比如:参数校验、调用失败后伪造容错数据等,此时就可以通过本地缓存来实现。

在服务消费者中定义本地缓存代码,实现某个接口,添加构造函数

public class ConsumerStub implements HelloDubboService {

    private final HelloDubboService helloDubboService;

    public ConsumerStub(HelloDubboService helloDubboService) {
        super();
        this.helloDubboService = helloDubboService;
    }

    @Override
    public String test() throws InterruptedException {
        // 这里可以进行一些条件判断
        if (true){
            System.out.println("调用了本地存根代码......");
            return helloDubboService.test();
        }
        return null;
    }
}

@Reference 指定本地缓存代码位置即可

@Reference(version = "1.0.0",stub = "com.hpu.dubboconsumer.service.ConsumerStub")

4、面试问题

(1)高可用

  • zookeeper宕机

现象:zookeeper注册中心宕机,还可以消费dubbo暴露的服务
1、监控中心宕机不影响使用,只是丢失部分采样数据
2、数据库宕机后,注册中心仍能通过缓存提供服务,但不能注册新服务
3、注册中心对等集群,任意一台宕机后,将自动切换到另外一台
4、注册中心全部宕机后,服务提供者和消费者仍能通过本地缓存通信
5、服务提供者无状态,任意一台宕机后,不影响使用
6、服务提供者全部宕机后,服务消费者将无法使用,并无线重连等待服务恢复

  • dubbo直连

在没有注册中心的情况下,服务消费者依然能够通过直连的方式调用服务提供者

@Reference(check = false,timeout = 2000,retries = 3,version = "1.0.0",url = "127.0.0.1:20880")

(2)负载均衡

在集群负载均衡时,Dubbo 提供了多种均衡策略,缺省为 random 随机调用。

负载均衡策略:

  • Random LoadBalance(基于权重的随机负载均衡机制)

随机,按权重设置随机概率。
在一个截面上碰撞的概率高,但调用量越大分布越均匀,而且按概率使用权重后也比较均匀,有利于动态调整提供者权重。
在这里插入图片描述

  • RoundRobin LoadBalance(基于权重的轮训负载均衡机制)

轮询,按公约后的权重设置轮询比率。
存在慢的提供者累积请求的问题,比如:第二台机器很慢,但没挂,当请求调到第二台时就卡在那,久而久之,所有请求都卡在调到第二台上。
在这里插入图片描述

  • LeastActive LoadBalance(最少活跃数负载均衡机制)

最少活跃调用数,相同活跃数的随机,活跃数指调用前后计数差。
使慢的提供者收到更少请求,因为越慢的提供者的调用前后计数差会越大。
在这里插入图片描述

  • ConsistentHash LoadBalance(一致性哈希负载均衡机制)

一致性 Hash,相同参数的请求总是发到同一提供者。
当某一台提供者挂时,原本发往该提供者的请求,基于虚拟节点,平摊到其它提供者,不会引起剧烈变动。
在这里插入图片描述
配置消费端负载均衡策略,此时为随机调用,在admin控制台可以调整权重

@Service
public class ConsumerImpl implements HelloDubboService{

    @Reference(version = "1.0.0",loadbalance = "random")
    private HelloDubboService helloDubboService;

    @Override
    public String test() throws InterruptedException {

        return helloDubboService.test();
    }

}

在这里插入图片描述

(3)服务降级

当服务器压力剧增的请款下,根据实际业务情况及流量,对一些服务和页面有策略的不处理或换种简单的方式处理,从而释放服务器资源以保证服务正常运行。

其中,mock=force:return + null表示消费方 对该服务的方法调用都直接返回null值,不发起远程调用,用来屏蔽不重要服务不可用是对调用放的影响。
在这里插入图片描述

还可以改为mock:fail:return+null表示消费方对该服务的方法调用失败后,再返回null,不抛异常,用来容忍不重要服务部稳定是对调用放的影响。
在这里插入图片描述

(4)集群容错(整合hystrix)

服务提供者中加入依赖

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
            <version>2.2.1.RELEASE</version>
        </dependency>

启动类上加入注解

@SpringBootApplication
@EnableDubbo
@EnableHystrix
public class DubboProviderApplication {
    public static void main(String[] args) {
        SpringApplication.run(DubboProviderApplication.class, args);
    }
}

在service实现类中加入注解

@Service(version = "1.0.0")
public class ProviderImpl implements HelloDubboService {

    @HystrixCommand
    @Override
    public String test() throws InterruptedException {
        System.out.println("我是老版本...........");
        if (true){
            throw new RuntimeException();
        }
        return "hello dubbo!";
    }
}

服务消费者中同样加入相关的依赖和注解

在调用的方法上加上注解和调用失败要回调的方法即可

@Service
public class ConsumerImpl implements HelloDubboService{

    @Reference(version = "1.0.0",timeout = 1000)
    private HelloDubboService helloDubboService;

    @Override
    @HystrixCommand(fallbackMethod = "hello")
    public String test() throws InterruptedException {

        return helloDubboService.test();
    }
    
    public String hello(){
        return "调用失败了,调用了回调方法";
    }
}

(5)RPC

RPC是指远程过程调用,是一种进程间通信方式,它是一种技术思想,而不是规范。他允许程序调用另一个地址空间的过程或函数,而不是程序员显式编码这个远程调用的细节,即程序员无论是调用本地还是远程的函数,本质上编写的调用代码基本相同。
在这里插入图片描述
RPC重点:socket通信和序列化效率

(6)Netty

(7)Dubbo原理

(8)dubbo服务暴露

对接口的实现类增加@Service注解,即可暴露服务,@service里面包含了@EnableDubbConfig和@DubboComponetScan,@EnableDubbConfig是开启dubbo相关配置的,绑定相关属性的,@DubboComponetScan是扫描相关组件并处理dubbo相关注解(@service、@reference)。postProcessBeanDefinitionRegistry实现了@Service注解的扫描,并作为ServiceBean注册进Spring容器中。具体的暴露行为是在ServiceConfig#doExportUrls中实现的,大致流程为:
1、先本地服务暴露,这样到会如果有本地调用,直接从本地服务调用即可,不必发起远程调用;
2、所有真实对象调用都是委托给代理,通过代理创建Invoker对象来实现调用;
3、服务暴露时会根据具体的协议执行相应的操作;

参考地址

配置中一些参数的问题:
1、token配置:保证注册中心的授权功能有效,如果使用点对点调用,需关闭令牌功能
2、本地服务的解析:在默认情况下,Dubbo同时支持本地导出和远程协议导出,我们可以通过ServiceConfig的setScope方法进行配置,为none表示不导出服务,为 remote 表示只导出远程服务,为local表示只导出本地服务。
3、ConfiguratorFactory 的解析:根据当前协议类型来获取到 SPI 接口 ConfiguratorFactory 的实现类,这里是Dubbo预留的 一个扩展点,通过 ConfiguratorFactory 可以用来设计自己的URL生成策略。

服务导出需要注意的点:
1、 本地服务导出:本地服务导出并不需要与注册中心交互,也不需要开启远程服务,所以其实现比较简单,将某些参数限制, 指定协议类型为injvm。
2、远程服务导出:加载注册中心-暴露服务-注册到服务中心-生成代理对象-服务订阅

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值