Java技术升华架构开发技巧

基于Redis+Lua实现分布式限流组件

2021-05-28  本文已影响0人  javacoo

limit-spring-boot-starter

limit-spring-boot-starter是一个基于springboot starter机制,结合SPI 接口设计思想(内部集成:Redis+Lua实现限流算法(令牌桶,固定窗口,滑动窗口)以及限流回退默认实现),支持注解方式/配置文件方式接入限流,扩展方便,集成使用简单的分布式限流组件。
开源地址:https://gitee.com/javacoo/limit-spring-boot-starter

背景介绍

业务背景

1、随着业务的快速发展,对接的第三方合作机构越来越多,对外提供服务API访问量成倍增加,导致服务器压力也不断增加,而服务器资源是有限的,当请求量达到设计的极限时,如果不采取措施,轻则导致服务响应时间变长,重则可能造成整个系统瘫痪。

生产环境背景

1、账单日批量业务接口访问量暴增,特别是某个时间段
2、业务方调用接口的速度未知,QPS可能达到400/s,600/s,或者更高
3、对外服务API性能上限是 QPS 300/s
4、已经出现服务不可用,应用崩溃的事故

需求分析

1、鉴于业务方对接口的调用频率未知,而我方的接口服务有上限,为保证服务的可用性,业务层需要对接口调用方的流量进行限制—–接口限流。

2、尽量少改或者不改造已有功能:少侵入或者0侵入式开发。

3、扩展方便,集成简单,开发速率高,使用简单。

设计思路

主流思路
前面的话

在实际应用时也不要太纠结算法问题,因为一些限流算法实现是一样的只是描述不一样;具体使用哪种限流技术还是要根据实际场景来选择,不要一味去找最佳模式,白猫黑猫能解决问题的就是好猫 :)

我的思路

组件基于springboot starter机制,结合SPI 接口设计思想(内部集成:Redis+Lua实现限流算法(令牌桶,固定窗口,滑动窗口)以及限流回退默认实现),支持注解方式/配置文件方式接入限流,主要分为以下部分:

具体实现见 实施步骤 一节,由于实施步骤较多,故放在后面章节,我们先来看看如何集成及使用。

集成及使用

集成
<dependency>
   <groupId>com.javacoo</groupId>
   <artifactId>limit-spring-boot-starter</artifactId>
   <version>1.0.0</version>
</dependency>
使用
#全局配置
#限流表达式:拦截 com.javacoo.service.example.service 包及子包下所有方法
limit.expression=execution(* com.javacoo.service.example.service..*.*(..))
#全局限流回退实现名称
limit.limit-rule.fallback-impl=globalFallback

#方法级配置:针对getExampleInfo方法 配置独立的限流规则
#给定的时间范围 单位(秒)
limit.limit-method-map[getExampleInfo].period = 60
#一定时间内最多访问次数
limit.limit-method-map[getExampleInfo].count = 5
#限流类型
limit.limit-method-map[getExampleInfo].limitType = CUSTOMER
#降级策略
limit.limit-method-map[getExampleInfo].fallbackStrategy = FALLBACK
#当降级策略为:回退 时回退处理接口实现名称
limit.limit-method-map[getExampleInfo].fallbackImpl = getExampleInfoFallback
2021-05-29 15:23:09.497  INFO 8592 --- [           main] c.j.l.c.handler.AnnotationLimitHandler   : [AnnotationLimitHandler限流交易请求],尝试获取方法:com.javacoo.service.example.service.impl.ExampleServiceImpl.getExampleInfo,执行权限
2021-05-29 15:23:09.666  INFO 8592 --- [           main] c.j.l.c.i.redis.RedisLuaRateLimiter      : [限流交易请求],key:[COM.JAVACOO.SERVICE.EXAMPLE.SERVICE.IMPL.EXAMPLESERVICEIMPL.GETEXAMPLEINFO],60秒内,已访问次数:2,60秒内,限制次数:1
2021-05-29 15:23:09.666  INFO 8592 --- [           main] c.j.l.c.handler.AbstractLimitHandler     : [限流交易请求],尝试获取执行权限失败,服务降级处理,降级策略:FALLBACK
2021-05-29 15:23:09.668  INFO 8592 --- [           main] c.j.s.e.fallback.GetExampleInfoFallback  : getExampleInfo方法降级处理
...
 - 修改配置文件,添加如下内容:

   ```properties
   #全局配置
   limit.limit-rule.fallback-impl=globalFallback
   #方法级配置
   limit.limit-method-map[getExampleInfo].fallbackImpl = getExampleInfoFallback
   ```

全局实现

/**
 * 全局方法降级处理接口实现
 * <li></li>
 *
 * @author: duanyong@jccfc.com
 * @since: 2021/5/29 14:35
 */
@Slf4j
public class GlobalFallback implements Fallback<Object> {
    /**
     * 服务降级处理
     * <li></li>
     *
     * @author duanyong@jccfc.com
     * @date 2021/5/29 10:25
     * @return: R 返回对象
     */
    @Override
    public Object getFallback() {
        log.info("全局降级处理");
        return null;
    }
}

指定方法实现

/**
 * getExampleInfo方法降级处理接口实现
 * <li></li>
 *
 * @author: duanyong@jccfc.com
 * @since: 2021/5/29 11:20
 */
@Slf4j
public class GetExampleInfoFallback implements Fallback<Optional<ExampleDto>> {
    /**
     * 服务降级处理
     * <li></li>
     *
     * @author duanyong@jccfc.com
     * @date 2021/5/29 10:25
     * @return: java.lang.Object 返回对象
     */
    @Override
    public Optional<ExampleDto> getFallback() {
        log.info("getExampleInfo方法降级处理");
        ExampleDto exampleDto = new ExampleDto();
        exampleDto.setData("请求过多,请稍后再试");
        return Optional.ofNullable(exampleDto);
    }
}

实施步骤

1,新建limit-spring-boot-starter工程
limit.png RateLimiter.png
2,基于SPI思想设计扩展接口
3,redis+lua实现分布式限流(内部扩展实现)
4,支持接口添加注解方式限流
5,支持配置文件方式限流
6,支持限流回退
7,其他辅助类
8,资源文件

问题及局限性

问题

一些信息

路漫漫其修远兮,吾将上下而求索
码云:https://gitee.com/javacoo
QQ:164863067
作者/微信:javacoo
邮箱:xihuady@126.com
上一篇 下一篇

猜你喜欢

热点阅读