Dubbo学习系列之十(Sentinel之限流与降级)
作者原创文章,谢绝任何形式转载,否则追究法律责任!
各位看官,先提个问题,如果让你设计一套秒杀系统,核心要点是啥???我认为有三点:缓存、限流和分离。想当年12306大面积崩溃,还有如今的微博整体宕机情况,
感觉就是限流降级没做好,"用有限的资源响应过量请求"
——这就是限流降级的核心。限流降级组件,当今开源界应该是Hystrix最为出名,这也得益于SpringCloud的流
行,当然,挑战者总是有的,于是Sentinel横空出世,正因实际生产使用中似乎并不多见,所以才有必要拿来一用,不然就脱离了此系列文章的主旨了,就是要见些不一样的风景!
工具:Idea201902/JDK11/ZK3.5.5/Gradle5.4.1/RabbitMQ3.7.13/Mysql8.0.11/Lombok0.26/Erlang21.2/postman7.5.0/Redis3.2/RocketMQ4.5.2/Sentinel1.6.3/SpringBoot2.1.6
难度: 新手--战士--老兵--大师
目标:
使用Sentinel实现交易业务特定方法的限流
AOP注解模式实现交易业务方法限流降级
使用Sentinel实现授权模式控制
步骤:
1.整体框架依旧,多模块微服务框架商城系统,一个共享模块,多个功能模块。
2.先说几个Sentinel基本概念:
资源Resource,可以是任意对象,一个字符串、一个方法,一个类对象;
规则Rule,需要如何限制或者降级,比如按照“QPS/失败比率”做出相应的处理;
入口Entry,每次资源调用都会创建一个Entry对象,Entry 创建的时候,同时也会创建一系列功能插槽(slot chain),链里面的slot各司其职,比如其中的FlowSlot 则用于根据预设的限流规则以及前面 slot 统计的状态,来进行流量控制,DegradeSlot 则通过统计信息以及预设的规则,来做熔断降级;AuthoritySlot 则根据配置的黑白名单和调用来源信息,来做黑白名单控制;
3.引入的依赖项目:
// 引入此依赖后,Dubbo 的服务接口和方法(包括调用端和服务端)就会成为 Sentinel 中的资源
compile group: 'com.alibaba.csp', name: 'sentinel-dubbo-adapter', version: '1.6.3'
// Sentinel 控制台依赖,
compile group: 'com.alibaba.csp', name: 'sentinel-transport-simple-http', version: '1.6.3'
//
compile group: 'com.alibaba.csp', name: 'sentinel-core', version: '1.6.3'
// 可以使用URL:查询规则:http://localhost:8083/actuator/sentinel
compile group: 'org.springframework.boot', name: 'spring-boot-starter-actuator', version: '2.1.6.RELEASE'
// https://mvnrepository.com/artifact/com.alibaba.csp/sentinel-annotation-aspectj
compile group: 'com.alibaba.csp', name: 'sentinel-annotation-aspectj', version: '1.6.3'
// https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-alibaba-sentinel
compile group: 'org.springframework.cloud', name: 'spring-cloud-starter-alibaba-sentinel', version: '0.9.0.RELEASE'
4.Sentinel的使用方式都是:定义资源——定义规则——适配规则
,先看个最基本的样例:com.biao.mall.business.controller.SentinelTestController
中,方式很完整,定义一个字符串为资源,initFlowQpsRule
定义规则,QPS限制为2(即<2),testSentinel方法中使用规则。
@RestController
public class SentinelTestController { private String resourceName = "testSentinel"; @GetMapping("/testSentinel")
public String testSentinel(){
initFlowQpsRule();
Entry entry = null;
String retVal;
try{
entry = SphU.entry(resourceName,EntryType.IN);
retVal = "passed";
}catch(BlockException e){
retVal="block";
}finally{
if (entry != null){
entry.exit();
}
}
return retVal;
}
private void initFlowQpsRule() {
List<FlowRule> rules = new ArrayList<>();
FlowRule rule1 = new FlowRule();
rule1.setResource(resourceName);
// set limit qps to 2
rule1.setCount(2);
rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule1.setLimitApp("default");
rules.add(rule1);
FlowRuleManager.loadRules(rules);
}
}
5.测试运行一下,先启动各组件(zk-->redis-->Rabbit-->Rocket):快速刷新几次,就显示限流特征了!
6.再看第2个目标实现,注解模式,这里我先只改动business模块:com.biao.mall.business.controller.DubboOrderController
中,实现目标对saveOrder方法进行限流,对比之前版本,变化不大,只是先initFlowQpsRule初始化规则,然后再初始化一个Entry ,这里使用了try-with-resource语法糖,当然也可使用try-catch-finally语法,参数EntryType.IN
表示监视“进入流量”,这里的"saveOrder"是资源的名称,具体定义请见第7点,
@RequestMapping(value = "/order",method = RequestMethod.POST)
public ResEntity<String> saveOrder(@RequestBody OrderBO orderBO ) throws Exception {
logger.debug(orderBO.toString());
initFlowQpsRule("saveOrder");
try(Entry entry = SphU.entry("saveOrder",EntryType.IN)) {
//存未付款订单
orderService.saveOrder(orderBO);
//响应封装
ResEntity<String> resEntity = new ResEntity<>();
resEntity.setCode(ResConstant.SUCCESS_CODE);
resEntity.setMsg(ResConstant.SUCCESS_STRING);
resEntity.setData("order saved");
return resEntity;
}
}
进一步,看初始化规则initFlowQpsRule方法:生成一个规则链,每个资源可以对应多个规则,sentinel将遍历匹配每个规则,具体作用见代码中的注释:
private void initFlowQpsRule(String resourceName) {
List<FlowRule> rules = new ArrayList<>();
FlowRule rule1 = new FlowRule();
//定义资源,resourceName只能是String类型
rule1.setResource(resourceName);
// set limit QPS
rule1.setCount(2);
//流控制的门槛类型
rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
//设置应用的名称,
rule1.setLimitApp("default");
rules.add(rule1);
FlowRuleManager.loadRules(rules);
}
这里为了测试效果,我将QPS设置较小,其参数为double类型,应设置为>1,否则测试时会直接流量拒绝,因为其按每秒计数。setGrade是设置流量控制的门槛类型0: thread count, 1: QPS,即常量值为0按照并发线程数标准,为1按照QPS标准;
7.再看com.biao.mall.business.impl.DubboOrderServiceImpl
,其中的saveOrder方法,这里使用了AOP模式,使用了引入的sentinel-annotation-aspectj依赖,其实就是sentinel对AspectJ做了封装处理,这样注解后,saveOrder方法即成了一个resource,就对应上了DubboOrderController中"saveOrder"资源的名称,同时还指定了blockHandler,即对应处理 BlockException 的函数名称。fallback,用于在抛出异常的时候提供 fallback 处理逻辑。
@Override
@Transactional
@SentinelResource(value = "saveOrder", blockHandler = "saveOrderExHandler", fallback = "saveOrderFallback")
public boolean saveOrder(OrderBO orderBO) throws Exception {...}
这里注意两点:
若希望使用其他类的函数,则可以在SentinelResource注解参数中指定 blockHandlerClass 为对应的类的 Class 对象,注意对应的函数必须为 static 函数,否则无法解析,实例见payOrder方法上的注解模式
@Override
@Transactional
@SentinelResource(value = "payOrder", blockHandler = "PayOrderExHandler",blockHandlerClass = {ExceptionUtil.class})
public boolean payOrder(String orderId) throws MQClientException, UnsupportedEncodingException {...}
若 blockHandler 和 fallback 都进行了配置,则被限流降级而抛出 BlockException 时只会进入 blockHandler 处理逻辑。若未配置 blockHandler、fallback 和 defaultFallback,则被限流降级时会将 BlockException 直接抛出
8.再看下定义的blockHandler 和 fallback 方法,比较简单,真实业务系统肯定会做些其他处理,比如显示静态内容,提示些用户友好型信息等。
// Fallback 函数,函数签名与原函数一致或加一个 Throwable 类型的参数.
public String saveOrderFallback(long s) {
logger.info("saveOrderFallback");
return String.format("saveOrderFallback %d", s);
}
// BlockHandle 异常处理函数,参数最后多一个 BlockException,其余与原函数一致.
public String saveOrderExHandler(long s, BlockException ex) {
logger.error("saveOrderExHandler");
ex.printStackTrace();
return "Oops, error occurred at saveOrder" + s;
}
9.测试:启动ZK-->Redis-->RabbitMQ-->RocketMQ-->各模块-->postman, 快速点击send按钮3次,就发现报错500:
同时sentinelDashboard(下篇文章)的监控图:
10.实现授权模式,先修改下business模中RPC调用的stockService.updateStockRPC(stockEntity)
方法,其中的ContextUtil.enter(resourceName,"mall-business")模拟了请求应用名为“mall-business”:
@Override
@Transactional
public int updateStockRPC(DubboStockEntity stockEntity) throws BlockException {
String resourceName = "updateStockRPC";
this.initWhiteRules(resourceName);
//获取app来源
ContextUtil.enter(resourceName,"mall-business");
try(Entry entry = SphU.entry(resourceName)){
if (Objects.equals(null, stockEntity)) {
return -1;
}
return dubboStockDao.updateById(stockEntity);
}
}
再看initWhiteRules方法:即只允许应用名为 appA/appE 的应用请求通过,
/**白名单规则*/
private void initWhiteRules(String resourceName){
AuthorityRule rule = new AuthorityRule();
rule.setResource(resourceName);
rule.setStrategy(RuleConstant.AUTHORITY_WHITE);
rule.setLimitApp("appA,appE");
AuthorityRuleManager.loadRules(Collections.singletonList(rule));
}
测试效果如下:
同时sentinelDashboard也可以看到拒绝的请求:
11.经测试,授权模式(黑白名单)模式的资源定义适合于service调用,如果放在controller中,将不起作用,具体可看com.biao.mall.logistic.controller.DubboDeliveryController
中的代码,测试运行时无任何作用,这是因为REST调用使用http请求,sentinel规则将被忽略。
12.代码地址:其中的day13
https://github.com/xiexiaobiao/dubbo-project.git
后记:
1.运行sentinel官方源码时,JDK11下提示sun.misc does not exist,但是类文件又可以在jdk文件夹下找到,这是因为sun.misc.Unsafe自JDK9起已经不再是标准API,被移除,编译时会提示出错,解决方法:要么重构代码,或者下载1.8的rt.jar包,再作为依赖导入。我直接下载导入解决问题。
2.java.util.stream.longstream 或者类似java.util.XXX not found 通过设置java language level解决。
3.Sentinel的核心规则类:
AuthorityRule:黑白名单根据资源的请求来源(origin)限制资源是否通过,若配置白名单则只有请求来源位于白名单内时才可通过;若配置黑名单则请求来源位于黑名单时不通过,其余的请求通过。
FlowRule:监控应用流量的 QPS 或并发线程数等指标,当达到指定的阈值时对流量进行控制,以避免被瞬时的流量高峰冲垮。
DegradeRule:在调用链路中某个资源出现不稳定状态时(例如调用超时或异常比例升高),对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联错误
SystemRule:单台机器的总体 Load、RT(ResponseTime)、入口 QPS 和线程数四个维度监控应用数据,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。
相关核心方法我整理如下图:
4.下载源码 打包 dashboard生成jar,提示缺少各类依赖,可先install:sentinel-parent,生成各个依赖的jar。
5.Sentinel与Hystrix的对比,借用一张图:大致来讲,sentinel轻量级、组件独立、适配好、规则丰富。
6.如果使用springBoot开发,必须添加依赖spring-cloud-starter-alibaba-sentinel,否则无法连接sentinelDashboard。
7.如想使用URL输出Rules: http://localhost:8083/actuator/sentinel,需添加actuator依赖。
8.注意启动参数比如 -Dserver.port=8718 放 java <-D参数位置> -jar sentinel-dashboard.jar 中间,不要放后面,会丢失参数 。
作者原创文章,谢绝任何形式转载,否则追究法律责任!
推荐阅读:
个人微信公众号,只发原创文章!
Dubbo学习系列之十(Sentinel之限流与降级)的更多相关文章
- Dubbo学习系列之十二(Quartz任务调度)
Quartz词义为"石英"水晶,然后聪明的人类利用它发明了石英手表,因石英晶体在受到电流影响时,它会产生规律的振动,于是,这种时间上的规律,也被应用到了软件界,来命名了一款任务调度 ...
- Dubbo学习系列之十五(Seata分布式事务方案TCC模式)
上篇的续集. 工具: Idea201902/JDK11/Gradle5.6.2/Mysql8.0.11/Lombok0.27/Postman7.5.0/SpringBoot2.1.9/Nacos1.1 ...
- Dubbo学习系列之十六(ELK海量日志分析框架)
外卖公司如何匹配骑手和订单?淘宝如何进行商品推荐?或者读者兴趣匹配?还有海量数据存储搜索.实时日志分析.应用程序监控等场景,Elasticsearch或许可以提供一些思路,作为业界最具影响力的海量搜索 ...
- Dubbo学习系列之十八(Skywalking服务跟踪)
我们知道,微服务不是独立的存在,否则就不需要微服务这个架构了,那么当发起一次请求,如何知道这次请求的轨迹,或者说遇到响应缓慢. 请求出错的情况,我们该如何定位呢?这就涉及到APM(Applicatio ...
- Dubbo学习系列之十四(Seata分布式事务方案AT模式)
一直说写有关最新技术的文章,但前面似乎都有点偏了,只能说算主流技术,今天这个主题,我觉得应该名副其实.分布式微服务的深水区并不是单个微服务的设计,而是服务间的数据一致性问题!解决了这个问题,才算是把分 ...
- Dubbo学习系列之十三(Mycat数据库代理)
软件界有只猫,不用我说,各位看官肯定知道是哪只,那就是大名鼎鼎的Tomcat,现在又来了一只猫,据说是位东方萌妹子,暂且认作Tom猫的表妹,本来叫OpencloudDB,后又改名为Mycat,或许Ca ...
- Dubbo学习系列之十一(Dashboard+Nacos规则推送)
中国武术,门派林立,都是号称多少代的XXX传人,结果在面对现代武术时,经常被KO秒杀,为啥,光靠宣传和口号撑门面,终究是靠不住,必须得有真货 ,得经得住考验,所以不能只说Sentinel有多好,也得给 ...
- Dubbo学习系列之八(分布式事务之MQ方案)
自从小王玩起了微服务,发现微服务果然很强大,好处真是太多,心中暗喜,然而,却也遇到了分布式中最棘手的问题:分布式事务.小王遍访各路神仙,也无个完美开源解决方案,当然,也有些实际可行的手法,虽不算完美, ...
- Dubbo学习系列之九(Shiro+JWT权限管理)
村长让小王给村里各系统来一套SSO方案做整合,隔壁的陈家村流行使用Session+认证中心方法,但小王想尝试点新鲜的,于是想到了JWT方案,那JWT是啥呢?JavaWebToken简称JWT,就是一个 ...
随机推荐
- 关于jsp中jstl报错Can not find the tag library descriptor for "http://java.sun.com/jsp/jstl/core
有的时候在开发jsp时,需要使用jstl时,在jsp上面引用jstl却出现错误:Can not find the tag library descriptor for "http://jav ...
- React - 组件:类组件
目录: 1. 类组件有自己的状态 2. 继承React.Component-会有生命周期和this 3. 内部需要一个render函数(类组件会默认调用render方法,但不会默认添加,需要手动填写r ...
- Java学习笔记(面向对象上)
面向对象(上) 面向对象的特点:封装性(是面向对象的核心思想,将对象的属性和行为封装起来).继承性(主要描述类与类之间的关系,通过继承,可以在无需重新编写原有类的情况下,对原有类的功能进行扩展)和多态 ...
- Android 自定义饼状图
github 地址:https://github.com/dkest/PieView 简单分析 其实根据我们上面的知识已经能自己制作一个饼状图了.不过制作东西最重要的不是制作结果,而是制作思路. 相信 ...
- 编码规范(c#)
万丈高楼平地起,好的编码风格能让别人撸起来更带劲,反之则想吐槽这是哪个傻X写的,这都是些什么乱七八糟的玩意? 然后看后面的注释发现是自己以前写的,那场面一度很尴尬.... 规约不是规则,不是一定要这样 ...
- autoLayout+sizeClass屏幕适配
一.屏幕适配(autoLayout+sizeClass) 1.目前市面上的主流布局形式: a. frame 布局,通过代码计算(老程序员习惯使用) b. autoLayout(新的出现)与sizeCl ...
- 在Linux中配置jdk,Tomcat,MySQL
解压缩: tar 命令 : 使用方式 tar [参数] source [target] source - 压缩文件 target - 解压缩后的目标位置, 默认解压到当前目录 常用写法 : 解压缩 : ...
- Dubbo学习系列之七(分布式订单ID方案)
既然选择,就注定风雨兼程! 开始吧! 准备:Idea201902/JDK11/ZK3.5.5/Gradle5.4.1/RabbitMQ3.7.13/Mysql8.0.11/Lombok0.26/Erl ...
- [Java并发] AQS抽象队列同步器源码解析--独占锁释放过程
[Java并发] AQS抽象队列同步器源码解析--独占锁获取过程 上一篇已经讲解了AQS独占锁的获取过程,接下来就是对AQS独占锁的释放过程进行详细的分析说明,废话不多说,直接进入正文... 锁释放入 ...
- 【原创】005 | 搭上SpringBoot请求处理源码分析专车
前言 如果这是你第二次看到师长,说明你在觊觎我的美色! 点赞+关注再看,养成习惯 没别的意思,就是需要你的窥屏^_^ 专车介绍 该趟专车是开往Spring Boot请求处理源码分析专车,主要用来分析S ...