searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

SpringBoot中实现限流模式灵活切换

2023-07-25 07:52:57
49
0

概述    

限流是对某一时间窗口内的请求数进行限制,保持系统的可用性和稳定性,防止因流量暴增而导致的系统运行缓慢或宕机。在突发情况下,平台/系统面对大并发大流量请求时,瞬时大流量会直接将系统打垮,无法对外提供服务。限流是针对这种场景最常见的解决方案之一,当平台/系统的请求达到一定并发数或速率,便进行等待、排队、降级、拒绝服务等。目前实现限流有两种常用模式:基于Guava实现单机令牌桶限流、基于Redis实现分布式限流。这里主要介绍下如何将这两种限流模式整合到一起,提供能力给用户按需灵活切换。

整合思路

抽象一个通用的限流器模块,在业务模块中引入,支持通过配置文件切换不同的限流模式,定义limit.mod = local ,表示启用本地Guava限流模式,定义limit.mod = remote,表示启用远程分布式限流模式。

整合步骤

1、创建通用模块common-limiter
在父项目下创建通用模块common-limiter服务,并在pom中引入如下相关依赖

<dependencies>
  <dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
  </dependency>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
    <scope>provided</scope>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <scope>provided</scope>
  </dependency>
</dependencies>

2、限流接口实现

2.1、创建限流接口

public interface LimiterMgr {
    boolean tryExcute(Limiter limiter);
}

2.2、GLimiter:Guava限流的关键实现

@Slf4j
public class GLimiter implements LimiterMgr{
    private final Map<String, RateLimiter> limiterMap = Maps.newConcurrentMap();
 
    @Override
    public boolean tryExcute(Limiter limiter) {
        RateLimiter rateLimiter = getRateLimiter(limiter);
        if (null == rateLimiter) {
            return false;
        }
        boolean access = rateLimiter.tryAcquire(1,100, TimeUnit.MILLISECONDS);
        return access;
    }
}

2.3、RLimiter:Redis限流的关键实现

@Slf4j
public class RLimiter implements LimiterMgr{
    private final StringRedisTemplate strRedisTpl;
 
    public RLimiter(StringRedisTemplate strRedisTpl) {
        this.strRedisTpl = strRedisTpl;
    }
 
    @Override
    public boolean tryExcute(Limiter limiter) {
        String key = limiter.getKey();
        if (StringUtils.isEmpty(key)) {
            throw new LimiterException( "key cannot be null" );
        }
        List<String> keys = new ArrayList<>();
        keys.add( key );
        // ......
        return true;
    }
}

3、创建配置类
编写对应配置类,根据配置文件注入限流实现类,当配置文件中属性 limit.mod = local 时启用Guava限流,当limit.mod = remote 时启用Redis限流

@Configuration
public class LimiterConfigure {
    @Bean
    @ConditionalOnProperty(name = "limit.mod",havingValue = "local")
    public LimiterMgr gLimiter(){
        return new GLimiter();
    }
    @Bean
    @ConditionalOnProperty(name = "limit.mod",havingValue = "remote")
    public LimiterMgr rLimiter(StringRedisTemplate strRedisTpl){
        return new RLimiter(strRedisTpl);
    }
}

4、创建AOP并引导加载配置类
避免限流处理侵入业务功能代码,通过借助Spring AOP,定义一个拦截器,注解@Aspect,同时创建spring.factories文件,引导SpringBoot加载配置类

5、在业务模块/项目中引入通用限流器模块
5.1、引入pom依赖

<dependency>
    <groupId>com.busi</groupId>
    <artifactId>common-limiter</artifactId>
</dependency>

5.2、在配置文件application.properties中设置使用的限流模式:limit.mod = remote

5.3、在需要限流的业务接口上增加注解

@Limit(key = "Limiter:app",limitNum = 5,seconds = 0.5)

小结
通过上述整合步骤,我们已成功实现了将一个通用的限流器模块集成到其他业务模块中,在实际场景里,用户只需要根据场景需求,通过配置切换对应的限流模式,兼具灵活性及可维护性。

0条评论
作者已关闭评论
李****h
2文章数
0粉丝数
李****h
2 文章 | 0 粉丝
李****h
2文章数
0粉丝数
李****h
2 文章 | 0 粉丝
原创

SpringBoot中实现限流模式灵活切换

2023-07-25 07:52:57
49
0

概述    

限流是对某一时间窗口内的请求数进行限制,保持系统的可用性和稳定性,防止因流量暴增而导致的系统运行缓慢或宕机。在突发情况下,平台/系统面对大并发大流量请求时,瞬时大流量会直接将系统打垮,无法对外提供服务。限流是针对这种场景最常见的解决方案之一,当平台/系统的请求达到一定并发数或速率,便进行等待、排队、降级、拒绝服务等。目前实现限流有两种常用模式:基于Guava实现单机令牌桶限流、基于Redis实现分布式限流。这里主要介绍下如何将这两种限流模式整合到一起,提供能力给用户按需灵活切换。

整合思路

抽象一个通用的限流器模块,在业务模块中引入,支持通过配置文件切换不同的限流模式,定义limit.mod = local ,表示启用本地Guava限流模式,定义limit.mod = remote,表示启用远程分布式限流模式。

整合步骤

1、创建通用模块common-limiter
在父项目下创建通用模块common-limiter服务,并在pom中引入如下相关依赖

<dependencies>
  <dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
  </dependency>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
    <scope>provided</scope>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <scope>provided</scope>
  </dependency>
</dependencies>

2、限流接口实现

2.1、创建限流接口

public interface LimiterMgr {
    boolean tryExcute(Limiter limiter);
}

2.2、GLimiter:Guava限流的关键实现

@Slf4j
public class GLimiter implements LimiterMgr{
    private final Map<String, RateLimiter> limiterMap = Maps.newConcurrentMap();
 
    @Override
    public boolean tryExcute(Limiter limiter) {
        RateLimiter rateLimiter = getRateLimiter(limiter);
        if (null == rateLimiter) {
            return false;
        }
        boolean access = rateLimiter.tryAcquire(1,100, TimeUnit.MILLISECONDS);
        return access;
    }
}

2.3、RLimiter:Redis限流的关键实现

@Slf4j
public class RLimiter implements LimiterMgr{
    private final StringRedisTemplate strRedisTpl;
 
    public RLimiter(StringRedisTemplate strRedisTpl) {
        this.strRedisTpl = strRedisTpl;
    }
 
    @Override
    public boolean tryExcute(Limiter limiter) {
        String key = limiter.getKey();
        if (StringUtils.isEmpty(key)) {
            throw new LimiterException( "key cannot be null" );
        }
        List<String> keys = new ArrayList<>();
        keys.add( key );
        // ......
        return true;
    }
}

3、创建配置类
编写对应配置类,根据配置文件注入限流实现类,当配置文件中属性 limit.mod = local 时启用Guava限流,当limit.mod = remote 时启用Redis限流

@Configuration
public class LimiterConfigure {
    @Bean
    @ConditionalOnProperty(name = "limit.mod",havingValue = "local")
    public LimiterMgr gLimiter(){
        return new GLimiter();
    }
    @Bean
    @ConditionalOnProperty(name = "limit.mod",havingValue = "remote")
    public LimiterMgr rLimiter(StringRedisTemplate strRedisTpl){
        return new RLimiter(strRedisTpl);
    }
}

4、创建AOP并引导加载配置类
避免限流处理侵入业务功能代码,通过借助Spring AOP,定义一个拦截器,注解@Aspect,同时创建spring.factories文件,引导SpringBoot加载配置类

5、在业务模块/项目中引入通用限流器模块
5.1、引入pom依赖

<dependency>
    <groupId>com.busi</groupId>
    <artifactId>common-limiter</artifactId>
</dependency>

5.2、在配置文件application.properties中设置使用的限流模式:limit.mod = remote

5.3、在需要限流的业务接口上增加注解

@Limit(key = "Limiter:app",limitNum = 5,seconds = 0.5)

小结
通过上述整合步骤,我们已成功实现了将一个通用的限流器模块集成到其他业务模块中,在实际场景里,用户只需要根据场景需求,通过配置切换对应的限流模式,兼具灵活性及可维护性。

文章来自个人专栏
develop
2 文章 | 1 订阅
0条评论
作者已关闭评论
作者已关闭评论
0
0