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如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>sentinelzuul</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>sentinelzuul</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Greenwich.SR1</spring-cloud.version>
        <sentinel.version>1.6.1</sentinel.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
        </dependency>
        <!--<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-zookeeper</artifactId>
        </dependency>-->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-zuul-adapter</artifactId>
            <version>${sentinel.version}</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-core</artifactId>
            <version>${sentinel.version}</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-parameter-flow-control</artifactId>
            <version>${sentinel.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>0.2.2.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

官方文档上写,只需要引入sentinel-zuul-adapter依赖,实测后发现,只引入这个的话,所依赖的Sentinel-core是1.5.2版本,会导致启动失败。所以我手工加入了其他几个依赖。

yml文件如下:

server:
  port: 9999
zuul:
  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.
 */
@Configuration
public class ZuulConfig {

    @Bean
    public ZuulFilter sentinelZuulPreFilter() {
        return new SentinelZuulPreFilter(10000);
    }

    @Bean
    public ZuulFilter sentinelZuulPostFilter() {
        return new SentinelZuulPostFilter(1000);
    }

    @Bean
    public 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.
 */
@Configuration
public 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;

    @PostConstruct
    public 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<ApiDefinition> definitions = new HashSet<>();
        ApiDefinition api1 = new ApiDefinition("baobao_api")
                .setPredicateItems(new HashSet<ApiPredicateItem>() {{
                    //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<ApiPredicateItem>() {{
        //            add(new ApiPathPredicateItem().setPattern("/**")
        //                    .setMatchStrategy(URL_MATCH_STRATEGY_PREFIX));
        //        }});
        definitions.add(api1);
        //definitions.add(api2);
        GatewayApiDefinitionManager.loadApiDefinitions(definitions);
    }

    private void initGatewayRules() {
        Set<GatewayFlowRule> rules = 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<String, Set<GatewayFlowRule>> flowRuleDataSource = new ZookeeperDataSource<>(null, null,
        //        source -> JSON.parseObject(source, new TypeReference<Set<GatewayFlowRule>>() {
        //        }));
        //GatewayRuleManager.register2Property(flowRuleDataSource.getProperty());
    }
}

主要做的有2件事

1是配置一下APIDefinition,也就是给自己的映射规则起个名字。

2是配置Rule,和之前的配置rule差不多。创建一个rule的集合,设置rule规则,具体规则各字段在上面截图中有解释。

这里我配了一个简单的一秒1个QPS的规则。最后用GatewayRuleManager去loadRules即可。

之后测试一下就发现规则已生效。频繁访问被限流的服务时,会报下面的异常。

如果你想自定义这个熔断的返回值的话,可以加个类实现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
    @Override
    public String getRoute() {
        return "baobao_api";
    }

    @Override
    public 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。然后注册一下就好了。

当然这也是基于内存的规则,不能动态改变,在实际生产中,如果需要动态改变规则的话,还是需要去用zookeeper之类的。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • 详解Springboot集成sentinel实现接口限流入门

    Sentinel是阿里巴巴开源的限流器熔断器,并且带有可视化操作界面. 在日常开发中,限流功能时常被使用,用于对某些接口进行限流熔断,譬如限制单位时间内接口访问次数:或者按照某种规则进行限流,如限制ip的单位时间访问次数等. 之前我们已经讲过接口限流的工具类ratelimter可以实现令牌桶的限流,很明显sentinel的功能更为全面和完善.来看一下sentinel的简介: https://github.com/spring-cloud-incubator/spring-cloud-alibab

  • Spring cloud 限流的多种方式

    在频繁的网络请求时,服务有时候也会受到很大的压力,尤其是那种网络攻击,非法的.这样的情形有时候需要作一些限制.例如:限制对方的请求,这种限制可以有几个依据:请求IP.用户唯一标识.请求的接口地址等等. 当前限流的方式也很多:Spring cloud 中在网关本身自带限流的一些功能,基于 redis 来做的.同时,阿里也开源了一款:限流神器 Sentinel.今天我们主要围绕这两块来实战微服务的限流机制. 首先讲 Spring cloud 原生的限流功能,因为限流可以是对每个服务进行限流,也可以对

  • spring cloud gateway 限流的实现与原理

    在高并发的系统中,往往需要在系统中做限流,一方面是为了防止大量的请求使服务器过载,导致服务不可用,另一方面是为了防止网络攻击. 常见的限流方式,比如Hystrix适用线程池隔离,超过线程池的负载,走熔断的逻辑.在一般应用服务器中,比如tomcat容器也是通过限制它的线程数来控制并发的:也有通过时间窗口的平均速度来控制流量.常见的限流纬度有比如通过Ip来限流.通过uri来限流.通过用户访问频次来限流. 一般限流都是在网关这一层做,比如Nginx.Openresty.kong.zuul.Spring

  • 详解Spring Cloud Gateway 限流操作

    开发高并发系统时有三把利器用来保护系统:缓存.降级和限流. API网关作为所有请求的入口,请求量大,我们可以通过对并发访问的请求进行限速来保护系统的可用性. 常用的限流算法比如有令牌桶算法,漏桶算法,计数器算法等. 在Zuul中我们可以自己去实现限流的功能 (Zuul中如何限流在我的书 <Spring Cloud微服务-全栈技术与案例解析>  中有详细讲解) ,Spring Cloud Gateway的出现本身就是用来替代Zuul的. 要想替代那肯定得有强大的功能,除了性能上的优势之外,Spr

  • zuul集成Sentinel,完成对path映射的限流操作

    zuul集成Sentinel完成对path映射的限流 前面我们讲过了对单体应用的Sentinel限流,以及使用zookeeper对规则的持久化.通过前面的工作,我们可以完成单个实例的细粒度的限流.熔断操作. 譬如有一个服务User,在分布式环境下,开启了多个实例,那么每个实例都可以获得如每秒限制10个登录的限流功能.但是有些场景下,我们想要另外一种限流方式,譬如在网关zuul层,想限制对User服务的限流,而不去关心具体它有多少个实例.这时,就需要用到网关限流了. Sentinel 1.6.0

  • SpringBoot基于Sentinel在服务上实现接口限流

    Sentinel是阿里巴巴开源的限流器熔断器,并且带有可视化操作界面. 在日常开发中,限流功能时常被使用,用于对某些接口进行限流熔断,譬如限制单位时间内接口访问次数:或者按照某种规则进行限流,如限制ip的单位时间访问次数等. 之前我们已经讲过接口限流的工具类ratelimter可以实现令牌桶的限流,很明显sentinel的功能更为全面和完善.来看一下sentinel的简介: https://github.com/spring-cloud-incubator/spring-cloud-alibab

  • spring cloud zuul 与 sentinel的结合使用操作

    spring cloud zuul 与 sentinel结合 本来大型服务处理请求超时,限流,降级熔断工作用hystrix,但是这个这个项目不再更新了,虽说它现在提供的版本不会影响到大多数开发者的使用,但是长远考虑,被更换是一件必然的事,而且现在像resilience4j, Sentinel这样的替代品出现,今天我们就看看使用zuul 与 Sentinel整合,实现降级与超时处理,其实网上有很多这样的教程,这里我只是做一个自己的笔记而已 1.必须的依赖 <dependency> <gro

  • Java微服务Filter过滤器集成Sentinel实现网关限流过程详解

    目录 Gateway-过滤器Filter 局部路由过滤器 使用局部过滤器 全局过滤器 使用全局过滤器 集成Sentinel实现网关限流 网关限流 API分组限流 Gateway-过滤器Filter 过滤器就是在请求的传递过程中,对请求和响应做一些手脚. 在Gateway中, Filter的生命周期只有两个:“pre”和“post”". .PRE:这种过滤器在请求被路由之前调用.我们可利用这种过滤器实现身份验证.在集群中选择请求的微服务.记录调试信息等. .POST:这种过滤器在路由到微服务以后执

  • Spring Cloud Alibaba之Sentinel实现熔断限流功能

    微服务中为了防止某个服务出现问题,导致影响整个服务集群无法提供服务的情况,我们在系统访问量和业务量高起来了后非常有必要对服务进行熔断限流处理. 其中熔断即服务发生异常时能够更好的处理:限流是限制每个服务的资源(比如说访问量). spring-cloud中很多使用的是Hystrix组件来进行限流的,现在我们这里使用阿里的sentinel来实现熔断限流功能. sentinel简介 这个在阿里云有企业级的商用版本 应用高可用服务 AHAS:现在有免费的入门级可以先体验下,之后再决定是否使用付费的专业版

  • SpringBoot2.0+阿里巴巴Sentinel动态限流实战(附源码)

    Sentinel 是什么? 随着微服务的流行,服务和服务之间的稳定性变得越来越重要.Sentinel 以流量为切入点,从流量控制.熔断降级.系统负载保护等多个维度保护服务的稳定性. Sentinel 具有以下特征: 丰富的应用场景:Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围).消息削峰填谷.集群流量控制.实时熔断下游不可用应用等. 完备的实时监控:Sentinel 同时提供实时的监控功能.您可以在控制台中看到接入应用的

  • Sentinel实现动态配置的集群流控的方法

    介绍 为什么要使用集群流控呢? 相对于单机流控而言,我们给每台机器设置单机限流阈值,在理想情况下整个集群的限流阈值为机器数量✖️单机阈值.不过实际情况下流量到每台机器可能会不均匀,会导致总量没有到的情况下某些机器就开始限流.因此仅靠单机维度去限制的话会无法精确地限制总体流量.而集群流控可以精确地控制整个集群的调用总量,结合单机限流兜底,可以更好地发挥流量控制的效果. 基于单机流量不均的问题以及如何设置集群整体的QPS的问题,我们需要创建一种集群限流的模式,这时候我们很自然地就想到,可以找一个 s

  • SpringCloud中使用Sentinel实现限流的实战

    目录 前言 正文 Sentinel Sentinel的限流原理 第一步:部署sentinel-dashboard 第二步:在项目中整合sentinel 前言 在分布式的项目中经常会遇到那种高并发的场景,为了保证系统不会被突然激增的请求导致宕机,我们常常会使用一种服务降级的手段来保护我们的系统,本篇博客将介绍如何使用SpringCloud中使用Sentinel实现限流,从而达到服务降级的目的. 正文 Sentinel Sentinel 是面向微服务的轻量级流量控制框架,从流量控制.熔断降级.系统负

  • Spring Cloud Alibaba微服务组件Sentinel实现熔断限流

    目录 Sentinel简介 Sentinel具有如下特性: 安装Sentinel控制台 创建sentinel-service模块 限流功能 创建RateLimitController类 根据URL限流 自定义限流处理逻辑 熔断功能 与Feign结合使用 使用Nacos存储规则 原理示意图 功能演示 Sentinel简介 Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案,Sentinel 作为其核心组件之一,具有熔断与限流等一系列服务保护功能,本文将对其用法进行详细介

随机推荐