Sentinel流控与熔断
参考: https://thinkwon.blog.csdn.net/article/details/103770879
项目结构
com.guo
├── guo-sentinel // sentinel限流熔断学习
│ └── guo-sentinel-base // [9204]消费端,限流、熔断在这里体现
│ └── guo-sentinel-provider // [9205]接口提供端
安装Sentinel控制台
Sentinel控制台是一个轻量级的控制台应用,它可用于实时查看单机资源监控及集群资源汇总,并提供了一系列的规则管理功能,如流控规则、降级规则、热点规则等。
下载</br> 可以从https://github.com/alibaba/Sentinel/releases下载sentinel-dashboard-$version.jar包。我这里下载的是 sentinel-dashboard-1.8.0.jar 版本。可以从百度云盘下载 提取码:0708
启动控制台
java -Dserver.port=8718 -Dcsp.sentinel.dashboard.server=localhost:8718 -Dproject.name=sentinel-dashboard -Dcsp.sentinel.api.port=8719 -jar D:\bgy\install\微服务\sentinel-dashboard-1.8.0.jar
其中-Dserver.port=8718用于指定Sentinel控制台端口为8718,D:\bgy\install\微服务\sentinel-dashboard-1.8.0.jar为下载的包路径地址。
打开控制台</br> Sentinel提供了一个可视化的操作平台,安装好之后,在浏览器中输入(http://localhost:8718 (opens new window))就可以访问了,默认的用户名和密码都是sentinel(我使用的是1.8.0版本)
限流
添加依赖
<!-- 在guo-sentinel导入依赖 -->
<dependencyManagement>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud.alibaba}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencyManagement>
<!-- 在guo-sentinel-base添加依赖 -->
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
<version>${spring-cloud.alibaba}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
添加bootstrap.yml配置
server:
port: 9100
address: localhost
spring:
application:
name: guo-sentinel-base
cloud:
sentinel:
transport:
dashboard: localhost:8718 #sentinel控制台的请求地址
按资源名称限流
在guo-sentinel-base编写需要限流的资源接口
import java.util.HashMap;
import java.util.Map;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.guo.sentinel.handle.CustomBlockHandler;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@RestController
@RequestMapping("/rateLimit")
public class RateLimitController {
/**
* 按资源名称限流,需要指定限流处理逻辑
*
* @return
*/
@GetMapping("/byResource")
@SentinelResource(value = "byResource", blockHandler = "handleException")
public Map<String,Object> byResource() {
log.info("/rateLimit/byResource");
Map<String,Object> result = new HashMap<>();
result.put("name","按资源名称限流");
result.put("code",200);
return result ;
}
/**
* 按url限流,有默认的限流处理逻辑
*
* @return
*/
@GetMapping("byUrl")
@SentinelResource(value = "byUrl", blockHandler = "handleException")
public Map<String,Object> byUrl() {
log.info("/rateLimit/byResource");
Map<String,Object> result = new HashMap<>();
result.put("name","按url限流");
result.put("code",200);
return result ;
}
public Map<String,Object> handleException(BlockException exception) {
Map<String,Object> result = new HashMap<>();
result.put("name",exception.getClass().getCanonicalName());
result.put("code",200);
return result ;
}
@GetMapping("/customBlockHandler")
@SentinelResource(value = "customBlockHandler", blockHandler = "handleException", blockHandlerClass = CustomBlockHandler.class)
public Map<String,Object> blockHandler() {
Map<String,Object> result = new HashMap<>();
result.put("name","限流成功");
result.put("code",200);
return result ;
}
}
在项目guo-sentinel-provider编写远程测试接口
controller
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.guo.sentinel.service.UserService;
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@PostMapping("/insert")
public Map<String,Object> insert(@RequestBody Map<String,Object> user) {
return userService.insert(user);
}
@GetMapping("/{id}")
public Map<String,Object> getUser(@PathVariable Long id) {
return userService.getUser(id);
}
@GetMapping("/listUsersByIds")
public Map<String,Object> listUsersByIds(@RequestParam List<Long> ids) {
return userService.listUsersByIds(ids);
}
@GetMapping("/getByUsername")
public Map<String,Object> getByUsername(@RequestParam String username) {
return userService.getByUsername(username);
}
@PostMapping("/update")
public Map<String,Object> update(@RequestBody Map<String,Object> user) {
return userService.update(user);
}
@PostMapping("/delete/{id}")
public Map<String,Object> delete(@PathVariable Long id) {
return userService.delete(id);
}
}
service
import java.util.List;
import java.util.Map;
public interface UserService {
Map<String,Object> insert(Map<String,Object> user);
Map<String,Object> getUser(Long id);
Map<String,Object> listUsersByIds(List<Long> ids);
Map<String,Object> getByUsername(String username);
Map<String,Object> update(Map<String,Object> user);
Map<String,Object> delete(Long id);
}
service.impl
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.stereotype.Service;
import com.guo.sentinel.service.UserService;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Service
public class UserServiceImpl implements UserService {
@Override
public Map<String, Object> insert(Map<String, Object> user) {
log.info("新增:{}", user);
return null;
}
@Override
public Map<String, Object> getUser(Long id) {
log.info("获取:{}", id);
if(Long.valueOf("1").equals(id)) {
throw new RuntimeException("remote func is fail");
}
Map<String,Object> result = new HashMap<>();
result.put("reqData",id);
result.put("code","200");
return result ;
}
@Override
public Map<String, Object> listUsersByIds(List<Long> ids) {
log.info("获取集合:{}", ids);
return null;
}
@Override
public Map<String, Object> getByUsername(String username) {
log.info("根据用户名获取:{}", username);
if(1==1) throw new RuntimeException("模拟异常");
return null;
}
@Override
public Map<String, Object> update(Map<String, Object> user) {
log.info("更新:{}", user);
return null;
}
@Override
public Map<String, Object> delete(Long id) {
log.info("删除:{}", id);
return null;
}
}
在nacos配置guo-sentinel-base-dev.yml中添加远程调用接口地址
service-url:
user-service: http://localhost:9205
在sentinel控制台给资源添加限流规则
资源名称必须与流量控制定义的资源名称一致
快速访问接口发现资源被限流, 设置1QPS,连续访问2次以上发现,远程服务并未被调用,直接走了限流逻辑
##按url限流
在sentinel控制台给资源添加限流规则
资源名称必须与流量控制定义的资源访问全路径一致
自定义限流逻辑
用blockHandlerClass = CustomBlockHandler.class指定限流逻辑
import com.alibaba.csp.sentinel.slots.block.BlockException;
import java.util.HashMap;
import java.util.Map;
public class CustomBlockHandler {
public static Map<String,Object> handleException(BlockException exception) {
Map<String,Object> result = new HashMap<>();
result.put("name","自定义限流信息");
result.put("code",200);
return result ;
}
}
熔断
在guo-sentinel-base编写需要熔断的资源接口
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.HashMap;
import java.util.Map;
@Slf4j
@RestController
@RequestMapping("/breaker")
public class CircleBreakerController {
private static final Logger LOGGER = LoggerFactory.getLogger(CircleBreakerController.class);
@Autowired
private RestTemplate restTemplate;
@Value("${service-url.user-service}")
private String userServiceUrl;
@GetMapping("/fallback/{id}")
@SentinelResource(value = "fallback", fallback = "handleFallback")
public Map<String,Object> fallback(@PathVariable Long id) {
Map<String,Object> forObject = restTemplate.getForObject(userServiceUrl + "/user/{1}", Map.class, id);
System.out.println(forObject);
return forObject;
}
@GetMapping("/fallbackException/{id}")
@SentinelResource(value = "fallbackException", fallback = "handleFallback2", exceptionsToIgnore = {NullPointerException.class})
public Map<String,Object> fallbackException(@PathVariable Long id) {
log.info("/breaker/fallbackException");
if (id == 1) {
throw new IndexOutOfBoundsException();
} else if (id == 2) {
throw new NullPointerException();
}
return restTemplate.getForObject(userServiceUrl + "/user/{1}", Map.class, id);
}
public Map<String,Object> handleFallback(Long id) {
Map<String,Object> result = new HashMap<>();
result.put("name","服务熔断");
result.put("code",200);
return result ;
}
public Map<String,Object> handleFallback2(Long id, Throwable e) {
LOGGER.error("handleFallback2 id:{},throwable class:{}", id, e.getClass());
Map<String,Object> result = new HashMap<>();
result.put("name","服务熔断");
result.put("code",200);
return result ;
}
}
在feign接口上的限流与熔断
guo-sentinel-base添加feign接口相关依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
guo-sentinel-base中nacos添加配置项
# 打开sentinel对feign的支持
feign:
sentinel:
enabled: true
在应用启动类上添加启用feign的注解@EnableFeignClients
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class SentinelBaseApplication {
public static void main(String[] args) {
SpringApplication.run(SentinelBaseApplication.class, args);
}
}
创建feign接口
controller
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.guo.sentinel.service.UserService;
@RestController
@RequestMapping("/user")
public class UserFeignController {
@Autowired
private UserService userService;
@PostMapping("/insert")
public Map<String,Object> insert(@RequestBody Map<String,Object> user) {
return userService.insert(user);
}
@GetMapping("/{id}")
public Map<String,Object> getUser(@PathVariable Long id) {
return userService.getUser(id);
}
@GetMapping("/listUsersByIds")
public Map<String,Object> listUsersByIds(@RequestParam List<Long> ids) {
return userService.listUsersByIds(ids);
}
@GetMapping("/getByUsername")
public Map<String,Object> getByUsername(@RequestParam String username) {
return userService.getByUsername(username);
}
@PostMapping("/update")
public Map<String,Object> update(@RequestBody Map<String,Object> user) {
return userService.update(user);
}
@PostMapping("/delete/{id}")
public Map<String,Object> delete(@PathVariable Long id) {
return userService.delete(id);
}
}
service
import java.util.List;
import java.util.Map;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import com.guo.sentinel.service.impl.UserFallbackService;
// 注意value = "guo-sentinel-provider"值与服务提供方的服务注册名一致
@FeignClient(value = "guo-sentinel-provider", fallback = UserFallbackService.class)
public interface UserService {
@PostMapping("/user/insert")
Map<String,Object> insert(@RequestBody Map<String,Object> user);
@GetMapping("/user/{id}")
Map<String,Object> getUser(@PathVariable(value = "id") Long id);
@GetMapping("/user/listUsersByIds")
Map<String,Object> listUsersByIds(@RequestParam(value = "ids") List<Long> ids);
@GetMapping("/user/getByUsername")
Map<String,Object> getByUsername(@RequestParam(value = "username") String username);
@PostMapping("/user/update")
Map<String,Object> update(@RequestBody Map<String,Object> user);
@PostMapping("/user/delete/{id}")
Map<String,Object> delete(@PathVariable(value = "id") Long id);
}
fallback熔断逻辑UserFallbackService.java
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.stereotype.Service;
import com.guo.sentinel.service.UserService;
@Service
public class UserFallbackService implements UserService {
@Override
public Map<String, Object> insert(Map<String, Object> user) {
return this.installFallBack();
}
@Override
public Map<String, Object> getUser(Long id) {
return this.installFallBack();
}
@Override
public Map<String, Object> listUsersByIds(List<Long> ids) {
return this.installFallBack();
}
@Override
public Map<String, Object> getByUsername(String username) {
return this.installFallBack();
}
@Override
public Map<String, Object> update(Map<String, Object> user) {
return this.installFallBack();
}
@Override
public Map<String, Object> delete(Long id) {
return this.installFallBack();
}
private Map<String, Object> installFallBack() {
Map<String, Object> r = new HashMap<>();
r.put("code", 500);
r.put("msg", "调用失败,服务被降级");
return r;
}
}
在sentinel控制台配置熔断逻辑
统一限流处理
参考: https://zhuanlan.zhihu.com/p/150058613
使用nacos存储限流、熔断规则
默认情况下,当我们在Sentinel控制台中配置规则时,控制台推送规则方式是通过API将规则推送至客户端并直接更新到内存中。一旦我们重启应用,规则将消失。下面我们介绍下如何将配置规则进行持久化,以存储到Nacos为例。
先在guo-sentinel-base pom.xml中添加相关依赖:
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
修改bootstrap.yml添加规则配置
server:
port: 9204
spring:
application:
name: guo-sentinel-base
profiles:
active: dev
cloud:
sentinel:
transport:
# 配置Sentinel dashborad地址
dashboard: http://localhost:8718
port: 8719
# 添加Nacos数据源配置
datasource:
- nacos:
server-addr: localhost:8848
# guo-sentinel-base-flow-rules.json
data-id: ${spring.application.name}-flow-rules
group-id: DEFAULT_GROUP
data-type: json
rule-type: flow
nacos:
discovery:
server-addr: localhost:8848
config:
server-addr: localhost:8848
file-extension: yml
ext-config:
# guo-sentinel-base-dev.yml
- data-id: ${spring.application.name}-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
group: DEFAULT_GROUP
refresh: true
在nacos中新建配置guo-sentinel-base-flow-rules.json
[
{
"resource": "/rateLimit/byUrl",
"limitApp": "default",
"grade": 1,
"count": 1,
"strategy": 0,
"controlBehavior": 0,
"clusterMode": false
}
]
限流相关参数解释:
resource:资源名称;
limitApp:来源应用;
grade:阈值类型,0表示线程数,1表示QPS;
count:单机阈值;
strategy:流控模式,0表示直接,1表示关联,2表示链路;
controlBehavior:流控效果,0表示快速失败,1表示Warm Up,2表示排队等待;
clusterMode:是否集群。
熔断相关参数解释
resource:资源名,即规则的作用对象
grade:熔断策略,支持慢调用比例/异常比例/异常数策略,默认为 慢调用比例
count:慢调用比例模式下为慢调用临界 RT(超出该值计为慢调用);异常比例/异常数模式下为对应的阈值
timeWindow:熔断时长,单位为 s
minRequestAmount:熔断触发的最小请求数,请求数小于该值时即使异常比率超出阈值也不会熔断(1.7.0 引入),默认为5
statIntervalMs:统计时长(单位为 ms),如 60*1000 代表分钟级(1.8.0 引入),默认为1000ms
slowRatioThreshold:慢调用比例阈值,仅慢调用比例模式有效(1.8.0 引入)
代码地址
https://gitee.com/laiba_yun/test20210702
Sentinel流控与熔断的更多相关文章
- Spring Cloud & Alibaba 实战 | 第十二篇: 微服务整合Sentinel的流控、熔断降级,赋能拥有降级功能的Feign新技能熔断,实现熔断降级双剑合璧(JMeter模拟测试)
目录 一. Sentinel概念 1. 什么是Sentinel? 2. Sentinel功能特性 3. Sentinel VS Hystrix 二. Docker部署Sentinel Dashboar ...
- sentinel流控规则校验之源码分析
前言: 上节给大家把sentinel流控整个执行大致过了,但涉及到最核心的流控算法还没有讲,先提前说明一下 sentinel用的流控算法是令牌桶算法,参考了Guava的RateLimiter,有读过R ...
- 什么!Sentinel流控规则可以这样玩?
项目源码地址:公众号回复 sentinel,即可免费获取源码 前言 上一篇文章中,我们讲解了关于sentinel基本介绍以及流控规则中直接和快速失败的效果,有兴趣的可以去看上一篇文章,今天,我们给大家 ...
- 微服务架构 | 5.4 Sentinel 流控、统计和熔断的源码分析
目录 前言 1. Sentinel 的自动装配 1.2 依赖引入 1.3 SentinelWebAutoConfiguration 配置类 1.4 CommonFilter 过滤器 1.5 小结 2. ...
- 开发者说:Sentinel 流控功能在 SpringMVC/SpringBoot 上的实践
从用户的视角来感受一个开源项目的成长,是我们推出「开发者说」专栏的初衷,即在开发者进行开源项目选型时,提供更为立体的项目信息.专栏所有内容均来自作者原创/投稿,本文是「开发者说」的第6篇,作者 Jas ...
- SpringBoot 2.0 + Nacos + Sentinel 流控规则集中存储
前言 Sentinel 原生版本的规则管理通过API 将规则推送至客户端并直接更新到内存中,并不能直接用于生产环境.不过官方也提供了一种 Push模式,扩展读数据源ReadableDataSource ...
- Sentinel流控规则
流控规则 注:Sentinel的监控页面一开始是没有东西,需要对监控的服务发起请求后才会出现 资源名:唯一名称,默认请求路径 针对来源:Sentinel可以针对调用者进行限流,填写微服务名,指定对哪个 ...
- Spring Cloud Alibaba整合Sentinel流控
前面我们都是直接通过集成sentinel的依赖,通过编码的方式配置规则等.对于集成到Spring Cloud中阿里已经有了一套开源框架spring-cloud-alibaba,就是用于将一系列的框架成 ...
- Sentinel Slot扩展实践-流控熔断预警实现
前言 前几天公司生产环境一个服务由于流量上升触发了 Sentinel 的流控机制,然后用户反馈访问慢,定位发现是 task 定时任务导致,后面 task 优化之后发布,流量恢复正常. 这是一个再正常不 ...
随机推荐
- JFlash ARM对stm32程序的读取和烧录-(转载)
本篇文章主要是记录一下JFlash ARM 的相关使用和操作步骤,读取程序说不上破解,这只是在没有任何加密情况下对Flash的读写罢了!在我们装了JLINK驱动后再根目录下找到JFlash ARM , ...
- 【Java】Files.readAllBytes(Path) 遇见的坑
Files.readAllBytes(Path)方法把整个文件读入内存,此方法返回一个字节数组,还可以把结果传递给String的构造器,以便创建字符串输出. 在针对大文件的读取的时候,可能会出现内存不 ...
- 6.5 scp:远程文件复制
scp命令 用于在不同的主机之间复制文件,它采用SSH协议来保证复制的安全性.scp命令每次都是全量完整复制,因此效率不高,适合第一次复制时使用,增量复制建议使用rsync命令替代. scp ...
- python 如何让俩个对象相等及如何让俩个对象具有相同的id值
- unity项目字符串转为Vector3和Quaternion
运用环境:一般在读取csv表格的数据时是string类型转为Vector3或者Quaternion类型 字符串格式:x,x,x /x,x,x,x (英文逗号) 方法: /// <summary& ...
- Step By Step(Lua弱引用table)
Step By Step(Lua弱引用table) Lua采用了基于垃圾收集的内存管理机制,因此对于程序员来说,在很多时候内存问题都将不再困扰他们.然而任何垃圾收集器都不是万能的,在有些特殊情况下,垃 ...
- js的基本数据类型和typeof的关系
JavaScript数据类型是非常简洁的,它定义了6中基本数据类型 null:空.无.表示不存在,当为对象的属性赋值为null,表示删除该属性 undefined:未定义.当声明变量却没有赋值时会显示 ...
- springboot 非端口模式启动
@SpringBootApplication @ComponentScan(basePackages = {"demo.test"}) public class ReportApp ...
- PaddlePaddle推理部署
PaddlePaddle推理部署 飞桨推理产品简介 作为飞桨生态重要的一部分,飞桨提供了多个推理产品,完整承接深度学习模型应用的最后一公里. 整体上分,推理产品主要包括如下子产品 各产品在推理生态中的 ...
- NNVM Compiler,AI框架的开放式编译器
NNVM Compiler,AI框架的开放式编译器 深度学习已变得无处不在且不可或缺.在多种平台(例如手机,GPU,IoT设备和专用加速器)上部署深度学习工作负载的需求不断增长.宣布了TVM堆栈,以弥 ...