Dubbo入门

Posted by DeepBlue on 12-18,2020

Dubbo入门

什么是Dubbo

Dubbo 是一款高性能 Java RPC 架构。它实现了面向接口代理的RPC 调用服务注册和发现负载均衡,容错,扩展性等等功能。

其实说明白了就是一个远程过程调用的框架(除此之外增加了一些常用的功能),那么什么是远程过程调用呢?通俗来说以前的时候我们在自己本机上写代码的时候,我们调用了sayHello()这个方法,然后计算机就去执行这个函数,这是本地函数调用,那么同理远程过程调用是什么意思呢?就是现在虽然也是一个sayHello()这个方法,我们不在本机上调用了,我们去找不在本地计算机上的另外一台计算机上进行函数的执行,然后让他把执行的结果给我发过来,这样的过程就是远程过程调用

img

那么有同学就会问了我就在本地调用方法不好吗,为什么非要让别的计算机去完成这个操作呢?

其实要解决这个疑问,我们就要从服务架构的的变化说起了,也就是为什么我们要用RPC。

为什么要用RPC

这个要从服务架构的变化说起来:

单一应用服务架构,这也是我们平时用的最多的架构,比如平时写个xx管理系统,等QPS很少的系统,因为用户很少,单机服务就好使了。

多服务架构,到后来我们发现我们的服务有点扛不住了,我们可能去提高我们应用程序的QPS了,这个时候我们容易想到的方法就是再加一台服务器呗,然后把原来服务器上跑的服务原版复刻下来到这个服务器上,然后来个nginx搞个负载均衡就ok了。

再到后来我们发现这种堆叠服务器来实现也有很多的问题,如果多个服务器使用的是同一个数据库,那么这个数据库压力就会非常的大,除此之外还有很多的缺点,比如:每次部署要把整个应用程序全量的部署上去,这显然是不好的,如果发生系统的更改的话,那么这些系统需要全部的下线->修改->上线,会造成服务停止。

微服务架构 :随之我们出现了微服务的架构,这种架构可以使我们对一个大型的服务进行拆分,比如把电商服务拆分成为订单服务,登录服务,物流服务等部分,如果哪个服务需求量增加,我们只需要增加对应服务的服务器数量就可以了,资源分配更加的合理。

随着这种分布式微服务架构的发展,我们又遇到了新的问题,那就是每个服务模块相互独立,但是在一些业务逻辑的处理是可能是需要相互的进行通信,比如物流服务需要订单服务的订单数据,这时候我们就需要使用RPC。

流量计算架构 当服务越来越多时,容量评估变得困难,小规模的服务也经常导致资源浪费。为了解决这些问题,应该添加一个调度中心来管理基于流量的集群容量,并提高集群的利用率。此时,用于提高机器利用率的资源调度和治理中心(SOA)是关键。

为什么用Dubbo

  1. 透明化的远程方法调用,就像调用本地方法一样调用远程方法,只需简单配置,没有任何API侵入。

  2. 软负载均衡及容错机制,可在内网替代硬件负载均衡器,降低成本,减少单点。

  3. 服务自动注册与发现,不再需要写死服务提供方地址,注册中心基于接口名查询服务提供者的IP地址,并且能够平滑添加或删除服务提供者。

Dubbo的架构

image-20201218191511926

角色

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

调用关系

  1. 服务提供者在启动时,向注册中心注册自己提供的服务。

  2. 服务消费者在启动时,向注册中心订阅自己所需的服务。

  3. 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。

  4. 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。

  5. 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。

How to Use

我们可以看到注册中心在RPC调用中扮演着很重要的作用,他记录了哪些消费者提供了哪些接口可以被消费者调用,还有哪些服务发生了变更,是Dubbo框架中的重要组成部分。

那么我们就需要自己搭建一个注册中心,Dubbo官方提供了Multicast zookeeper Nacos Redis Simple 注册中心等注册中心,但是官方建议使用zookeeper作为dubbo的注册中心。我们可以使用zookeeper的docker镜像进行环境的搭建,减少一些配置的操作。docker地址:https://hub.docker.com/_/zookeeper 或者使用docker-compose进行搭建。

version: '3.1'

services:
  zoo1:
    image: zookeeper
    restart: always
    hostname: zoo1
    ports:
      - 2181:2181
    environment:
      ZOO_MY_ID: 1
      ZOO_SERVERS: server.1=0.0.0.0:2888:3888;2181 server.2=zoo2:2888:3888;2181 server.3=zoo3:2888:3888;2181

  zoo2:
    image: zookeeper
    restart: always
    hostname: zoo2
    ports:
      - 2182:2181
    environment:
      ZOO_MY_ID: 2
      ZOO_SERVERS: server.1=zoo1:2888:3888;2181 server.2=0.0.0.0:2888:3888;2181 server.3=zoo3:2888:3888;2181

  zoo3:
    image: zookeeper
    restart: always
    hostname: zoo3
    ports:
      - 2183:2181
    environment:
      ZOO_MY_ID: 3
      ZOO_SERVERS: server.1=zoo1:2888:3888;2181 server.2=zoo2:2888:3888;2181 server.3=0.0.0.0:2888:3888;2181

如果不想搭建注册系统的集群,我们可以在安装监视器的时候使用docker-compose进行安装。

如果不想搭建注册系统的集群,我们可以在安装监视器的时候使用docker-compose进行安装。docker-admin镜像地址:

https://hub.docker.com/r/apache/dubbo-admin

docker-compose.yml

version: '3'

services:
  zookeeper:
    image: zookeeper
    ports:
      - 2181:2181
  admin:
    image: apache/dubbo-admin
    depends_on:
      - zookeeper
    ports:
      - 8080
    environment:
      - admin.registry.address=zookeeper://zookeeper:2181
      - admin.config-center=zookeeper://zookeeper:2181
      - admin.metadata-report.address=zookeeper://zookeeper:2181

笔者这里使用docker-compose进行启动

docker-compose -f ./docker-compsoe.yml up -d

服务启动后我们可以访问8080端口查看admin界面:

image-20200814202645562

看到看到管理界面之后我们需要编写服务的提供者,笔者这里是使用的springboot进行开发,我们新建一个springboot项目,然需要导入dubbo的jar包。

		<dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-recipes</artifactId>
            <version>5.1.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo-spring-boot-starter</artifactId>
            <version>2.7.7</version>
        </dependency>

上面的两个jar包,其中curator-recipes是操作zookeeper的jar包,因为我们使用的是zookeeper作为注册中心,所以必须导入这个jar包,第二个jar包就是我们的dubbo的springboot的jar包,引入这个jar包之后,我们还需要新建一个项目,项目中存储公共的接口,这也是dubbo建议我们去做的,因为将公共接口暴露出去的话我们就可以在消费者这边看到哪些接口包含哪些方法。

这里我们在公共接口的项目中写入这个接口,其中有一个initOrder的方法。

public interface OrderService {
    public String initOrder(String username);
}

服务提供者

服务提供者,就是真正实现业务的一个对象,服务提供者将服务提供出去,那么消费者就可以消费服务提供者所提供的服务。在这里我们可以导入公共API的项目,从而进行实现。

		<dependency>
            <groupId>com.kklll.study</groupId>
            <artifactId>api</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

此外我们还需要配置dubbo的一些配置:

dubbo.application.name=order-sevice # 服务的名称
dubbo.registry.address=your registry ip :2181 # 注册中心的地址以及端口
dubbo.registry.protocol=zookeeper  # 注册协议,我们使用的是zookeeper进行注册所以注册协议就写zookeeper
dubbo.protocol.name=dubbo  # 使用的协议,dubbo也支持其他协议,详情请查看官方文档https://dubbo.apache.org/zh-cn/docs/user/references/protocol/introduction.html
dubbo.protocol.port=20880 # 协议端口号
dubbo.monitor.protocol=registry  # 如果为registry则表明从注册中心发现监视中心,否则直接连接监视中心

此外我们作为服务的提供者,我们需要实现公共接口的方法,以便于消费者进行调用

@Component
@DubboService 
public class OrderServiceImpl implements OrderService {
    @Override
    public String initOrder(String username) {
        System.out.println("服务提供者被调用");
        System.out.println("Hello "+username);
        return "Hello "+username;
    }
}

使用@DubboService来暴露出我们的服务,这个服务的实现将会被注册中心所感知到,便于消费者进行服务的调用。

随后我们启动provider的服务即可,这时候再看我们的dubbo-admin的面板上就会出现这个接口的信息。

服务消费者

作为服务消费者,我们也必须连接到dubbo的注册中心,通过和注册中心的信息交互实现远程的方法调用。

首先应该导入上面所说的两个jar包

同样的我们也要配置一下消费者的一些配置:

dubbo.application.name=consumer #同理
dubbo.registry.address=your registry ip :2181
dubbo.registry.protocol=zookeeper # 同理
dubbo.monitor.protocol=registry # 同理
server.port=9999 # 这里我修改一下本机服务的端口号避免冲突

配置好上面的配置之后,我们就可以写代码了,这里我导入了spring-boot-web的jar包,简单的写一个Controller

@Controller
public class MainController {
    @DubboReference(timeout = 6000)
    private OrderService orderService;

    @ResponseBody
    @RequestMapping("test")
    public Integer requst() {
        return orderService.initOrder("张三");
    }
}

我们看到,直接使用@DubboReference注解就可以远程调用该接口的方法,相当于我们在本地使用@Autowired注解注入了一个接口,非常的方便。

接下来我们启动web服务,然后请求这个方法。

结果

image-20200814211106266

我们可以看到,服务消费者返回了正确调用后的结果,同时也服务提供者也打印出了相应的信息。

image-20200814211200889

结语

通过这个小小的案例暂时入门Dubbo这个Java RPC框架,接下来会对Dubbo进行跟深层次的了解。