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 优化之后发布,流量恢复正常. 这是一个再正常不 ...
随机推荐
- jmeter while控制器踩坑
在使用jmeter测试一个复杂流程,需要用到while控制器,对于里面的contition,使用jexl3方式,怎么看都没有问题,可是死活跳不出流程,各种莫名其妙的报错,甚至用单个写死的变量(已设置为 ...
- Linux进阶之TCP三次握手四次挥手
TCP(Transfer control protocol)传输控制协议 一.两种传输模式: TCP面向有连接 可靠 常用于点对点 微信 UDP面向无连接 高速 常用于点对面 直播 二.数据方向: 在 ...
- HTML html5 语义化标签
什么是语义化标签 语义化标签就是具有某种含义及结构的标签,让其更容易理解和使用. HTML5 新增了一些语义化标签,如下: article article 标签装载显示一个独立的文章内容.例如一篇完整 ...
- CSS(2)盒子模型、定位浮动
盒子模型 盒子模型:一个盒子中主要的属性就5个.width与height.padding.border.margin.盒子模型标准有两种为标准盒模型和IE盒模型.学习上以标准盒子模型为主 width和 ...
- spring模板
applicationContext <?xml version="1.0" encoding="UTF-8"?> <beans xmlns= ...
- 如何让Android 支持HEIF 图片解码和加载(免费的方法)
字节跳动火山引擎ImageX提供了一种能力,可以支持客户端android 直接解码HEIF 和HEIC图片,经过测试发现,可以免费使用: 一.阅前准备 HEIF图片格式是什么? 高效率图像格式(Hig ...
- MSQL 数据完整性(约束)
0. 前言 1. 实体完整性 1.1 主键约束(primary key) 1.2 唯一约束(unique) 1.3 自动增长列(auto_increment) 2. 域完整性 数据类型 非空约束 默认 ...
- Proteus仿真MSP430单片机的若干问题记录
1.支持的具体型号: P7.8: Proteus8.9: Proteus8.9能够支持的类型明显要多于Proteus7.8.但是对于仿真而言,目前个人还是觉得Proteus7.8更稳定.这也是目前能用 ...
- 电阻存储器为edge-AI提供了仿生架构
电阻存储器为edge-AI提供了仿生架构 Resistive memories enable bio-inspired architectures for edge AI 近年来,脑启发计算领域的研究 ...
- mysql-8.0.16-winx64.zip安装教程详解
摘自:https://zhuanlan.zhihu.com/p/48531203 mysql-8.0.16-winx64.zip安装教程详解下载地址:https://dev.mysql.com/get ...