zuul集成Sentinel|zuul集成Sentinel,完成对path映射的限流操作
zuul集成Sentinel完成对path映射的限流
前面我们讲过了对单体应用的Sentinel限流,以及使用zookeeper对规则的持久化。通过前面的工作,我们可以完成单个实例的细粒度的限流、熔断操作。
譬如有一个服务User,在分布式环境下,开启了多个实例,那么每个实例都可以获得如每秒限制10个登录的限流功能。但是有些场景下,我们想要另外一种限流方式,譬如在网关zuul层,想限制对User服务的限流,而不去关心具体它有多少个实例。这时,就需要用到网关限流了。
Sentinel 1.6.0 引入了 Sentinel API Gateway Adapter Common 模块,包含网关限流的规则和自定义 API 的实体和管理逻辑:
GatewayFlowRule
:网关限流规则,针对 API Gateway 的场景定制的限流规则,可以针对不同 route 或自定义的 API 分组进行限流,支持针对请求中的参数、Header、来源 IP 等进行定制化的限流。
ApiDefinition
:用户自定义的 API 定义分组,可以看做是一些 URL 匹配的组合。比如我们可以定义一个 API 叫 my_api,请求 path 模式为 /foo/** 和 /baz/** 的都归到 my_api 这个 API 分组下面。
限流的时候可以针对这个自定义的 API 分组维度进行限流。
注意这个版本,1.6.0以后才有的。
文章图片
我们直接上代码,进入实战。新建一个SpringCloud项目,选中zuul。并在启动类上加上@EnableZuulProxy注解,代表这是一个zuul网关项目。
pom.xml如下:
4.0.0 org.springframework.boot spring-boot-starter-parent2.1.6.RELEASE com.example sentinelzuul0.0.1-SNAPSHOT sentinelzuul Demo project for Spring Boot 1.8 Greenwich.SR11.6.1org.springframework.boot spring-boot-starter-weborg.springframework.cloud spring-cloud-starter-netflix-zuulcom.alibaba.csp sentinel-zuul-adapter${sentinel.version} com.alibaba.csp sentinel-core${sentinel.version} com.alibaba.csp sentinel-parameter-flow-control${sentinel.version} org.springframework.boot spring-boot-starter-testtestorg.springframework.cloud spring-cloud-dependencies${spring-cloud.version} pom importorg.springframework.cloud spring-cloud-alibaba-dependencies0.2.2.RELEASE pom importorg.springframework.boot spring-boot-maven-plugin
官方文档上写,只需要引入sentinel-zuul-adapter依赖,实测后发现,只引入这个的话,所依赖的Sentinel-core是1.5.2版本,会导致启动失败。所以我手工加入了其他几个依赖。
yml文件如下:
server:port: 9999zuul:routes:one:path: /baoban/**url: http://localhost:8888/baoban/spring:application:name: sentinelzuul
这里配了一个简单的routes映射。那是另外一个本地服务。
使用zuul的限流很简单,2个类即可
ZuulConfig.java
import com.alibaba.csp.sentinel.adapter.gateway.zuul.filters.SentinelZuulErrorFilter; import com.alibaba.csp.sentinel.adapter.gateway.zuul.filters.SentinelZuulPostFilter; import com.alibaba.csp.sentinel.adapter.gateway.zuul.filters.SentinelZuulPreFilter; import com.netflix.zuul.ZuulFilter; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * @author wuweifeng wrote on 2019/7/3. */@Configurationpublic class ZuulConfig { @Beanpublic ZuulFilter sentinelZuulPreFilter() {return new SentinelZuulPreFilter(10000); } @Beanpublic ZuulFilter sentinelZuulPostFilter() {return new SentinelZuulPostFilter(1000); } @Beanpublic ZuulFilter sentinelZuulErrorFilter() {return new SentinelZuulErrorFilter(-1); }}
package com.example.sentinelzuul.config; import com.alibaba.csp.sentinel.adapter.gateway.common.SentinelGatewayConstants; import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiDefinition; import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiPathPredicateItem; import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiPredicateItem; import com.alibaba.csp.sentinel.adapter.gateway.common.api.GatewayApiDefinitionManager; import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule; import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayParamFlowItem; import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayRuleManager; import com.alibaba.csp.sentinel.slots.block.RuleConstant; import org.springframework.context.annotation.Configuration; import javax.annotation.PostConstruct; import java.util.HashSet; import java.util.Set; /** * @author wuweifeng wrote on 2019/7/3. */@Configurationpublic class GatewayRuleConfig {private static final int URL_MATCH_STRATEGY_EXACT = 0; private static final int URL_MATCH_STRATEGY_PREFIX = 1; private static final int URL_MATCH_STRATEGY_REGEX = 2; @PostConstructpublic void doInit() {// Prepare some gateway rules and API definitions (only for demo).// It's recommended to leverage dynamic data source or the Sentinel dashboard to push the rules.initCustomizedApis(); initGatewayRules(); } private void initCustomizedApis() {Set definitions = new HashSet<>(); ApiDefinition api1 = new ApiDefinition("baobao_api").setPredicateItems(new HashSet() {{//add(new ApiPathPredicateItem().setPattern("/ahas")); add(new ApiPathPredicateItem().setPattern("/baoban/**").setMatchStrategy(URL_MATCH_STRATEGY_PREFIX)); }}); //ApiDefinition api2 = new ApiDefinition("another_customized_api")//.setPredicateItems(new HashSet() {{//add(new ApiPathPredicateItem().setPattern("/**")//.setMatchStrategy(URL_MATCH_STRATEGY_PREFIX)); //}}); definitions.add(api1); //definitions.add(api2); GatewayApiDefinitionManager.loadApiDefinitions(definitions); } private void initGatewayRules() {Setrules = new HashSet<>(); rules.add(new GatewayFlowRule("baobao_api").setResourceMode(SentinelGatewayConstants.RESOURCE_MODE_CUSTOM_API_NAME).setCount(1).setIntervalSec(1)); rules.add(new GatewayFlowRule("aliyun-product-route").setCount(2).setIntervalSec(2)//应对突发请求时额外允许的请求数目。.setBurst(2).setParamItem(new GatewayParamFlowItem().setParseStrategy(SentinelGatewayConstants.PARAM_PARSE_STRATEGY_CLIENT_IP))); rules.add(new GatewayFlowRule("another-route-httpbin").setCount(10)//统计时间窗口,单位是秒,默认是 1 秒。.setIntervalSec(1)//流量整形的控制效果,同限流规则的 controlBehavior 字段,目前支持快速失败和匀速排队两种模式,默认是快速失败。.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER)//匀速排队模式下的最长排队时间,单位是毫秒,仅在匀速排队模式下生效。.setMaxQueueingTimeoutMs(600)//参数限流配置.setParamItem(new GatewayParamFlowItem().setParseStrategy(SentinelGatewayConstants.PARAM_PARSE_STRATEGY_HEADER).setFieldName("X-Sentinel-Flag"))); rules.add(new GatewayFlowRule("another-route-httpbin").setCount(1).setIntervalSec(1).setParamItem(new GatewayParamFlowItem().setParseStrategy(SentinelGatewayConstants.PARAM_PARSE_STRATEGY_URL_PARAM).setFieldName("pa"))); rules.add(new GatewayFlowRule("some_customized_api").setResourceMode(SentinelGatewayConstants.RESOURCE_MODE_CUSTOM_API_NAME).setCount(5).setIntervalSec(1).setParamItem(new GatewayParamFlowItem().setParseStrategy(SentinelGatewayConstants.PARAM_PARSE_STRATEGY_URL_PARAM).setFieldName("pn"))); GatewayRuleManager.loadRules(rules); //监听zookeeper,使用zookeeper的规则//ReadableDataSource> flowRuleDataSource = new ZookeeperDataSource<>(null, null,//source -> JSON.parseObject(source, new TypeReference>() {//})); //GatewayRuleManager.register2Property(flowRuleDataSource.getProperty()); }}
主要做的有2件事
1是配置一下APIDefinition,也就是给自己的映射规则起个名字。
2是配置Rule,和之前的配置rule差不多。创建一个rule的集合,设置rule规则,具体规则各字段在上面截图中有解释。
![zuul集成Sentinel|zuul集成Sentinel,完成对path映射的限流操作](https://img.it610.com/image/info11/a23b53b749174fae98d79413ff73de95.jpg)
文章图片
这里我配了一个简单的一秒1个QPS的规则。最后用GatewayRuleManager去loadRules即可。
之后测试一下就发现规则已生效。频繁访问被限流的服务时,会报下面的异常。
![zuul集成Sentinel|zuul集成Sentinel,完成对path映射的限流操作](https://img.it610.com/image/info11/cdb979eab3564c0abd9ac7502473c9e1.jpg)
文章图片
如果你想自定义这个熔断的返回值的话,可以加个类实现ZuulBlockFallbackProvider:
import com.alibaba.csp.sentinel.adapter.gateway.zuul.fallback.BlockResponse; import com.alibaba.csp.sentinel.adapter.gateway.zuul.fallback.DefaultBlockFallbackProvider; import com.alibaba.csp.sentinel.adapter.gateway.zuul.fallback.ZuulBlockFallbackProvider; import com.alibaba.csp.sentinel.log.RecordLog; import com.alibaba.csp.sentinel.slots.block.BlockException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @author wuweifeng wrote on 2019/7/3. */public class MyBlockFallbackProvider implements ZuulBlockFallbackProvider { private Logger logger = LoggerFactory.getLogger(DefaultBlockFallbackProvider.class); // you can define route as service level@Overridepublic String getRoute() {return "baobao_api"; } @Overridepublic BlockResponse fallbackResponse(String route, Throwable cause) {RecordLog.info(String.format("[Sentinel DefaultBlockFallbackProvider] Run fallback route: %s", route)); if (cause instanceof BlockException) {return new BlockResponse(429, "the route is blocked", route); } else {return new BlockResponse(500, "System Error", route); }}}
getRoute方法返回的就是上面定义的resouceName。然后注册一下就好了。
![zuul集成Sentinel|zuul集成Sentinel,完成对path映射的限流操作](https://img.it610.com/image/info11/c6bb21dcda5a496297d385d02a3d8726.jpg)
文章图片
![zuul集成Sentinel|zuul集成Sentinel,完成对path映射的限流操作](https://img.it610.com/image/info11/0e85ff51498a46569699d1072c9880ae.jpg)
文章图片
当然这也是基于内存的规则,不能动态改变,在实际生产中,如果需要动态改变规则的话,还是需要去用zookeeper之类的。
【zuul集成Sentinel|zuul集成Sentinel,完成对path映射的限流操作】以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
推荐阅读
- Activiti(一)SpringBoot2集成Activiti6
- 私有化轻量级持续集成部署方案--03-部署web服务(下)
- Spring集成|Spring集成 Mina
- 【SpringCloud-Alibaba系列教程】8.一文学会使用sentinel
- Python机器学习基础与进阶|Python机器学习--集成学习算法--XGBoost算法
- 网络请求,如斯优雅
- 雅集成长第二季|雅集成长第二季 第三周
- doc---Hbuilder中配置集成终端(cmd)
- travis|travis CI 持续集成
- Sentinel源码学习