
书接前文:
当项目中使用了 OpenFeign 后,可以很方便的进行远程服务调用,现在有个问题,假如远程服务出现故障了,调不了远程的接口,这边又着急等着返回结果,怎么办呢?
当然是使用 服务降级 ,本篇就使用 OpenFeign 进行远程调用,并结合 Sentinel 对出现的异常、故障等问题进行服务降级。
仍以前面 open-feign-service 服务为调用方, nacos-provider 服务为提供方来进行操练。
Open-feign-service 除了引入 spring-cloud-starter-openfeign 外,再引入 spring-cloud-starter-alibaba-sentinel 组件,另外我们这里使用 nacos 的配置中心做 Sentinel 限流规则的持久化,所以还需要引入 spring-cloud-alibaba-sentinel-datasource 和 sentinel-datasource-nacos :
<!-- 引入二方库 -->
<dependency>
<groupId>cn.chendapeng.springcloud</groupId>
<artifactId>internal-common</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel-datasource</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
复制代码

配置文件 application.yml :
spring:
application:
name: open-feign-service
cloud:
nacos:
discovery:
server-addr: 192.168.242.112:81
sentinel:
transport:
dashboard: localhost:8080
port: 8719
# https://github.com/alibaba/Sentinel/issues/1213
web-context-unify: false
# Sentinel 规则持久化到 Nacos
datasource:
rule1:
nacos:
serverAddr: 192.168.242.112:81
groupId: DEFAULT_GROUP
dataId: sentinelFlowRule.json
ruleType: flow
feign:
client:
config:
# 默认的超时时间设置
default:
connectTimeout: 5000
readTimeout: 5000
# 在指定的 FeignClient 设置超时时间,覆盖默认的设置
nacos-provider:
connectTimeout: 1000
readTimeout: 1000
loggerLevel: full
# 激活 Sentinel
sentinel:
enabled: true
复制代码
这里增加了 Sentinel 的数据持久化内容,以及激活 OpenFeign 与 Sentinel 联合使用的 feign.sentinel.enabled=true 配置。
不管是 Sentinel 限流后返回,还是 OpenFeign 的 fallback 返回,本质上他们都是出现异常了,这里配置一下全局的统一异常处理。
首先,增加一个业务异常类:
public class BusinessException extends RuntimeException {
private String code;
private String message;
public BusinessException(String code, String message) {
this.code = code;
this.message = message;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
@Override
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
复制代码
然后使用 Spring 的 @RestControllerAdvice 注解进行全局的异常进行处理:
@RestControllerAdvice
public class GlobalExceptionHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(GlobalExceptionHandler.class);
/**
* 业务异常,统一处理
* @param e 异常对象
* @return ResponseResult 全局异常响应
*/
@ExceptionHandler(BusinessException.class)
public ResponseResult<String> businessException(BusinessException e) {
LOGGER.info("code={}, message={}", e.getCode(), e.getMessage());
return ResponseResult.fail(e.getCode(), e.getMessage());
}
// 其他异常...
}
复制代码
这样,只要指定了抛出的异常类型,就会返回统一的响应格式。
在上一篇文章中,我们通过 FeignClient 接口调用远程的服务:
@Service
@FeignClient("nacos-provider")
public interface ProductService {
/**
* 调用远程服务 nacos-provider 的 product/{id} 接口
* @param id 参数 id
* @return 返回
*/
@GetMapping("/product/{id}")
String getProductById(@PathVariable("id") Long id);
}
复制代码
如果远程接口不通,这里可以在 @FeignClient 注解上增加一个属性 fallback ,该属性定义一个容错的处理类,当调用远程接口失败或超时时,会调用对应接口的容错逻辑,fallback 指定的类必须实现 @FeignClient 标记的接口。
先来定义一个实现 ProductService 的类:
@Component
@Slf4j
public class ProductServiceImpl implements ProductService {
/**
* 调用远程服务 nacos-provider 的 product/{id} 接口失败后的处理方法
*
* @param id 参数 id
* @return 返回
*/
@Override
public String getProductById(Long id) {
log.error("调用接口 getProduct 失败,id={}", id);
//return "OpenFeign 降级";
throw new BusinessException(ResponseCode.RPC_ERROR.getCode(), ResponseCode.RPC_ERROR.getMessage());
}
}
复制代码
该类需要被 Spring 识别,所以加个 @Component 。该类的实现方法可以添加实际业务的处理逻辑,本案例只是打印一些信息后直接抛出自定义的异常。
Tips :ResponseCode.RPC_ERROR 在二方库中有定义。
给 FeignClient 接口增加 fallback 属性:
@FeignClient(name = "nacos-provider", fallback = ProductServiceImpl.class)
复制代码
OK,不启动服务提供方 nacos-provider,直接调用接口测试。
接口返回:

控制台打印信息:

这样就实现了 fallback 的容错处理,即时远程服务不可用,也能进行降级处理。
在 Controller 层使用 FeignClient 定义的接口进行远程调用服务时,还可以定义 Sentinel 资源,并设置规则对资源进行限流。
@SentinelResource 的一些使用方法在前几篇文章中已有提及,这里再结合 OpenFeign 使用,本例中有如下定义:
@GetMapping("/product/{id}")
@SentinelResource(value = "getProduct",
blockHandler = "getProductBlock",
fallback = "getProductFallback")
public String getProduct(@PathVariable("id") Long id) {
return productService.getProductById(id);
}
public String getProductBlock(Long id, BlockException e) {
log.error("访问资源 getProduct 被限流,id={}", id);
throw new BusinessException("C0002", "访问资源 getProduct 被限流");
}
public String getProductFallback(Long id) {
log.error("访问资源 getProduct fallback");
return "请稍后重试";
}
复制代码
在前面的准备工作中,我们已经配置了 Sentinel 资源限流规则持久化到 Nacos,现在 Nacos 中配置一下资源 getProduct 的限流规则:
[
{
"resource": "getProduct",
"limitApp": "default",
"grade": 1,
"count": 1,
"strategy": 0,
"controlBehavior": 0,
"clusterMode": false
}
]
复制代码

限流规则是 QPS 阈值为1,只要我1秒大于1次请求就会被限流。
启动远程服务 nacos-provider ,下面来验证一下。
1秒只发一个请求的结果:

1秒内快速刷新几次,造成QPS大于1,将会被限流:

OpenFeign 整合 Sentinel 需要引入 Sentinel 相关依赖包;feign.sentinel.enabled=true 来开启 Feign 与 Sentinel的结合使用;fallback 属性,该属性定义远程接口访问有问题时的容错处理逻辑的类;fallback 定义的类需实现 @FeignClient 定义的接口。
一、机器人介绍 此处是基于MATLABRVC工具箱,对ABB-IRB-1200型号的微型机械臂进行正逆向运动学分析,并利Simulink工具实现对机械臂进行具有动力学参数的末端轨迹规划仿真,最后根据机械模型设计Simulink-Adams联合仿真。 图1.ABBIRB 1200尺寸参数示意图ABBIRB 1200提供的两种型号广泛适用于各作业,且两者间零部件通用,两种型号的工作范围分别为700 mm 和 900 mm,大有效负载分别为 7 kg 和5 kg。 IRB 1200 能够在狭小空间内能发挥其工作范围与性能优势,具有全新的设计、小型化的体积、高效的性能、易于集成、便捷的接
我正在尝试找到一种更好的方法将IRB与我的常规ruby开发集成。目前我很少在我的代码中使用IRB。我只用它来验证语法或尝试一些小的东西。我知道我可以将我自己的代码加载到ruby中作为一个require'mycode'但这通常不符合我的编程风格。有时我要检查的变量超出范围或在循环内。有没有一种简单的方法可以启动我的脚本并在IRB内的某个点卡住?我想我正在寻找一种更简单的方法来调试我的ruby代码而不破坏我的F5(编译)键。也许有经验的ruby开发者可以和我分享一个更精简的开发方法。 最佳答案 安装ruby-debugg
我开始了一个小型网络项目并使用Drupal来构建它。到目前为止,还不错:您可以快速建立一个不错的面向CMS的网站,通过模块添加社交功能,并且您有一个广泛的API可以在一个架构良好的平台中进行自定义。现在问题来了:网站的增长超出了最初的计划,我发现自己正处于认真开始为它编写代码的境地。由于Drupal项目,我对PHP有了新的认识,但我想用Ruby来做。我会感觉更舒服,以后维护起来更容易,我可以在其他Ruby/Rails应用程序中重用它。随着时间的推移,我想我会用Ruby重写Drupal中的现有部分。基于此,问题是:是否有人将两者(成功或失败的故事)结合起来?这是一个相当大的决定,但我在G
文章目录华为OD面试流程1.mysql数据库建了两个字段,且设置了联合索引,如果其中有一个字段为空会出现什么问题?2.谈谈springIOC的理解,有什么好处,解决了什么问题3.谈谈springAOP的理解,切面编程有没有实际应用,有哪些注解,作用是什么,有那些应用场景?4.Erika和zookeeper有了解过吗,作用是什么,主要解决了什么问题5.谈谈JDK、JRE、JVM的理解,区别是什么6.谈谈对泛型的理解7.JVM的组成华为OD面试流程机试:三道算法题,关于机试,橡皮擦已经准备好了各语言专栏,可以直接订阅。性格测试:机试技术一面(本专栏核心)技术二面(本专栏核心)主管面试定级定薪发of
我想从两个哈希数组中获取并集/交集/差集,例如:array1=[{:name=>'Guy1',:age=>45},{:name=>'Guy2',:age=>45}]array2=[{:name=>'Guy1',:age=>45},{:name=>'Guy3',:age=>45}]...parray1-array2=>[{:name=>"Guy2",:age=>45}]parray2-array1=>[{:name=>"Guy3",:age=>45}]parray1|array2=>[{:name=>"Guy1",:age=>45},{:name=>"Guy2",:age=>45},{:
相机内参标定,相机和激光雷达联合标定一、相机标定原理1.1成像过程1.2标定详解二、相机和激光雷达联合标定2.1标定方法汇总2.2Autoware的安装与运行2.2.1安装方式2.2.2安装Autoware的依赖(Ubuntu16.04/kinetic)2.2.3编译Autoware1.创造工作空间2.下载Autoware源码3.其他依赖4.编译5.效果2.3Autoware标定激光雷达和相机的外参过程一、相机标定原理1.1成像过程现实物体在相机中的成像过程离不开世界坐标系、相机坐标系、图像坐标系以及像素坐标系,只有理解了这些才能对获取的图像进行准确的分析。成像过程:四个坐标系如下图所示:世界
模块之间的关系我们可以了解到一共有这么多服务,我们先启动这三个服务其中rouyi–api模块是远程调用也就是提取出来的openfeign的接口ruoyi–commom是通用工具模块其他几个都是独立的服务ruoyi-api模块api模块当中有几个提取出来的OpenFeign的接口分别为文件,日志,用户服务我们以RemoteUserService接口为例子:其中contextId="remoteUserService"为bean的名称,value=ServiceNameConstants.SYSTEM_SERVICE为接口的描述,fallbackFactory=RemoteUserFallback
一、Elasticsearch简介实际业务场景中,多端的查询功能都有很大的优化空间。常见的处理方式有:建索引、建物化视图简化查询逻辑、DB层之上建立缓存、分页…然而随着业务数据量的不断增多,总有那么一张表或一个业务,是无法通过常规的处理方式来缩短查询时间的。在查询功能优化上,作为开发人员应该站在公司的角度,本着优化客户体验的目的去寻找解决方案。本人有幸做过Tomcat整合solr,今天一起研究一下当前比较火热的Elasticsearch搜索引擎。Elasticsearch是一个非常强大的搜索引擎。它目前被广泛地使用于各个IT公司。Elasticsearch是由Elastic公司创建。它的代码位
我有一个包含多个时间范围的数组:[Tue,24May201108:00:00CEST+02:00..Tue,24May201113:00:00CEST+02:00,Tue,24May201116:30:00CEST+02:00..Tue,24May201118:00:00CEST+02:00,Tue,24May201108:00:00CEST+02:00..Tue,24May201109:00:00CEST+02:00,Tue,24May201115:30:00CEST+02:00..Tue,24May201118:00:00CEST+02:00]我想获得具有重叠时间范围组合的相同数组
我有两个数组需要合并,使用Union(|)运算符非常慢..还有其他方法可以完成数组合并吗?此外,数组中填充的是对象,而不是字符串。数组中对象的示例#events.waikato.ac其中source是一小段XML。编辑对不起!“合并”是指我不需要插入重复项。A=>[1,2,3,4,5]B=>[3,4,5,6,7]A.magic_merge(B)#=>[1,2,3,4,5,6,7]了解整数实际上是Article对象,并且Union运算符似乎永远 最佳答案 这是一个对两种合并技术进行基准测试的脚本:使用管道运算符(a1|a2)和使用co