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 调用共存。
方便后续在业务中快速运用,完整结构如下:
- consumer,服务消费方模块;
- provider,服务提供方模块;
- 统一定义服务接口和实体类,被其他工程模块引用;
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 = 王炸 !
前言 全链路异步化的大趋势来了 随着业务的发展,微服务应用的流量越来越大,使用到的资源也越来越多。 在微服务架构下,大量的应用都是 SpringCloud 分布式架构,这种架构总体上是全链路同步模式。 全链路同步模式不仅造成了资源…...

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

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

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

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

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

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

基于GIS计算降雨侵蚀力R因子
一、数据来源介绍 (一)行政边界数据 本文所用到的河北唐山行政边界数据来源于中国科学院资源环境科学与数据中心(https://www.resdc.cn/Default.aspx)。 (二)降水量数据 本文所用到的降水量数据来源于国家…...

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

【跟我一起读《视觉惯性SLAM理论与源码解析》】第三章第四章 SLAM中常用的数学基础知识相机成像模型
齐次坐标能大大简化在三维空间中点、线、面表达方式和旋转、平移等操作在齐次坐标下,两个点的叉积结果可以表示一条直线l;也可以用两条直线的叉积结果表示它们的齐次坐标交点,关于叉积其实十四讲解释的还是比较清楚的,和李代数李群的关系可以…...

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

力扣mysql刷题记录
mysql刷题记录 刷题链接https://leetcode.cn/study-plan/sql/?progressjkih0qc mysql冲!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等,下面简单介绍一下各自的供电电源、电平标准及注意事项数字电路中,由TTL电子元件组成电路使用的电平。电平是个电压范围。标准输出高电平(VOH): 2.4V标准输出低电平(VOL):0.4V通常输出高…...

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

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

2020蓝桥杯真题回文日期 C语言/C++
题目描述 2020 年春节期间,有一个特殊的日期引起了大家的注意:2020 年 2 月 2 日。因为如果将这个日期按 “yyyymmdd” 的格式写成一个 8 位数是 20200202,恰好是一个回文数。我们称这样的日期是回文日期。 有人表示 20200202 是 “千年一遇…...

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

【算法数据结构体系篇class07】:加强堆
一、手动改写堆(非常重要)!系统提供的堆无法做到的事情:1)已经入堆的元素,如果参与排序的指标方法变化,系统提供的堆无法做到时间复杂度O(logN)调整!都是O(N)的调整!2&am…...

Taro3.x 容易踩坑的点(阻止滚动穿透,弹框蒙层父级定位)
解决弹框滚动的时候,下层也会滚动问题》阻止滚动穿透(react,vue)案例描述:页面展示时需要滚动条才可以显示完整,但是当我们显示弹框的时候,即使不需要滚动条,但是页面仍然可以滚动,并且下层内容会随着滚动变…...

SpringBoot+ActiveMQ-发布订阅模式(消费端)
ActiveMQ消息中间件的发布订阅模式 主题 topictopic生产端案例(配合topic消费端测试):SpringBootActiveMQ Topic 生产端ActiveMQ版本:apache-activemq-5.16.5案例源码:SpringBootActiveMQ-发布订阅DemoSpringBoot集成ActiveMQ Topic消费端的pom.xml<?…...

vscode下使用arduino插件开发ESP32 Heltec WiFi_Kit_32_V3
下载vsCode 添加 arduino 插件 在Arduino IDE 中添加开发板,注意只能用右侧的开发板管理器添加,自己下载之后复制进去的IDE认,但是vsCode不认,搜索ESP32 第一个库里面只有到V2的,没有V3,要安装下面那个 H…...

吐血整理AutoSAR Com-Stack 的配置【基于ETAS】
总目录链接>> AutoSAR入门和实战系列总目录 文章目录01.软件组件和系统说明02.基本软件配置03.系统数据映射04.代码生成05.代码整合06.测试下图显示了基于 AUTOSAR 的 ECU SW 的结构。纵观BSW,大体分为三层。三层模块中,与通信相关的模块称为通信…...

面向对象进阶之元类
6. 元类 Python 中一切皆对象,对象是由类实例化产生的。那么类应该也有个类去产生它,利用 type() 函数我们可以去查看: class A:pass a1 A() print(type(a1)) print(type(A))<class __main__.A> <class type>由上可知…...

【Android AIDL之详细使用】
Android AIDL之详细使用一级目录概述使用场景语法相关编码实践服务端:java文件修改AndroidManifest客户端坑一级目录 概述 AIDL叫Android接口定义语言,是用于辅助开发者完成Android跨进程编程的工具。 从某种意义上说AIDL其实是一个模板,因…...

ASP.NET MVC | 简介
目录 前提 1.教程 2.MVC 编程模式 最后 前提 在学习学过很多课程,但是最主要学的还是ASP.NET MVC这门课程,工作也是用的ASP.NET MVC,所以写一点ASP.NET MVC的东西,大家可以来看看,我自己不会的时候也不用找别的地方…...

95后刚毕业2、3年就年薪50W,才发现,打败我们的不是年龄····
一刷朋友圈,一读公众号,一打开微博,甚至是一和朋友聊天,这些让人焦虑的话题总会铺天盖地的袭来: Ta刚毕业半年,就升职加薪当上了测试主管 (同样是一天24小时,为什么同龄人正在抛弃…...

动态分析和静态分析最主要的区别是什么?
动态分析和静态分析主要的区别是什么? 动态分析和静态分析的主要区别是是否考虑时间因素。 动态分析(dynamic analysis)是相对于静态分析来讲的,动态分析是只改变一下自变量,因变量相应的做出的改变,动态改…...

WebUI 学习笔记
WebUI 学习笔记 背景此插件主要用于在数字孪生方向做 UI 显示的效果。比如一些温度曲线需要显示出来,可以直接用插件,配合html 文件,直接显示出来。 准备工作我们采用4.27 版本进行开发;...

C# 中常见的设计模式附带代码案例
设计模式是一套被广泛应用于软件设计的最佳实践,它们可以帮助开发者解决特定的问题,提高代码的可重用性、可读性和可维护性。本文将介绍 C# 中常见的几种设计模式,并提供相应的示例代码。 工厂模式 工厂模式是一种创建型设计模式,…...