当前位置: 首页 > news >正文

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.dubboapplication:name:  ${spring.application.name}protocol:name: dubboport: -1registry:address: nacos://${NACOS_SERVER:cdh1:8848}username: nacospassword: nacosparameters:namespace: dubbogroup: DUBBO_GROUPconfig-center:address: nacos://${NACOS_SERVER:cdh1:8848}username: nacospassword: nacosgroup: DUBBO_GROUPmetadata-report:address: nacos://${NACOS_SERVER:cdh1:8848}username: nacospassword: nacosgroup: 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: xxxprotocol:name: dubboport: -1# 注册中心配置registry:address: nacos://xxxparameters:namespace: dubbogroup: DUBBO_GROUPdubbo:application:name:  ${spring.application.name}protocol:name: dubboport: -1registry:address: nacos://${NACOS_SERVER:cdh1:8848}username: nacospassword: nacosparameters:namespace: dubbogroup: DUBBO_GROUPconfig-center:address: nacos://${NACOS_SERVER:cdh1:8848}username: nacospassword: nacosgroup: DUBBO_GROUPmetadata-report:address: nacos://${NACOS_SERVER:cdh1:8848}username: nacospassword: nacosgroup: 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
@Componentpublic class UserClientDubboService implements UserClient {@Overridepublic RestOut<UserDTO> detail(Long userId) {UserDTO dto=new UserDTO();dto.setUserId(userId);dto.setNickname(" dubbo rpc test");return RestOut.success(dto).setRespMsg("操作成功");}@Overridepublic String hello(String name) {return "from dubbo provider : 你好,"+name;}
}

dubbo和Feign的一个不同

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

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

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

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

Provider的Dubbo+Nacos配置文件

spring:security:enabled: falseapplication:name: dubbo-provider-demoserver:port: 28088servlet: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 404external-file: ${log_dubbo_provider_demo_path_full:C:/logs/dubbo-provider-demo/logs/output.log}enabled: truehealth:show-details: always# 未配置/注释 以下内容
#  boot:
#    admin:
#      context-path: consumermetrics:tags:application:  ${spring.application.name}export:prometheus:enabled: truestep: 1mdescriptions: truedubbo:scan:base-packages: com.crazymaker.cloud.dubboapplication:name:  ${spring.application.name}protocol:name: dubboport: -1registry:address: nacos://${NACOS_SERVER:cdh1:8848}username: nacospassword: nacosparameters:namespace: dubbogroup: DUBBO_GROUPconfig-center:address: nacos://${NACOS_SERVER:cdh1:8848}username: nacospassword: nacosgroup: DUBBO_GROUPmetadata-report:address: nacos://${NACOS_SERVER:cdh1:8848}username: nacospassword: nacosgroup: 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 -Xmx2048m
nohup java -server -Xms512m -Xmx2048m -Dserver.port=28088   -jar /work/dubbo-provider-demo-1.0-SNAPSHOT/lib/dubbo-provider-demo-1.0-SNAPSHOT.jar com.crazymaker.cloud.dubbo.demo.starter.DubboProviderApplication  &log file : /work/logs/dubbo-provider-demo-1.0-SNAPSHOT/output.log

太爽… 有个vagrant+Centos 开发环境, 开发Java应用,爽到不要不要的

关键是: 在这个虚拟机 box 文件中,尼恩给大家预装了K8S 云原生环境,大家一键导入省了N多麻烦。基于这个环境, 下一步咱们就开始 “左手大数据、右手云原生” 的高端实操

继续看,屏幕的下面,下面还有swagger体验地址

使用这个地址,可以在浏览器开起Swagger -UI 的界面

http:///cdh1:28088/dubbo-provider-demo/swagger-ui.html

开启之后的效果,但是,这个和dubbo没有关系

因为dubbo的服务并没有在swagger ui 展示

在Nacos查看Dubbo服务的注册情况

通过nacos,可以看到 dubbo的服务啦

具体的细节,咱们后面讲dubbo视频的时候,再说

这里先把性能优化起来

服务消费者实操:dubbo-consumer 服务

consumer模块

消费者实现类

package com.crazymaker.cloud.dubbo.demo.consumer.controller;import com.crazymaker.springcloud.common.dto.UserDTO;
import com.crazymaker.springcloud.common.result.RestOut;
import com.crazymaker.springcloud.user.info.remote.client.UserClient;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/user")
@Api(tags = "Dubbo-RPC  完成远程调用")
public class UserConsumerController {//注入  @DubboReference 注解配置 所配置的 EchoClient 客户端Feign实例@DubboReference(loadbalance = "groupLoadBalance")private UserClient userService;//用户详情@ApiOperation(value = "用户详情接口")@RequestMapping(value = "/detail/v1", method = RequestMethod.GET)RestOut<UserDTO> detail(@RequestParam(value = "userId", required = true)Long userId) {RestOut<UserDTO> ret = userService.detail(userId);return ret;}
}

消费者Dubbo+Nacos配置文件

spring:security:enabled: falseapplication:name: dubbo-consumer-demo
#http://cdh1:18081/dubbo-consumer-demo/swagger-ui.htmlserver:port: 18081servlet:context-path: /dubbo-consumer-demo#### 暴露端点
management:endpoints:web:base-path: "/actuator"  # 配置 Endpoint 的基础路径exposure:include: '*'  #在yaml 文件属于关键字,所以需要加引号endpoint:health:show-details: alwaysmetrics:tags:application: ${spring.application.name}
#  boot:
#    admin:
#      context-path: consumerdubbo:scan:base-packages: com.crazymaker.cloud.dubboapplication:name:  ${spring.application.name}protocol:name: dubboport: -1registry:address: nacos://${NACOS_SERVER:cdh1:8848}username: nacospassword: nacosparameters:namespace: dubbogroup: DUBBO_GROUPconfig-center:address: nacos://${NACOS_SERVER:cdh1:8848}username: nacospassword: nacosgroup: DUBBO_GROUPmetadata-report:address: nacos://${NACOS_SERVER:cdh1:8848}username: nacospassword: nacosgroup: DUBBO_GROUP

启动类 加上@EnableDubbo 注解

package com.crazymaker.cloud.dubbo.demo.consumer.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.actuate.autoconfigure.security.servlet.ManagementWebSecurityAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
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","com.crazymaker.springcloud.standard"},exclude = {SecurityAutoConfiguration.class,//排除db的自动配置DataSourceAutoConfiguration.class,DataSourceTransactionManagerAutoConfiguration.class,HibernateJpaAutoConfiguration.class,SecurityAutoConfiguration.class,ManagementWebSecurityAutoConfiguration.class,//排除redis的自动配置RedisAutoConfiguration.class,RedisRepositoriesAutoConfiguration.class})
//启动Feign
@EnableFeignClients(basePackages ={"com.crazymaker.cloud.dubbo.demo.consumer.client"})
public class DubboConsumerApplication {public static void main(String[] args) {try {ConfigurableApplicationContext applicationContext = SpringApplication.run(DubboConsumerApplication.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);}}
}

启动、体验 Consumer

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

来一个优雅的启动命令

[root@centos1 bin]# cd ../../dubbo-consumer-demo-1.0-SNAPSHOT/bin/
[root@centos1 bin]# sh ./deploy.sh start
PORT:18081
JVM:-server -Xms512m -Xmx2048m
nohup java -server -Xms512m -Xmx2048m -Dserver.port=18081   -jar /work/dubbo-consumer-demo-1.0-SNAPSHOT/lib/dubbo-consumer-demo-1.0-SNAPSHOT.jar com.crazymaker.cloud.dubbo.demo.consumer.starter.DubboConsumerApplication  &
nohup: appending output to 'nohup.out'

太爽… 有个vagrant+Centos 开发环境, 开发Java应用,爽到不要不要的

关键是: 在这个虚拟机 box 文件中,尼恩给大家预装了K8S 云原生环境,大家一键导入省了N多麻烦。

下一步,基于这个环境, 咱们就开始 “左手大数据、右手云原生” 的高端实操

继续看,屏幕的下面,下面还有swagger体验地址

使用这个地址,可以在浏览器开起Swagger -UI 的界面

http:///10.0.2.15:18081/dubbo-consumer-demo/swagger-ui.html

注意,要修改一下 host,修改之后为

http://cdh1:18081/dubbo-consumer-demo/swagger-ui.html

Feign 和Dubbo 两大RPC调用 并存的效果,如下:

在Nacos查看Dubbo服务的注册情况

通过nacos,可以看到 dubbo的服务的消费者啦

具体的细节,咱们后面讲dubbo视频的时候,再说

这里先把性能优化起来

性能的对比测试

然后进行了性能的对比验证

dubbo 的压测数据

wrk -t8 -c200 -d30s --latency  http://cdh1:18081/dubbo-consumer-demo/user/detail/v1?userId=1[root@centos1 src]# wrk -t8 -c200 -d30s --latency  http://cdh1:18081/dubbo-consumer-demo/user/detail/v1?userId=1
Running 30s test @ http://cdh1:18081/dubbo-consumer-demo/user/detail/v1?userId=18 threads and 200 connectionsThread Stats   Avg      Stdev     Max   +/- StdevLatency    30.10ms   45.68ms 644.45ms   95.43%Req/Sec     1.12k   465.63     2.36k    66.87%Latency Distribution50%   18.94ms75%   28.43ms90%   46.21ms99%  283.56ms264316 requests in 30.07s, 148.47MB read
Requests/sec:   8788.96
Transfer/sec:      4.94MB

feign 的压测数据

wrk -t8 -c200 -d30s --latency  http://cdh1:18081/dubbo-consumer-demo/echo/variable/11[root@centos1 src]# wrk -t8 -c200 -d30s --latency  http://cdh1:18081/dubbo-consumer-demo/echo/variable/11
Running 30s test @ http://cdh1:18081/dubbo-consumer-demo/echo/variable/118 threads and 200 connectionsThread Stats   Avg      Stdev     Max   +/- StdevLatency   321.50ms  294.59ms   2.00s    61.77%Req/Sec    87.18     43.39   232.00     67.00%Latency Distribution50%  309.06ms75%  503.06ms90%  687.99ms99%    1.21s20495 requests in 30.10s, 7.64MB readSocket errors: connect 0, read 0, write 0, timeout 49
Requests/sec:    680.90
Transfer/sec:    259.99KB

从数据来看, dubbo rpc 是feign rpc 性能10倍

Dubbo比Feign高10倍以上的本质

Dubbo比Feign高10倍以上的本质,不是在于应用层的协议,和传输格式

面试的时候,太多的小伙伴被问到: Dubbo比Feign性能高,说说原因。

小伙伴首先回答的是:

Dubbo 是TCP 层的传输协议,Feign是应用层 的HTTP传输协议,所以性能低。

这个答案不是本质原因,HTTP是有些冗余的头部报文,但是不至于差10倍。能差0.5倍,就已经顶天了。

差10倍的原因:是 同步链路 与异步链路 的 区别。

或者说:Dubbo比Feign高10倍以上的本质,是RPC 调用异步化

RPC 调用主要的框架有:

特点是:

  • feign 是同步IO 、阻塞模式的同步 RPC框架
  • dubbo 是基于Netty的非阻塞IO + Reactor 反应堆线程模型的 异步RPC框架

异步RPC 调用,等待upstream 上游 response 返回时,线程不处于block 状态

作为微服务架构中数据流量最大的一部分,RPC 调用异步化的收益巨大;

dubbo 的异步RPC,仅仅 SpringCloud 微服务全链路 异步的一个环节, SpringCloud 全链路 异步有5个以上的环节。

有关 微服务全链路 异步高性能改造,请参考尼恩的深度文章:

全链路异步,让你的 SpringCloud 性能优化10倍+

高并发、云原生、大数据时代,很多组件都是 全异步的、响应式的。

大家一定要掌握全链路异步的底层原理,掌握好 响应式编程的底层原理和实操,为 “左手大数据、右手云原生” 做好技术准备。

后面尼恩也会写一些列的博文,为大家“左手大数据、右手云原生” 做好技术储备。

具体请关注尼恩的疯狂创客圈社群(50+)。

Dubbo 与 SpringCloud 的通信 Openfeign的区别

1、协议支持方面

  • Feign更加优雅简单。
    Feign是通过REST API实现的远程调用,基于Http传输协议,服务提供者需要对外暴露Http接口供消费者调用,服务粒度是http接口级的。
    很多文章说:通过短连接的方式进行通信,不适合高并发的访问。
    尼恩纠错: Feign 并不是短链接,而是长连接 ,具体请 阅读 尼恩 的《Java 高并发核心编程 卷1 加强版》
  • Dubbo方式更灵活。
    Dubbo是通过RPC调用实现的远程调用,支持多传输协议(Dubbo、Rmi、http、redis等等),可以根据业务场景选择最佳的方式,非常灵活。
    默认的Dubbo协议:利用Netty,TCP传输,单一、异步、长连接,适合数据量小、高并发和服务提供者远远少于消费者的场景。Dubbo通过TCP长连接的方式进行通信,服务粒度是方法级的。

2、通信性能方面

  • Feign基于Http传输协议,底层实现是rest。在高并发场景下性能不够理想。
  • Dubbo框架的通信协议采用RPC协议,属于传输层协议,提升了交互的性能,保持了长连接,高性能。

3、线程模型方面

  • Feign使用的是阻塞式的线程模型, 在请求和响应直之间, IO线程是阻塞的,死等到超时。
  • Dubbo使用的是异步非阻塞式的线程模型(Netty的Reactor反应器), 在请求和响应直之间, IO线程是非阻塞的,有限的线程,可以处理大量的请求。

这点是性能的核心。

SpringCloud + Dubbo RPC 的集成的价值

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

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

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

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

尼恩强烈建议大家,做一下 SpringCloud + Dubbo RPC 的集成,在同一个微服务下,同时使用了Feign + Dubbo。

尼恩提示:很多小伙伴来找尼恩改简历,但是发现一点漂亮的技术亮点都没有,如果确实找不到亮点,可以把这个实操做一下,写入简历,作为亮点。如果确实不清楚怎么写入简历,可以来找尼恩进行简历指导。保证 脱胎换骨、金光闪闪、天衣无缝。

参考文献

全链路异步,让你的 SpringCloud 性能优化10倍+

https://blog.csdn.net/wpc2018/article/details/122634049

https://www.jianshu.com/p/7d80b94068b3

https://blog.csdn.net/yhj_911/article/details/119540000

http://bjqianye.cn/detail/6845.html

https://blog.csdn.net/hao134838/article/details/110824092

https://blog.csdn.net/hao134838/article/details/110824092

https://blog.csdn.net/weixin_34096182/article/details/91436704

https://blog.csdn.net/fly910905/article/details/121682625

https://gaocher.github.io/2020/01/05/mono-create/

推荐阅读:

《响应式圣经:10W字,实现Spring响应式编程自由》

《4次迭代,让我的 Client 优化 100倍!泄漏一个 人人可用的极品方案!》

《100亿级订单怎么调度,来一个大厂的极品方案》

《Linux命令大全:2W多字,一次实现Linux自由》

《阿里一面:你做过哪些代码优化?来一个人人可以用的极品案例》

《网易二面:CPU狂飙900%,该怎么处理?》

《阿里二面:千万级、亿级数据,如何性能优化? 教科书级 答案来了》

《峰值21WQps、亿级DAU,小游戏《羊了个羊》是怎么架构的?》

《场景题:假设10W人突访,你的系统如何做到不 雪崩?》

《2个大厂 100亿级 超大流量 红包 架构方案》

《Nginx面试题(史上最全 + 持续更新)》

《K8S面试题(史上最全 + 持续更新)》

《操作系统面试题(史上最全、持续更新)》

《Docker面试题(史上最全 + 持续更新)》

《Springcloud gateway 底层原理、核心实战 (史上最全)》

《Flux、Mono、Reactor 实战(史上最全)》

《sentinel (史上最全)》

《Nacos (史上最全)》

《TCP协议详解 (史上最全)》

《分库分表 Sharding-JDBC 底层原理、核心实战(史上最全)》

《clickhouse 超底层原理 + 高可用实操 (史上最全)》

《nacos高可用(图解+秒懂+史上最全)》

《队列之王: Disruptor 原理、架构、源码 一文穿透》

《环形队列、 条带环形队列 Striped-RingBuffer (史上最全)》

《一文搞定:SpringBoot、SLF4j、Log4j、Logback、Netty之间混乱关系(史上最全)》

《单例模式(史上最全)》

《红黑树( 图解 + 秒懂 + 史上最全)》

《分布式事务 (秒懂)》

《缓存之王:Caffeine 源码、架构、原理(史上最全,10W字 超级长文)》

《缓存之王:Caffeine 的使用(史上最全)》

《Java Agent 探针、字节码增强 ByteBuddy(史上最全)》

《Docker原理(图解+秒懂+史上最全)》

《Redis分布式锁(图解 - 秒懂 - 史上最全)》

《Zookeeper 分布式锁 - 图解 - 秒懂》

《Zookeeper Curator 事件监听 - 10分钟看懂》

《Netty 粘包 拆包 | 史上最全解读》

《Netty 100万级高并发服务器配置》

《Springcloud 高并发 配置 (一文全懂)》

相关文章:

SpringCloud+Dubbo3 = 王炸 !

前言 全链路异步化的大趋势来了 随着业务的发展&#xff0c;微服务应用的流量越来越大&#xff0c;使用到的资源也越来越多。 在微服务架构下&#xff0c;大量的应用都是 SpringCloud 分布式架构&#xff0c;这种架构总体上是全链路同步模式。 全链路同步模式不仅造成了资源…...

机器学习主要内容的思维导图

机器学习 机器学习&#xff1a; 定义&#xff1a;能够从经验中学习从而能够 把事情不断做好的计算机程序 人工智能的一个分支和 实现方式 理论基础&#xff1a;概率论 数理统计 线性代数 数学分析 数值逼近 最优化理论 计算复杂理论 核心要素&#xff1a;数据 算法 模型 机器…...

嵌套走马灯Carousel

Carousel 的应用很广泛&#xff0c;基础用法这里不多做阐述&#xff0c;感兴趣的可以去element-gui了解Carousel 组件。 今天主要是梳理嵌套走马灯的逻辑&#xff0c;背景如下&#xff1a; 需要对项目做一个展示&#xff0c;项目可能有一个或多个&#xff0c;同时一个项目可能…...

实战——缓存的使用

文章目录前言概述实践一、缓存数据一致1.更新缓存类2.删除缓存类二、项目实践&#xff08;商城项目&#xff09;缓存预热双缓存机制前言 对于我们日常开发的应用系统。由于MySQL等关系型数据库读写的并发量是有一定的上线的&#xff0c;当请求量过大时候那数据库的压力一定会上…...

2023年中职网络安全竞赛跨站脚本渗透解析-2(超详细)

跨站脚本渗透 任务环境说明:需求环境可私信博主! 服务器场景:Server2126(关闭链接)服务器场景操作系统:未知访问服务器网站目录1,根据页面信息完成条件,将获取到弹框信息作为flag提交;访问服务器网站目录2,根据页面信息完成条件,将获取到弹框信息作为flag提交;访问…...

Scala的简单使用

文章目录Scala的简单使用&#xff08;一&#xff09;交互模式1、命令行方式2、文件方式&#xff08;二&#xff09;编译模式1、创建源程序2、编译成字节码3、解释执行对象Scala的简单使用 Scala可以在交互模式和编译模式两种方式下运行 &#xff08;一&#xff09;交互模式 在…...

Java之前缀和算法

目录 一.前缀和 1.前缀和介绍 2.编程中的前缀和 二.一维数组的动态和 1.题目描述 2.问题分析 3.代码实现 三.除自身以外数组的乘积 1.题目描述 2.问题分析 3.代码实现 四.和为 K 的子数组 1.题目描述 2.问题分析 3.代码实现 五.形成两个异或相等数组的三元组数目…...

基于GIS计算降雨侵蚀力R因子

一、数据来源介绍 &#xff08;一&#xff09;行政边界数据 本文所用到的河北唐山行政边界数据来源于中国科学院资源环境科学与数据中心&#xff08;https://www.resdc.cn/Default.aspx&#xff09;。 &#xff08;二&#xff09;降水量数据 本文所用到的降水量数据来源于国家…...

大数据时代下的企业网络安全

在大数据技术迅猛发展的今天&#xff0c;网络安全问题已经发展成一个广受关注的热门研究方向。有人说&#xff0c;“大数据下&#xff0c;人人裸奔”&#xff0c;隐私保护、数据防护日益成为广大学者、企业研究的焦点。 面对这种安全威胁&#xff0c;企业必须实施一些有效的信…...

【跟我一起读《视觉惯性SLAM理论与源码解析》】第三章第四章 SLAM中常用的数学基础知识相机成像模型

齐次坐标能大大简化在三维空间中点、线、面表达方式和旋转、平移等操作在齐次坐标下&#xff0c;两个点的叉积结果可以表示一条直线l;也可以用两条直线的叉积结果表示它们的齐次坐标交点&#xff0c;关于叉积其实十四讲解释的还是比较清楚的&#xff0c;和李代数李群的关系可以…...

LeetCode 242. 有效的字母异位词

242. 有效的字母异位词 难度&#xff1a;easy\color{Green}{easy}easy 题目描述 给定两个字符串 sss 和 ttt &#xff0c;编写一个函数来判断 ttt 是否是 sss 的字母异位词。 注意&#xff1a; 若 sss 和 ttt 中每个字符出现的次数都相同&#xff0c;则称 sss 和 ttt 互为字…...

力扣mysql刷题记录

mysql刷题记录 刷题链接https://leetcode.cn/study-plan/sql/?progressjkih0qc mysql冲&#xff01;mysql刷题记录1699. 两人之间的通话次数1251. 平均售价1571. 仓库经理1445. 苹果和桔子1193. 每月交易 I1633. 各赛事的用户注册率1173. 即时食物配送 I1211. 查询结果的质量…...

Linux基础命令-lsof查看进程打开的文件

Linux基础命令-uptime查看系统负载 Linux基础命令-top实时显示系统状态 Linux基础命令-ps查看进程状态 文件目录 前言 一 命令的介绍 二 语法及参数 2.1 使用help查看命令的语法信息 2.2 常用参数 2.2.lsof命令-i参数的条件 三 命令显示内容的含义 3.1 FD 文件描述符的…...

常用电平标准

现在常用的电平标准有TTL CMOS LVTTL LVCMOS LVDS PCI等&#xff0c;下面简单介绍一下各自的供电电源、电平标准及注意事项数字电路中&#xff0c;由TTL电子元件组成电路使用的电平。电平是个电压范围。标准输出高电平(VOH): 2.4V标准输出低电平(VOL)&#xff1a;0.4V通常输出高…...

小程序开发注意点

1.组件样式隔离注意点 2.methods方法 3.自定义组件的properties参数 4.自定义组件的事件监听 5.纯数据字段 6.插槽 单个插槽 启用多插槽 使用多个插槽 7.属性绑定实现父传子功能 例如在这里有一个组件为<one></one>&#xff0c;那么可以在组件当中传入参数 &l…...

自行车出口欧盟CE认证,新版自行车标准ISO 4210:2023与ISO 8098:2023发布

2023年1月&#xff0c;国际标准化组织ISO发布了新版“自行车以及儿童自行车的测试标准”&#xff0c;即ISO 4210&#xff1a;2023以及ISO 8098:2023&#xff0c;用于取代了SO 4210&#xff1a;2015以及ISO 8098:2015。新版标准一经发布&#xff0c;立即生效。欧盟标准化委员会C…...

2020蓝桥杯真题回文日期 C语言/C++

题目描述 2020 年春节期间&#xff0c;有一个特殊的日期引起了大家的注意&#xff1a;2020 年 2 月 2 日。因为如果将这个日期按 “yyyymmdd” 的格式写成一个 8 位数是 20200202&#xff0c;恰好是一个回文数。我们称这样的日期是回文日期。 有人表示 20200202 是 “千年一遇…...

postman入门到精通之【接口知识准备】(一)

postman入门到精通之【接口知识准备】&#xff08;一&#xff09; 目录&#xff1a;导读 前言 接口测试概念 接口测试 接口测试的原理 常用接口测试工具 接口测试基础知识 接口的定义 接口的分类 HTTP接口 Web Service接口 RESTful接口 HTTP请求 统一资源定位符&…...

【算法数据结构体系篇class07】:加强堆

一、手动改写堆&#xff08;非常重要&#xff09;&#xff01;系统提供的堆无法做到的事情&#xff1a;1&#xff09;已经入堆的元素&#xff0c;如果参与排序的指标方法变化&#xff0c;系统提供的堆无法做到时间复杂度O(logN)调整&#xff01;都是O(N)的调整&#xff01;2&am…...

Taro3.x 容易踩坑的点(阻止滚动穿透,弹框蒙层父级定位)

解决弹框滚动的时候&#xff0c;下层也会滚动问题》阻止滚动穿透(react,vue)案例描述&#xff1a;页面展示时需要滚动条才可以显示完整&#xff0c;但是当我们显示弹框的时候&#xff0c;即使不需要滚动条&#xff0c;但是页面仍然可以滚动&#xff0c;并且下层内容会随着滚动变…...

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…...

label-studio的使用教程(导入本地路径)

文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...

Leetcode 3576. Transform Array to All Equal Elements

Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接&#xff1a;3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到&#xf…...

【机器视觉】单目测距——运动结构恢复

ps&#xff1a;图是随便找的&#xff0c;为了凑个封面 前言 在前面对光流法进行进一步改进&#xff0c;希望将2D光流推广至3D场景流时&#xff0c;发现2D转3D过程中存在尺度歧义问题&#xff0c;需要补全摄像头拍摄图像中缺失的深度信息&#xff0c;否则解空间不收敛&#xf…...

P3 QT项目----记事本(3.8)

3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...

【单片机期末】单片机系统设计

主要内容&#xff1a;系统状态机&#xff0c;系统时基&#xff0c;系统需求分析&#xff0c;系统构建&#xff0c;系统状态流图 一、题目要求 二、绘制系统状态流图 题目&#xff1a;根据上述描述绘制系统状态流图&#xff0c;注明状态转移条件及方向。 三、利用定时器产生时…...

现代密码学 | 椭圆曲线密码学—附py代码

Elliptic Curve Cryptography 椭圆曲线密码学&#xff08;ECC&#xff09;是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础&#xff0c;例如椭圆曲线数字签…...

Map相关知识

数据结构 二叉树 二叉树&#xff0c;顾名思义&#xff0c;每个节点最多有两个“叉”&#xff0c;也就是两个子节点&#xff0c;分别是左子 节点和右子节点。不过&#xff0c;二叉树并不要求每个节点都有两个子节点&#xff0c;有的节点只 有左子节点&#xff0c;有的节点只有…...

Webpack性能优化:构建速度与体积优化策略

一、构建速度优化 1、​​升级Webpack和Node.js​​ ​​优化效果​​&#xff1a;Webpack 4比Webpack 3构建时间降低60%-98%。​​原因​​&#xff1a; V8引擎优化&#xff08;for of替代forEach、Map/Set替代Object&#xff09;。默认使用更快的md4哈希算法。AST直接从Loa…...

【 java 虚拟机知识 第一篇 】

目录 1.内存模型 1.1.JVM内存模型的介绍 1.2.堆和栈的区别 1.3.栈的存储细节 1.4.堆的部分 1.5.程序计数器的作用 1.6.方法区的内容 1.7.字符串池 1.8.引用类型 1.9.内存泄漏与内存溢出 1.10.会出现内存溢出的结构 1.内存模型 1.1.JVM内存模型的介绍 内存模型主要分…...