Skip to content

Latest commit

 

History

History
481 lines (350 loc) · 16.7 KB

Dubbo.md

File metadata and controls

481 lines (350 loc) · 16.7 KB

Dubbo

我们来回顾一下不断演进的服务架构

单体架构 -> 分布式架构 -> 微服务

单体架构:将业务的所有功能集中在一个项目中开发,打成一个包部署

image-20210713202807818

优点:

  • 架构简单
  • 部署成本低

缺点:

  • 耦合度高(维护困难、升级困难)

分布式架构:根据业务功能对系统做拆分,每个业务功能模块作为独立项目开发,称为一个服务

image-20210713203124797

优点:

  • 降低服务耦合
  • 有利于服务升级和拓展

缺点:

  • 服务调用关系错综复杂

分布式架构虽然降低了服务耦合,但是服务拆分时也有很多问题需要思考:

  • 服务拆分的粒度如何界定?
  • 服务之间如何调用?
  • 服务的调用关系如何管理?

人们需要制定一套行之有效的标准来约束分布式架构,进而有了我们现在的微服务,微服务的上述特性其实是在给分布式架构制定一个标准,进一步降低服务之间的耦合度,提供服务的独立性和灵活性。做到高内聚,低耦合。

因此,可以认为微服务是一种经过良好架构设计的分布式架构方案

image-20210713203753373

微服务的架构特征:

  • 单一职责:微服务拆分粒度更小,每一个服务都对应唯一的业务能力,做到单一职责
  • 自治:团队独立、技术独立、数据独立,独立部署和交付
  • 面向服务:服务提供统一标准的接口,与语言和技术无关
  • 隔离性强:服务调用做好隔离、容错、降级,避免出现级联问题

现在国内用的最多的微服务就是SpringCloud,它的核心组件包括:

image-20210713204155887

1. 什么是Dubbo

我们在学习SpringCloud的时候,为了调用其他微服务里面的接口,经常会使用Feign来调用,其实这就是一种远程过程调用(RPC),是基于Http协议的远程服务调用

Dubbo其实也是干类似的事情的,即Dubbo是一款高性能的RPC框架,用来解决微服务中各个模块调用的问题,那我们既然有了Feign,为什么还要有Dubbo呢?那是因为对于微服务模块来说HTTP协议还是太重了,HTTP协议在设计之处为了许多的安全性,设置了许多健壮性的设计,对于微服务模块来说,其实完全可以采用更加轻量级的通讯协议来完成远程服务调用,Dubbo应运而生

Dubbo主要从一下两个方面来加快远程调用的速度,这两个方面同时也是我们进行网络IO最耗时的方面:

  • 序列化

    我们在学习Java网络编程的时候知道,一个对象要想在网络中传输,就必须要实现Serializable接口进行序列化,一般序列化的方式有:xml、json、二进制流等,其中效率最高的就是二进制流(因为网络传输的本质就是通过二进制传输的),Dubbo采用的就是效率最高的二进制方式进行序列化

  • 网络通信

    Dubbo采用Socket通信,自定义一套高效的通讯协议,提升了通信效率,并且可以建立长连接,不用反复连接,极大的提升了传输的效率

现在市面上还有很多的RPC框架,如:gRPC、Thrift、HSF等等

Dubbo除了提供远程服务调用的功能之外,还有服务注册发现的功能,我们来看一下官方的Dubbo架构图:

image-20220806232532540

可以看到在Dubbo中主要有五个角色:

  • Container: 服务运行容器,负责加载、运行服务提供者。必须。

  • Provider: 暴露服务的服务提供方,会向注册中心注册自己提供的服务。必须。

  • Consumer: 调用远程服务的服务消费方,会向注册中心订阅自己所需的服务。必须。

  • Registry: 服务注册与发现的注册中心。注册中心会返回服务提供者地址列表给消费者。非必须。

  • Monitor: 统计服务的调用次数和调用时间的监控中心。服务消费者和提供者会定时发送统计数据到监控中心。 非必须。

读者可能会感觉这些服务好像Nacos也提供叭,或者说是SpringCloud也提供,是的,其实DubboSpringCloud在某种程度上是竞争关系

Dubbo为我们提供的主要功能有:

  1. 面向接口代理的高性能 RPC 调用
  2. 智能容错和负载均衡。
  3. 服务自动注册和发现
  4. 高度可扩展能力
  5. 运行期流量调度
  6. 可视化的服务治理与运维

我们总结一下Dubbo的作用: Dubbo是一站式的微服务解决方案

2. Dubbo快速上手

因为Dubbo是使用Zookeeper进行服务注册发现,所以我们需要安装一个zk,后续可以使用Nacos作为注册中心

我们可以在Linux环境下搭建一个Zookeeper,这里笔者采用的方式是Docker的方式

如果读者对Zookeeper的使用还比较陌生,可以看笔者的这篇文章:docker安装zookeeper&zookeeper基本使用(非常详细)

docker run -d \
-e TZ="Asia/Shanghai" \
-p 2181:2181 \
--name zookeeper \
--log-opt max-size=500m \
--restart always zookeeper

2.1 各模块的配置文件

我们这里来新建一个项目用来演示一下Dubbo的使用过程:

image-20220807224017838

父模块的依赖如下,采用的都是现在最新的版本,如果版本发生冲突可以试着降低版本

<?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>cn.hnit</groupId>
    <artifactId>dubbo-demo</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>dubbo-provider</module>
        <module>dubbo-comsumer</module>
        <module>dubbo-provider2</module>
        <module>dubbo-api</module>
    </modules>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.2</version>
    </parent>
    <properties>
        <java.version>1.8</java.version>
        <dubbo-boot.version>3.0.8</dubbo-boot.version>
        <zkclient.version>5.1.0</zkclient.version>
        <web.version>2.6.4</web.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <!-- apache 官方 3.0 starter依赖 -->
            <dependency>
                <groupId>org.apache.dubbo</groupId>
                <artifactId>dubbo-spring-boot-starter</artifactId>
                <version>${dubbo-boot.version}</version>
            </dependency>
            <!-- zookeeper客户端  只需引入此依赖curator-framework curator-recipes 都有 -->
            <dependency>
                <groupId>org.apache.curator</groupId>
                <artifactId>curator-x-discovery</artifactId>
                <version>${zkclient.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
                <version>${web.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>
</project>

dubbo-api依赖:

<?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">
    <parent>
        <artifactId>dubbo-demo</artifactId>
        <groupId>cn.hnit</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>dubbo-api</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>
</project>

接着在这两个子模块添加依赖

dubbo-provider

<dependencies>
    <!-- 不需要对外暴露接口,仅需要给其他模块进行RPC调用 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>org.apache.curator</groupId>
        <artifactId>curator-x-discovery</artifactId>
    </dependency>
    <dependency>
        <groupId>cn.hnit</groupId>
        <artifactId>dubbo-api</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
</dependencies>

配置文件:

# 这里的配置属性只是基础配置,如需更多功能配置,请自行扩展
dubbo:
  application:
    name: dubbo-provider
  registry:
    address: zookeeper://volunteer.fengxianhub.top:20016
  protocol:
    name: dubbo
    port: 20880

第二个dubbo-provider和上面一样,只是要将dubbo通信的端口修改一下,例如改为20881

dubbo-comsumer

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo-spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-x-discovery</artifactId>
        </dependency>

        <dependency>
            <groupId>cn.hnit</groupId>
            <artifactId>dubbo-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

配置文件:

server:
  port: 8080   #Tomcat端口
# 这里的配置属性只是基础配置,如需更多功能配置,请自行扩展
dubbo:
  application:
    name: dubbo-provider
  registry:
    address: zookeeper://volunteer.fengxianhub.top:20016
  protocol:
    name: dubbo
    port: 20882

接着我们在API中写几个需要进行RPC的接口,这个包一般用来定义接口,提供给其他包进行实现,读者也可以不写这个包image-20220807225117481

User类

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User implements Serializable {

    private static final long serialVersionUID = 8728327146677888239L;

    private Integer userId;

    private String  userName;
}

接口UserService

public interface UserService {
    User getByUserId(Integer userId);
}

2.2 对外暴露接口

接着我们写调用逻辑和对外暴露的接口,对外暴露的接口仅写在dubbo-consumer模块中,在此之前我们需要先写服务中心的RPC调用逻辑,也就是dubbo-provider模块中,写一个类来实现之前我们dubbo-api中定义的接口

@Slf4j
@DubboService
public class UserServiceImpl implements UserService {
    // 模拟数据
    private static final List<User> USERS = Arrays.asList(
            new User(1, "张三"),
            new User(2, "李四")
    );
    // 用来记录被调用的次数
    private final AtomicInteger sum = new AtomicInteger(0);

    @Override
    public User getByUserId(Integer userId) {
        // 打印一下被调用情况,dubbo-provider2中这里填dubbo-provider2被调用
        log.info("dubbo-provider被调用【{}】次", sum.incrementAndGet());
        for (User user : USERS) {
            if (user.getUserId().equals(userId)) {
                return user;
            }
        }
        return null;
    }
}

当然在启动类上我们需要加上@EnableDubbo注解表示启动Dubbo RPC

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

2.3 查看调用情况

接下来我们启动dubbo-consumerdubbo-providerdubbo-provider2三个服务,注意我们这里要先启动后面两个RPC提供的服务,再启动第一个对外暴露接口的服务

image-20220807235348409

我们来测试一下,发现可以完成调用:

image-20220807235601326

我们再来做一万次压测,看看两个provider服务的负载情况

这里压测笔者使用AB压力测试,启用100个线程共发送一万个请求

image-20220808000426373

来看看两个provider的负载,provider1:

image-20220808000459914

provider2:

image-20220808000532278

可以看到请求被平均发到两个服务上了,起到了负载均衡的作用

我们再来看看ZooKeeper上的结点情况:

image-20220808001808645

3. 使用nacos作为注册中心

在上面的快速入门中,我们知道了Dubbo进行RPC调用的过程,我们可以想注入一个普通Bean一样,注入一个远程的Bean,并且还可以配置负载均衡策略,到这里Dubbo中的五个核心组件我们已经见识过四个了,其中Container容器就是我们的Spring容器,现在只有最后一个组件:Monitor没有见过了,接下来我们就开始学习它

Monitor是监视器的意思,用来监视整个Dubbo组件的状态,它提供了一个web界面让我们更清楚在查看我们的Dubbo使用情况,由于Monitor本身存在一些问题,一般我们会使用dubbo-admin进行管理,但是 dubbo-2.6.1以后的版本不再有dubbo-admin

现在一般我们会使用Nacos作为注册中心和配置管理中心,接下来,我们使用Nacos重复一遍上面的过程

Nacos的使用可以看笔者的另一篇文章:eureka&nacos学习一

image-20220808003201046

这里我在docker上面安装一下,这里需要注意的是Nacos进行RPC通信的端口是98489849,所以这两个端口也需要开放

image-20220821151534355

docker run -d \
-e MODE=standalone \
--privileged=true \
--restart=always \
-e JVM_XMS=256m \
-e JVM_XMX=256m \
-e MODE=standalone \
-e PREFER_HOST_MODE=hostname \
--log-opt max-size=500m \
-p 8848:8848  \
-p 9848:9848  \
-p 9849:9849  \
--name nacos \
--restart=always \
nacos/nacos-server:1.4.1        

在浏览器中输入:http://你的ip地址:8848/nacos,即可访问(账号密码都是Nacos),如果是云服务器记得开安全组

3.1 nacos 添加命名空间

我们需要在Nacos上添加一个命名空间,用来专门作为Dubbo的空间

image-20220808220510272

3.1 添加依赖

这里的方式是非SpringCloud的方式,后面再看SpringCloud的方式

首先我们需要改造一下之前的pom依赖,将SpringCloudNacos的依赖添加进去

首先在父工程的pom文件中的<dependencyManagement>中引入Dubbo Registry Nacos的依赖:

然后在对应的consumerprovider中也要引入这个依赖,版本和自己Nacos依赖一样即可

<!-- Dubbo Registry Nacos -->
<dependency>
    <groupId>org.apache.dubbo</groupId>
    <artifactId>dubbo-registry-nacos</artifactId>
    <version>3.0.8</version>
</dependency>

consumerprovider的application.yml中添加nacos地址:

# 这里的配置属性只是基础配置,如需更多功能配置,请自行扩展
dubbo:
  application:
    name: dubbo-provider # 这里取名字的时候要区分开
  registry:
    address: nacos://volunteer.fengxianhub.top:20026
  protocol:
    name: dubbo
    port: 20880