SpringCloud+Dubbo3 = 王炸 !

Posted 40岁资深老架构师尼恩

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringCloud+Dubbo3 = 王炸 !相关的知识,希望对你有一定的参考价值。

前言

全链路异步化的大趋势来了

随着业务的发展,微服务应用的流量越来越大,使用到的资源也越来越多。

在微服务架构下,大量的应用都是 SpringCloud 分布式架构,这种架构总体上是全链路同步模式

全链路同步模式不仅造成了资源的极大浪费,并且在流量发生激增波动的时候,受制于系统资源而无法快速的扩容。

全球后疫情时代,降本增效是大背景。如何降本增效?

可以通过技术升级,全链路同步模式 ,升级为 全链路异步模式

先回顾一下全链路同步模式架构图

全链路同步模式 ,如何升级为 全链路异步模式, 就是一个一个 环节的异步化。

40岁老架构师尼恩,持续深化自己的3高架构知识宇宙,当然首先要去完成一次牛逼的全链路异步模式 微服务实操,下面是尼恩的实操过程、效果、压测数据(性能足足提升10倍多)。

全链路异步模式改造 具体的内容,请参考尼恩的深度文章:全链路异步,让你的 SpringCloud 性能优化10倍+

并且,上面的文章,作为尼恩 全链路异步的架构知识,收录在《尼恩Java面试宝典》V46版的架构专题中

注:本文以 PDF 持续更新,最新尼恩 架构笔记、面试题 的PDF文件,请从这里获取:码云

SpringCloud + Dubbo 完成 RPC 异步

高并发时代来了, 各大项目有越来越强烈的诉求,全链路异步, 是性能优化的一个杀手锏。

全链路异步核心环境,就是RPC的异步化。

使用Dubbo来替换Feign,足足可以提升10倍性能。

所以,SpringCloud + Dubbo RPC 的集成 是一个比较刚性的需求。

有小伙伴查招聘网站,发现很多需要有SpringCloud + Dubbo 的集成经验,刚好印证了这点。

接下来,尼恩一步一步带着大家,来做一下 SpringCloud + Dubbo RPC 的集成实验+性能测试。

见证一下奇迹: 使用Dubbo 提升10倍的性能。

Dubbo3应用的宏观架构

Dubbo3应用架构,如下图所示:

从上面的图中,整体的的Dubbo的Rpc框架中,核心的组件有:

  • config-center 配置中心,接下来使用 nacos
  • Consumer消费端, 业务服务,使用Dubbo SDK 完成服务发现
  • Provider服务提供端,业务服务,使用Dubbo SDK 完成服务注册
  • Registry注册中心 配置中心,接下来使用 nacos

Dubbo3 应用架构的核心组件

两大部分:

  • 一个Dubbo SDK
  • 三中心

Dubbo SDK

Dubbo SDK作为模块,被微服务所引入和依赖。跟随着微服务组件被部署在分布式集群各个位置,实现各个微服务组件间的协作,主要是服务的注册、服务的发现

三中心

Dubbo3包含一些中心化组件,主要有3个,这包括:

  • 注册中心
    • 协调Consumer消费者与Provider服务提供者之间的地址注册与发现。
  • 配置中心
    • 存储Dubbo启动阶段的全局配置,保证配置的跨环境共享与全局一致性
    • 负责服务治理规则(路由规则、动态配置等)的存储与推送。
  • 元数据中心
    • 接收Provider服务端上报的服务接口元数据,为Admin等控制台提供运维能力(如服务测试、接口文档等)
    • 作为服务发现机制的补充,提供额外的接口/方法级别配置信息的同步能力,相当于注册中心的额外扩展。

以上三个中心,由Nacos组件承担,

所以在下面的实操中,无论dubbo-Provider还是dubbo-consumer,配置文件中都是这么配置的:

dubbo:
  scan:
    base-packages: com.crazymaker.cloud.dubbo
  application:
    name:  $spring.application.name
  protocol:
    name: dubbo
    port: -1
  registry:
    address: nacos://$NACOS_SERVER:cdh1:8848
    username: nacos
    password: nacos
    parameters:
      namespace: dubbo
      group: DUBBO_GROUP
  config-center:
    address: nacos://$NACOS_SERVER:cdh1:8848
    username: nacos
    password: nacos
    group: DUBBO_GROUP
  metadata-report:
    address: nacos://$NACOS_SERVER:cdh1:8848
    username: nacos
    password: nacos
    group: DUBBO_GROUP

SpringBoot整合Dubbo3.0基础准备

阿里早已把dubbo捐赠给了Apache,现在dubbo由Apache在维护更新,dubbo也已经成了Apache下的顶级项目。

SpringCloud+Nacos+Dubbo3.0

版本说明

  • SpringCloud:Hoxton.SR8
  • SpringCloudAlibaba:2.2.3.RELEASE
  • SpringBoot:2.3.4.RELEASE
  • Nacos:2.0.3
  • Dubbo:3.0.7

项目结构介绍

1、dubbo的依赖的坐标

Maven 依赖的坐标是Apache官方最新的3.0.4坐标。

<dependency>
    <groupId>org.apache.dubbo</groupId>
    <artifactId>dubbo-bom</artifactId>
    <version>$dubbo.version</version>
    <type>pom</type>
    <scope>import</scope>
</dependency>

如果使用的老版本的Dubbo,比如下面的这些依赖, 现在需要去掉啦

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

<dependency>
    <groupId>io.dubbo.springboot</groupId>
    <artifactId>spring-boot-starter-dubbo</artifactId>
    <version>1.0.0</version>
</dependency>

2、 注册中心的依赖的坐标

老的项目采用zookeeper为注册中心,当然,咱们的电脑里的虚拟机,其实都已经安装好zookeeper服务器,并已经启动。

所以,如果要使用ZK,对于咱们技术自由圈(疯狂创客圈的新名字)的小伙伴来说,也是非常方便的。

但是SpringCloud项目上一般使用的注册中,不是appolo,不是eureka,而是nacos。

现在Dubbo也支持nacos, 所以我们使用Nacos作为注册中心

<dependency>
    <groupId>org.apache.dubbo</groupId>
    <artifactId>dubbo-registry-nacos</artifactId>
    <version>$dubbo.version</version>
    <exclusions>
        <exclusion>
            <groupId>com.alibaba.nacos</groupId>
            <artifactId>nacos-client</artifactId>
        </exclusion>
    </exclusions>

    <type>pom</type>
</dependency>

这里有个版本兼容性的bug,尼恩稍微花了一点点时间,才解决这个问题。

具体的话,视频中给大家详细说一下。

SpringBoot整合Dubbo3.0大致步骤

  • SpringBoot 项目创建
  • Dubbo 服务提供方实现
  • Dubbo 服务消费方实现
  • 自定义Filter拦截所有消费请求
  • 自定义LoadBalance完成特殊场景负载均衡

模块结构

接下来演示下整合的模块结构,注意,是Springcloud 项目的老项目升级,

不是一个全新的项目,很多老的代码,要复用的

所以,就是在原来的crazy-SpringCloud 微服务项目上改造

但是这里仅仅演示 dubbo,所以,在原理的 脚手架里边,增加了两个子模块,

注意: 模块里边,并没有去掉原来的SpringCloud OpenFeign 的RPC调用, 而是两种RPC 调用共存。

方便后续在业务中快速运用,完整结构如下:

  1. consumer,服务消费方模块;
  2. provider,服务提供方模块;
  3. 统一定义服务接口和实体类,被其他工程模块引用;

consumer,服务消费方模块\\ provider,服务提供方模块;如下图

统一定义服务接口和实体类,被其他工程模块引用; 所以,这个之前fegin 的RPC 接口,现在接着给Dubbo用。

Dubbo微服务注册发现的相关配置

  • 命名空间隔离
  • 微服务注册中心配置

命名空间隔离

在nacos 的命名空间, 用来做 dubbo 的命名空间隔离

首先创建nacos的命名空间

命名id 是要用到的, 这里需要填写,

主要,不要自动生产

微服务yml配置

微服务 yml 配置, yml配置 dubbo nacos 命名空间

dubbo:
  scan:
	base-packages: xxx
  protocol:
    name: dubbo
    port: -1
  # 注册中心配置
  registry:
    address: nacos://xxx
 	parameters:
   		namespace: dubbo
    group: DUBBO_GROUP

dubbo:
  application:
    name:  $spring.application.name
  protocol:
    name: dubbo
    port: -1
  registry:
    address: nacos://$NACOS_SERVER:cdh1:8848
    username: nacos
    password: nacos
    parameters:
      namespace: dubbo
      group: DUBBO_GROUP
  config-center:
    address: nacos://$NACOS_SERVER:cdh1:8848
    username: nacos
    password: nacos
    group: DUBBO_GROUP
  metadata-report:
    address: nacos://$NACOS_SERVER:cdh1:8848
    username: nacos
    password: nacos
    group: DUBBO_GROUP

common-service 模块

服务接口 进行利旧 复用

还是之前的 UserClient 老接口,open fegn注解都不去掉

package com.crazymaker.springcloud.user.info.remote.client;

import com.crazymaker.springcloud.common.dto.UserDTO;
import com.crazymaker.springcloud.common.result.RestOut;
import com.crazymaker.springcloud.standard.config.FeignConfiguration;
import com.crazymaker.springcloud.user.info.remote.fallback.UserClientFallbackFactory;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

/**
 * Feign 客户端接口
 * @description: 用户信息 远程调用接口
 * @date 2019年7月22日
 */

@FeignClient(value = "uaa-provider",
        configuration = FeignConfiguration.class,
//        fallback = UserClientFallback.class,
        fallbackFactory = UserClientFallbackFactory.class,
        path = "/uaa-provider/api/user")
public interface UserClient

      /**
     * 远程调用 RPC 方法:获取用户详细信息
     * @param userId 用户 Id
     * @return 用户详细信息
     */
    @RequestMapping(value = "/detail/v1", method = RequestMethod.GET)
    RestOut<UserDTO> detail(@RequestParam(value = "userId") Long userId);

    @RequestMapping(value = "/hello/v1", method = RequestMethod.GET)
    public String hello(@RequestParam(value = "name") String name);

服务提供者实操:dubbo-provider 服务

pom依赖

<!-- dubbo -->
<dependency>
    <groupId>org.apache.dubbo</groupId>
    <artifactId>dubbo</artifactId>
</dependency>
<dependency>
    <groupId>org.apache.dubbo</groupId>
    <artifactId>dubbo-registry-nacos</artifactId>
    <exclusions>
        <exclusion>
            <artifactId>nacos-client</artifactId>
            <groupId>com.alibaba.nacos</groupId>
        </exclusion>
    </exclusions>
</dependency>

<!-- dubbo starter -->

<dependency>
    <groupId>com.alibaba.nacos</groupId>
    <artifactId>nacos-client</artifactId>
    <version>$nacos-client-verson</version>
</dependency>

服务实现类

package com.crazymaker.cloud.dubbo.demo.sevice;

import com.crazymaker.springcloud.common.dto.UserDTO;
import com.crazymaker.springcloud.common.result.RestOut;
import com.crazymaker.springcloud.user.info.remote.client.UserClient;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.stereotype.Component;

@DubboService
@Component

public class UserClientDubboService implements UserClient 
    @Override
    public RestOut<UserDTO> detail(Long userId) 
        UserDTO dto=new UserDTO();
        dto.setUserId(userId);
        dto.setNickname(" dubbo rpc test");
        return RestOut.success(dto).setRespMsg("操作成功");
    

    @Override
    public String hello(String name) 
        return "from dubbo provider : 你好,"+name;
    

dubbo和Feign的一个不同

  • dubbo的服务发布和暴露,直接在 service 层加上注解 ,就完成了

比如:上面的案例中,加上一个类级别的 注解,就可以 暴露这个服务接口 @DubboService

  • 而 Feign 的服务接口发布,是在 @Controller 层完成的。

相对来说,比 使用 Dubbo 更为笨重

Provider的Dubbo+Nacos配置文件

spring:
  security:
    enabled: false
  application:
    name: dubbo-provider-demo


server:
  port: 28088
  servlet:
    context-path: /dubbo-provider-demo

#### 暴露端点
management:
  endpoints:
    web:
      base-path: "/actuator"  # 配置 Endpoint 的基础路径
      exposure:
        include: '*'  #在yaml 文件属于关键字,所以需要加引号
  endpoint:
    logfile:
      # spring boot admin  client不配置日志文件路径(同时配置logback-spring.xml对应的日志输出配置,否则无法输出日志),
      # 控制台上的Logging模块下的Logfile会报错:Fetching logfile failed.Request failed with status code 404
      external-file: $log_dubbo_provider_demo_path_full:C:/logs/dubbo-provider-demo/logs/output.log
      enabled: true
    health:
      show-details: always
    # 未配置/注释 以下内容
#  boot:
#    admin:
#      context-path: consumer
  metrics:
    tags:
      application:  $spring.application.name
    export:
      prometheus:
        enabled: true
        step: 1m
        descriptions: true

dubbo:
  scan:
    base-packages: com.crazymaker.cloud.dubbo
  application:
    name:  $spring.application.name
  protocol:
    name: dubbo
    port: -1
  registry:
    address: nacos://$NACOS_SERVER:cdh1:8848
    username: nacos
    password: nacos
    parameters:
      namespace: dubbo
      group: DUBBO_GROUP
  config-center:
    address: nacos://$NACOS_SERVER:cdh1:8848
    username: nacos
    password: nacos
    group: DUBBO_GROUP
  metadata-report:
    address: nacos://$NACOS_SERVER:cdh1:8848
    username: nacos
    password: nacos
    group: DUBBO_GROUP

启动类 加上@EnableDubbo 注解

package com.crazymaker.cloud.dubbo.demo.starter;

import com.crazymaker.springcloud.common.util.IpUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.Environment;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

import java.net.Inet4Address;
import java.util.Optional;

@EnableSwagger2
@EnableDiscoveryClient
@Slf4j
@EnableDubbo

@SpringBootApplication(scanBasePackages =
        
                "com.crazymaker.cloud.dubbo.demo",
        
)


public class DubboProviderApplication 
    public static void main(String[] args) 
        try 
            ConfigurableApplicationContext applicationContext = SpringApplication.run(DubboProviderApplication.class, args);

            Environment env = applicationContext.getEnvironment();
            String port = env.getProperty("server.port");
            String name = env.getProperty("spring.application.name");

            String path = env.getProperty("server.servlet.context-path");
            if (StringUtils.isBlank(path)) 
                path = "";
            
            Optional<Inet4Address> ip = IpUtil.getLocalIp4Address();

          log.info("\\n----------------------------------------------------------\\n\\t" +
                    name.toUpperCase() + " is running! Access URLs:\\n\\t" +
                    "Local: \\t\\thttp://" + ip.get() + ":" + port + path + "/\\n\\t" +
                    "swagger-ui: \\thttp://" + ip.get() + ":" + port + path + "/swagger-ui.html\\n\\t" +
                    "actuator: \\thttp://" + ip.get() + ":" + port + path + "/actuator/info\\n\\t" +
                    "----------------------------------------------------------");

         catch (Exception e) 
            log.error("服务启动报错", e);

        
    

启动、体验Provider

打包之后,在 咱们优雅的虚拟机centos8中,优雅的启动一下,

来一个优雅的启动命令

[root@centos1 work]# cd dubbo-provider-demo-1.0-SNAPSHOT/bin/
[root@centos1 bin]# sh ./deploy.sh start
PORT:28088
JVM:-server -Xms512m 深入浅出Dubbo3原理及实战「SpringCloud-Alibaba系列」基于Nacos作为注册中心进行发布SpringCloud-alibaba生态的RPC接口实战

在 Dubbo3.0 上服务治理的实践

基于 Dubbo3.0 的服务治理的实践

干翻 nio ,王炸 io_uring 来了 !!(图解+史上最全)

Dubbo3中服务端线程模型,线程处理(基于Dubbo3)

深入浅出Dubbo3原理及实战「新特性简介」Dubbo3新特性要点之RPC协议介绍