Spring Cloud Alibaba系列(六)sentinel的实际应用
一、sentinel的持久化配置
上一章中我们通过Dashboard来为Sentinel客户端设置各种各样的规则,但是这些规则默认是存放在内存中,极不稳定,无法用于生成环境,所以需要将其持久化。
DataSource
扩展常见的实现方式有:
- 拉模式:客户端主动向某个规则管理中心定期轮询拉取规则,这个规则中心可以是 RDBMS、文件,甚至是 VCS 等。这样做的方式是简单,缺点是无法及时获取变更;
- 推模式:规则中心统一推送,客户端通过注册监听器的方式时刻监听变化,比如使用 Nacos、Zookeeper 等配置中心。这种方式有更好的实时性和一致性保证。
Sentinel 目前支持以下数据源扩展:
生产环境中一般常用的就是推模式
。这里我们使用Nacos存储规则。推送模式的正确做法应该是 配置中心控制台/Sentinel 控制台 → 配置中心 → Sentinel 数据源 → Sentinel。
1.1 sentinel同步nacos配置
- 增加sentinel的依赖和nacos存储扩展依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
- 添加nacos相关配置
spring:
cloud:
sentinel:
datasource:
# 名称随意
javatrip:
nacos:
server-addr: 127.0.0.1:8848
dataId: ${spring.application.name}-rules
groupId: SENTINEL_GROUP
# 规则类型,取值见:
# org.springframework.cloud.alibaba.sentinel.datasource.RuleType
rule-type: flow
- 提供接口用于测试限流
@RestController
class test{
@RequestMapping("/test")
public String test(){
return "Java旅途";
}
}
- nacos中增加限流规则的配置
- resource:资源名,即限流规则的作用对象
- limitApp:流控针对的调用来源,若为 default 则不区分调用来源
- grade:限流阈值类型(QPS 或并发线程数);
0
代表根据并发数量来限流,1
代表根据QPS来进行流量控制 - count:限流阈值
- strategy:调用关系限流策略
- controlBehavior:流量控制效果(直接拒绝、Warm Up、匀速排队)
- clusterMode:是否为集群模式
- 测试,访问test接口,发现sentinel-dashboard中出现了一条流控规则
1.2 sentinel-dashboard中修改规则同步到nacos
要想实现在sentinel-dashboard中修改规则并同步到nacos,我们就需要修改sentinel服务。首先我们去官网下载Sentinel。
- 修改pom文件
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
<scope>test</scope>
</dependency>
将test注释掉,因为这个是作用与test目录下的。
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
<!--<scope>test</scope>-->
</dependency>
- 找到
sentinel-dashboard/src/test/java/com/alibaba/csp/sentinel/dashboard/rule/nacos
目录,将整个目录拷贝到sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/rule/
。 - 找到
com.alibaba.csp.sentinel.dashboard.controller.v2.FlowControllerV2
,将默认动态规则修改为nacos动态规则。
@Autowired
@Qualifier("flowRuleDefaultProvider")
private DynamicRuleProvider<List<FlowRuleEntity>> ruleProvider;
@Autowired
@Qualifier("flowRuleDefaultPublisher")
private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;
修改为:
@Autowired
@Qualifier("flowRuleNacosProvider")
private DynamicRuleProvider<List<FlowRuleEntity>> ruleProvider;
@Autowired
@Qualifier("flowRuleNacosPublisher")
private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;
- 找到
sentinel-dashboard/src/main/webapp/resources/app/scripts/directives/sidebar/sidebar.html
将以下内容注释去掉
<!--<li ui-sref-active="active" ng-if="entry.appType==0">-->
<!--<a ui-sref="dashboard.flow({app: entry.app})">-->
<!--<i class="glyphicon glyphicon-filter"></i> 流控规则 V1</a>-->
<!--</li>-->
重新编译打包,运行打包后的sentinel-dashboard.jar。
测试,我们删除nacos中的流量规则配置
- 在sentinel-dashboard——>流量规则V1中新增一个规则。
- 刷新nacos,发现多了一个配置
- 在nacos中修改这个配置,将阀值改为1
- 刷新sentinel-dashboard,流量阀值修改为1了。
- 重启服务,重启sentinel-dashboard,发现流控规则依然存在。
注意:以上只是演示了流控规则的持久化,sentinel还支持其他规则,如果想实现哪种规则都可以采用相同的方式实现!
二、Gateway网关限流
限流:就是请求多了,对请求进行定制的快速响应处理,应用在服务提供者本身。
从 1.6.0 版本开始,Sentinel 提供了 Spring Cloud Gateway 的适配模块,可以提供两种资源维度的限流:
- route 维度:即在 Spring 配置文件中配置的路由条目,资源名为对应的 routeId
- 自定义 API 维度:用户可以利用 Sentinel 提供的 API 来自定义一些 API 分组
- 添加依赖
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
<version>x.y.z</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-simple-http</artifactId>
</dependency>
- 注入对应的
SentinelGatewayFilter
实例以及SentinelGatewayBlockExceptionHandler
实例。
@Configuration
public class GatewayConfiguration {
private final List<ViewResolver> viewResolvers;
private final ServerCodecConfigurer serverCodecConfigurer;
public GatewayConfiguration(ObjectProvider<List<ViewResolver>> viewResolversProvider,
ServerCodecConfigurer serverCodecConfigurer) {
this.viewResolvers=viewResolversProvider.getIfAvailable(Collections::emptyList);
this.serverCodecConfigurer = serverCodecConfigurer;
}
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
// Register the block exception handler for Spring Cloud Gateway.
return new MySentinelGatewayBlockExceptionHandler(viewResolvers,serverCodecConfigurer);
}
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public GlobalFilter sentinelGatewayFilter() {
return new SentinelGatewayFilter();
}
}
- 自定义异常处理
public class MySentinelGatewayBlockExceptionHandler extends SentinelGatewayBlockExceptionHandler {
private List<ViewResolver> viewResolvers;
private List<HttpMessageWriter<?>> messageWriters;
public MySentinelGatewayBlockExceptionHandler(List<ViewResolver> viewResolvers, ServerCodecConfigurer serverCodecConfigurer) {
super(viewResolvers,serverCodecConfigurer);
this.viewResolvers = viewResolvers;
this.messageWriters = serverCodecConfigurer.getWriters();
}
@Override
public Mono<Void> handle(ServerWebExchange serverWebExchange, Throwable throwable) {
if(serverWebExchange.getResponse().isCommitted()){
return Mono.error(throwable);
}
if(!BlockException.isBlockException(throwable)){
return Mono.error(throwable);
}
return handleBlockedRequest(serverWebExchange, throwable).flatMap(response -> writeResponse(response, serverWebExchange));
}
private Mono<ServerResponse> handleBlockedRequest(ServerWebExchange exchange, Throwable throwable) {
return GatewayCallbackManager.getBlockHandler().handleRequest(exchange, throwable);
}
private final Supplier<ServerResponse.Context> contextSupplier = () -> new ServerResponse.Context() {
@Override
public List<HttpMessageWriter<?>> messageWriters() {
return MySentinelGatewayBlockExceptionHandler.this.messageWriters;
}
@Override
public List<ViewResolver> viewResolvers() {
return MySentinelGatewayBlockExceptionHandler.this.viewResolvers;
}
};
private Mono<Void> writeResponse(ServerResponse response, ServerWebExchange exchange) {
ServerHttpResponse resp = exchange.getResponse();
resp.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
String json = "{\"code\": -1, \"data\": null, \"msg\": \"访问量过大,请稍后再试\"}";
DataBuffer buffer = resp.bufferFactory().wrap(json.getBytes(StandardCharsets.UTF_8));
return resp.writeWith(Mono.just(buffer));
}
}
- 配置路由
server:
port: 7003
spring:
application:
name: alibaba-gateway
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
gateway:
enabled: true
discovery:
locator:
enabled: true # 开启从注册中心动态创建路由的功能,利用微服务名称进行路由
routes:
- id: sentinel-nacos # 路由id,建议配合服务名
uri: lb://sentinel-nacos #匹配路由名
predicates:
- Path=/sentinel/** # 断言,路径相匹配的进行路由
filters:
- StripPrefix=1
- 添加启动参数
-Dcsp.sentinel.app.type=1 -Dcsp.sentinel.dashboard.server=localhost:8081 -Dproject.name=alibaba-gateway
- 访问接口,查看效果
三、feign调用实现熔断降级
降级:就是服务崩溃了,所以降级逻辑应该应用在消费者(调用者)那里,加在服务提供者本身是毫无意义的,因为服务已经断开了。
我们根据实际需求在sentinel-dashboard中配置降级规则,然后编写代码。
- 定义接口
@RequestMapping("/test")
public String test(){
return "Java旅途";
}
- 定义远程服务调用接口
@FeignClient(name = "nacos-sentinel",fallback = RmoteTestFallback.class)
interface RemoteTest{
@RequestMapping("/test")
public String test();
}
为了简写fallback,我们更倾向于用fallbackFactory = RmoteTestFallbackFactory.class
@FeignClient(name = "nacos-sentinel",fallbackFactory = RmoteTestFallbackFactory.class)
interface RemoteTest{
@RequestMapping("/test")
public String test();
}
- 服务降级处理fallback
@Component
class RmoteTestFallback implements RemoteTest{
@Override
public String test() {
return null;
}
}
- 服务降级处理fallbackFactory
@Component
class RmoteTestFallbackFactory implements FallbackFactory<RemoteTest> {
@Override
public RemoteTest create(Throwable throwable) {
return null;
}
}
Spring Cloud Alibaba系列(六)sentinel的实际应用的更多相关文章
- Spring Cloud Alibaba系列(一)nacos作为服务注册中心
Spring Cloud Alibaba各组件版本关系 Spring Cloud Alibaba Version Sentinel Version Nacos Version RocketMQ Ver ...
- Spring Cloud Alibaba系列之分布式服务组件Dubbo
本博客的例子代码可以在github找到下载链接:代码下载 SpringBoot.SpringCloud Alibaba系列博客专栏:链接 1.分布式理论 1.1.分布式基本定义 <分布式系统原理 ...
- Spring Cloud Alibaba系列(二)nacos作为服务配置中心
Nacos 提供用于存储配置和其他元数据的 key/value 存储,为分布式系统中的外部化配置提供服务器端和客户端支持.使用 Spring Cloud Alibaba Nacos Config,您可 ...
- Spring Cloud Alibaba系列(五)sentinel实现服务限流降级
一.sentinel是什么 sentinel的官方名称叫分布式系统的流量防卫兵.Sentinel 以流量为切入点,从流量控制.熔断降级.系统负载保护等多个维度保护服务的稳定性.在Spring Clou ...
- spring cloud 入门系列六:使用Zuul 实现API网关服务
通过前面几次的分享,我们了解了微服务架构的几个核心设施,通过这些组件我们可以搭建简单的微服务架构系统.比如通过Spring Cloud Eureka搭建高可用的服务注册中心并实现服务的注册和发现: 通 ...
- Spring Cloud Alibaba系列(三)使用feign进行服务调用
什么是Feign Feign是spring cloud提供的一个声明式的伪http客户端,它使得调用远程服务就像调用本地服务一样简单,只需要创建一个接口并添加一天注解即可. Nacos很好的兼容了Fe ...
- Spring Cloud Alibaba系列(四)使用gateway作为服务网关
什么是网关 在微服务架构里,服务的粒度被进一步细分,各个业务服务可以被独立的设计.开发.测试.部署和管理.这时,各个独立部署单元可以用不同的开发测试团队维护,可以使用不同的编程语言和技术平台进行设计, ...
- Spring Cloud Alibaba 新一代微服务解决方案
本篇是「跟我学 Spring Cloud Alibaba」系列的第一篇, 每期文章会在公众号「架构进化论」进行首发更新,欢迎关注. 1.Spring Cloud Alibaba 是什么 Spring ...
- Spring Cloud Alibaba 从孵化到 "挂牌" 之旅
背景 2014 年,Spring Boot 1.0 发布.Spring Boot 的发布绝对是 Pivotal 历史上具有里程碑意义的事件,它让我们能够非常简便地开发 Spring 应用,屏蔽了各种配 ...
随机推荐
- XStrea学习手册
一.前言 1.XStream官网 http://x-stream.github.io 2.XStream是什么 XStream是一个简单的基于Java的类库,用来将Java对象序列化成XML(J ...
- Java培训Day02——制作疫情地图(一)
一.前言 此次培训,是为期三天的网上培训.最终的目的是制作出疫情地图.首先我们来看看主要的讲课内容大纲. Day1 |-Java语法学习(个人感觉讲得还可以,主要围绕本次培训作出的讲解,没有像网上的基 ...
- Windows下虚拟机Linux(CentOS8)扩容设置 - 磁盘扩容中的坑和解决方法
摘要:[原创]转载请注明作者Johnthegreat和本文链接 由于虚拟机空间不足,为了避免重装虚拟机,做了一次无损扩容. 过程中的报错如下: [root@localhost ~]# pvcrea ...
- Cypress系列(17)- 查找页面元素的辅助方法
如果想从头学起Cypress,可以看下面的系列文章哦 https://www.cnblogs.com/poloyy/category/1768839.html 前言 单一的基础定位元素方法并不一定能满 ...
- 一个可扩展的弹幕播放器的HTML5实现范例---ABPlayerHTML5
ABPlayerHTML5 是一个简单易懂的现代弹幕魔法播放器.这个项目意在取代基于 Flash 的 ABPlayer,同时也希望能为新一代的HTML5弹幕播放器打造一个实现范例.这个播放器將用相对通 ...
- [转] 浅谈C++中的那些内存泄露
点击阅读原文 尽管学过C语言.可是C++里面的一些基础还是不太懂,还须要再掌握. 对于内存泄露,我的个人理解就是程序在执行过程中,自己开辟了空间,用完这块空间后却没有释放. 今晚上我就犯了这种低级错误 ...
- Dart Memo for Android Developers
Dart Memo for Android Developers Dart语言一些语法特点和编程规范. 本文适合: 日常使用Kotlin, 突然想写个Flutter程序的Android程序员. Dar ...
- ado.net Web前端:关于JavaScript知识点的简单梳理
学习js:1.htmml2.cssjs+html+css == html5 js的组成:1).ecamscript ES是js的标准,js 是es 的实现2)文档对象模型(Document Objec ...
- css方法1(清除ul边距间隙,两端对齐,字母大写,首字放大)
一.清除ul自带左边间距 ul{ margin:; padding:; } 二.ul li 与li 之间隙 1.ul 设置font-size:0 ; 子li 设置字体大小 2.把li写到一起,不换行 ...
- cb44a_c++_STL_算法_删除_(2)remove_copy_remove_copy_if
cb44a_c++_STL_算法_删除_(2)remove_copy_remove_copy_if remove_copy()//在复制过程中删除一些数据remove_copy_if() 删除性算法: ...