自定义限流参数

因为gateway官方提供的是两个参数配置死在yml中,所以我们想要根据不同的用户来限制,只能自己重写限流实现。

本篇文章介绍自定义限流维度:

1、数据库表设计
CREATE TABLE `sys_rate_limiter` (
  `limit_id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID',
  `level` varchar(255) NOT NULL COMMENT '等级',
  `replenish_rate` int(11) NOT NULL COMMENT '流速',
  `burst_capacity` int(11) NOT NULL COMMENT '桶容量',
  `limit_type` int(10) NOT NULL COMMENT '单位 1:秒,2:分钟,3:小时,4:天',
  PRIMARY KEY (`limit_id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;

对于该表curd不再重述

具体代码在 ms-common > ms-common-gateway

2、定义接口标准
public interface LimiterLevelResolver {

    default void save(RateLimiterLevel limiterLevel){}

    default RateLimiterLevel get(){
        return null;
    }
}

一个获取,一个保存方法,具体实现

public class RedisLimiterLevelHandler implements LimiterLevelResolver {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RedisTokenStoreSerializationStrategy redisTokenStoreSerializationStrategy;

    @Override
    public void save(RateLimiterLevel limiterLevel) {
        byte[] key = redisTokenStoreSerializationStrategy.serialize(CommonConstants.REDIS_LIMIT_KEY);
        byte[] value = redisTokenStoreSerializationStrategy.serialize(limiterLevel);
        try{
            redisTemplate.getConnectionFactory().getConnection().openPipeline();
            redisTemplate.getConnectionFactory().getConnection().set(key, value);
            redisTemplate.getConnectionFactory().getConnection().closePipeline();
        }finally {
            redisTemplate.getConnectionFactory().getConnection().close();
        }
    }

    @Override
    public RateLimiterLevel get() {
        byte[] key = redisTokenStoreSerializationStrategy.serialize(CommonConstants.REDIS_LIMIT_KEY);
        byte[] value = redisTemplate.getConnectionFactory().getConnection().get(key);
       RateLimiterLevel rateLimiterLevel = redisTokenStoreSerializationStrategy.deserialize(value,RateLimiterLevel.class);
        if(ObjectUtil.isNull(value) ||  ObjectUtil.isNull(rateLimiterLevel) || CollUtil.isEmpty(rateLimiterLevel.getLevels())){
            rateLimiterLevel = new RateLimiterLevel();
            List<RateLimiterVO> vos = new ArrayList<>();
            vos.add(RateLimiterVO
                    .builder()
                    .level(CommonConstants.DEFAULT_LEVEL)
                    .burstCapacity(CommonConstants.DEFAULT_LIMIT_LEVEL)
                    .replenishRate(CommonConstants.DEFAULT_LIMIT_LEVEL)
                    .limitType(CommonConstants.DEFAULT_LIMIT_TYPE)
                    .build());
            rateLimiterLevel.setLevels(vos);
        }
        return rateLimiterLevel;
    }
}
3、加载数据库配置的限流参数

在服务启动的时候自动把数据库的中的限流参数,通过调用 LimiterLevelResolver 接口中的save方法保存到redis中

具体实现 在 ms-admin 服务中

@Slf4j
@Configuration
@AllArgsConstructor
public class LimiterInitConfig {

    private final SysRateLimitService sysRateLimitService;
    private final LimiterLevelResolver limiterLevelResolver;

    @Async
    @Order
    @EventListener({WebServerInitializedEvent.class})
    public void initLimit(){
        List<SysRateLimiter> list = sysRateLimitService.list();
        RateLimiterLevel rateLimiterLevel = new RateLimiterLevel();
        Map<String,Integer[]> map = new HashMap<>();
        list.forEach(sysRateLimiter -> {
            map.put(sysRateLimiter.getLevel(),new Integer[]{sysRateLimiter.getReplenishRate(),sysRateLimiter.getBurstCapacity(),sysRateLimiter.getLimitType()});
        });
        rateLimiterLevel.setLevels(map);
        limiterLevelResolver.save(rateLimiterLevel);
        log.info("==============限流配置初始化成功================");
    }

}

本篇介绍了,把限流参数放到redis,下一篇介绍,在http请求过来的时候,经过网关,在网关中使用保存在redis中的限流参数进行限流《网关 springcloud-gateway 基于Token限流》

具体代码:传送门 : https://github.com/yzcheng90/ms

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐