zuul-ratelimit ---- 快速开始一

因为访问的url是无状态验证的,需要对访问进行限流,由于正在使用zuul 网关转发,准备使用zuul-ratelimit进行限流。

1》配置文件如下:

zuul.ignored-services = *
zuul.routes.test.path = /mirco/**
zuul.routes.test.serviceId = mirco-service-1

zuul.ratelimit.enabled = true    # 使能配置
zuul.ratelimit.repository = REDIS # 使用redis存储计数
zuul.ratelimit.behind-proxy = true # 是否启动代理
zuul.ratelimit.add-response-headers = true  #是否增加响应头
# 通过实例配置覆盖默认配置,注意这里的`test`需要和网关对应路由的`test`关联
zuul.ratelimit.policy-list.test[0].limit = 2
zuul.ratelimit.policy-list.test[0].quota = 1000
zuul.ratelimit.policy-list.test[0].refresh-interval = 5
zuul.ratelimit.policy-list.test[0].type[2] = url
zuul.ratelimit.policy-list.test[0].type[0] = user
zuul.ratelimit.policy-list.test[0].type[1] = origin

2> pom.xml

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
        </dependency>
        <dependency>
            <groupId>com.marcosbarbero.cloud</groupId>
            <artifactId>spring-cloud-zuul-ratelimit</artifactId>
        </dependency>

注意版本使用的是2.3.0RELAESE

限流的配置也挺简单,只需要简单的几行配置就可以起到限流的作用。

经过简单的配置,我们就实现了限流。

接下来我们就看源码中 RateLimitProperties.java

@Validated
@RefreshScope
@ConfigurationProperties("zuul.ratelimit")
public class RateLimitProperties {
    public static final String PREFIX = "zuul.ratelimit";
    @Valid
    @NotNull
    @Policies
    @NestedConfigurationProperty
    private List<RateLimitProperties.Policy> defaultPolicyList = Lists.newArrayList();
    @Valid
    @NotNull
    @Policies
    @NestedConfigurationProperty
    private Map<String, List<RateLimitProperties.Policy>> policyList = Maps.newHashMap();
    private boolean behindProxy;
    private boolean enabled;
    @NotNull
    private ResponseHeadersVerbosity responseHeaders;
    @NotNull
    @Value("${spring.application.name:rate-limit-application}")
    private String keyPrefix;
    @NotNull
    private RateLimitRepository repository;
    private int postFilterOrder;
    private int preFilterOrder;
    //to-do
}

从源码可以看出,我们的配置文件应该如何配置了吧 。

这里定义了@ConfigurationProperties("zuul.ratelimit") 我们取配置的数据的前缀。

 private List<RateLimitProperties.Policy> defaultPolicyList = Lists.newArrayList();
@NestedConfigurationProperty
    private Map<String, List<RateLimitProperties.Policy>> policyList = Maps.newHashMap();

我们可以看到里面有这两行代码,里面有个默认的配置。

那默认的配置具体什么含义呢,我猜测是只要配置了默认了限流规则,则所有的通过zuul转发的都会被限制。

 public List<RateLimitProperties.Policy> getPolicies(String key) {
        return (List)this.policyList.getOrDefault(key, this.defaultPolicyList);
    }

  

从上面的代码可以看出,获取策略时,如果没有指定某一个服务的策略,则会使用默认的策略代替。

提到策略,我看下策略的源代码

public static class Policy {
        @NotNull
        @DurationUnit(ChronoUnit.SECONDS)
        private Duration refreshInterval = Duration.ofSeconds(60L);
        private Long limit;
        @DurationUnit(ChronoUnit.SECONDS)
        private Duration quota;
        private boolean breakOnMatch;
        @Valid
        @NotNull
        @NestedConfigurationProperty
        private List<RateLimitProperties.Policy.MatchType> type = Lists.newArrayList();

    //to-do

我们可以到其中的属性字段正式我们配置的。

这里的quota 的含义是  在 60s 的时间内访问limit次数的最大延迟不超过quota设定的时间。

 public static class MatchType {
            @Valid
            @NotNull
            private RateLimitType type;
            private String matcher;

            public MatchType(@Valid @NotNull RateLimitType type, String matcher) {
                this.type = type;
                this.matcher = matcher;
            }

            public boolean apply(HttpServletRequest request, Route route, RateLimitUtils rateLimitUtils) {
                return StringUtils.isEmpty(this.matcher) || this.type.apply(request, route, rateLimitUtils, this.matcher);
            }

这里定义匹配类型

public enum RateLimitType {
    ORIGIN {
        public boolean apply(HttpServletRequest request, Route route, RateLimitUtils rateLimitUtils, String matcher) {
            if (matcher.contains("/")) {
                SubnetUtils subnetUtils = new SubnetUtils(matcher);
                return subnetUtils.getInfo().isInRange(rateLimitUtils.getRemoteAddress(request));
            } else {
                return matcher.equals(rateLimitUtils.getRemoteAddress(request));
            }
        }

        public String key(HttpServletRequest request, Route route, RateLimitUtils rateLimitUtils, String matcher) {
            return rateLimitUtils.getRemoteAddress(request);
        }
    },
    USER {
        public boolean apply(HttpServletRequest request, Route route, RateLimitUtils rateLimitUtils, String matcher) {
            return matcher.equals(rateLimitUtils.getUser(request));
        }

        public String key(HttpServletRequest request, Route route, RateLimitUtils rateLimitUtils, String matcher) {
            return rateLimitUtils.getUser(request);
        }
    },
    URL {
        public boolean apply(HttpServletRequest request, Route route, RateLimitUtils rateLimitUtils, String matcher) {
            return route == null || route.getPath().startsWith(matcher);
        }

        public String key(HttpServletRequest request, Route route, RateLimitUtils rateLimitUtils, String matcher) {
            return (String)Optional.ofNullable(route).map(Route::getPath).orElse("");
        }
    },
    ROLE {
        public boolean apply(HttpServletRequest request, Route route, RateLimitUtils rateLimitUtils, String matcher) {
            return rateLimitUtils.getUserRoles().contains(matcher.toUpperCase());
        }

        public String key(HttpServletRequest request, Route route, RateLimitUtils rateLimitUtils, String matcher) {
            return matcher;
        }

        public boolean isValid(String matcher) {
            return StringUtils.isNotEmpty(matcher);
        }
    },
    /** @deprecated */
    @Deprecated
    HTTPMETHOD {
        public boolean apply(HttpServletRequest request, Route route, RateLimitUtils rateLimitUtils, String matcher) {
            return HTTP_METHOD.apply(request, route, rateLimitUtils, matcher);
        }

        public String key(HttpServletRequest request, Route route, RateLimitUtils rateLimitUtils, String matcher) {
            return HTTP_METHOD.key(request, route, rateLimitUtils, matcher);
        }
    },
    HTTP_METHOD {
        public boolean apply(HttpServletRequest request, Route route, RateLimitUtils rateLimitUtils, String matcher) {
            return request.getMethod().equalsIgnoreCase(matcher);
        }

        public String key(HttpServletRequest request, Route route, RateLimitUtils rateLimitUtils, String matcher) {
            return StringUtils.isEmpty(matcher) ? request.getMethod() : "http-method";
        }
    },
    URL_PATTERN {
        public boolean apply(HttpServletRequest request, Route route, RateLimitUtils rateLimitUtils, String matcher) {
            return (new AntPathMatcher()).match(matcher.toLowerCase(), request.getRequestURI().toLowerCase());
        }

        public String key(HttpServletRequest request, Route route, RateLimitUtils rateLimitUtils, String matcher) {
            return matcher;
        }

        public boolean isValid(String matcher) {
            return StringUtils.isNotEmpty(matcher);
        }
    };

目前zuul-ratelimit 支持这7种限流类型。

接下来针对这几种限流类型进行源码级一一解析。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值