美文网首页
redission简单实现分布式限流组件

redission简单实现分布式限流组件

作者: 不二不二熊 | 来源:发表于2022-06-27 22:22 被阅读0次

    业务场景

    某个三方API接口限制调用频率为200/min,但是某项业务功能中需要频繁的去调用该接口。尽量不去触发限流规则,因此在内部接口调用前先行限流。

    技术选型

    本着接入时间成本考虑以及包含分布式场景,选用redission在目前看来是比较好的选择。

    主要代码实现

    POM引入

        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson</artifactId>
            <version>3.17.3</version>
        </dependency>
    

    配置引入

    spring:
        redisson:
        database: 1
        address: redis://127.0.0.1:6379
        password:
        connectionPoolSize: 8
        connectionMinimumIdleSize: 3
        subscriptionConnectionPoolSize: 6
        subscriptionConnectionMinimumIdleSize: 1
    

    RedissonClient注册

    @Component
    public class RedissonClientConfig {
    
        @Value("${spring.redisson.address}")
        private String address;
    
        @Value("${spring.redisson.database}")
        private Integer dataBase;
    
        @Bean
        public RedissonClient redissonClient(){
            Config config = new Config();
            config.useSingleServer().setAddress(address)
                    .setDatabase(dataBase);
            return Redisson.create(config);
        }
    }
    

    自定义限流注解

    @Target({ElementType.TYPE, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface ApiRateLimiter {
    
        String name();
    
        long rate() default 180;
    }
    

    定义简单工厂

    public class RateLimiterFactory {
        private volatile static RateLimiterFactory SINGLETON;
    
        private RateLimiterFactory(){}
    
    
        private final ConcurrentHashMap<String, RRateLimiter> rateLimiterMap = new ConcurrentHashMap<>();
    
        public static RateLimiterFactory getSingleton() {
            if (null==SINGLETON) {
                synchronized (RateLimiterFactory.class) {
                    if (null==SINGLETON) {
                        SINGLETON = new RateLimiterFactory();
                    }
                }
            }
            return SINGLETON;
        }
    
        public RRateLimiter get(String name, long rate) {
            if (StringUtils.isBlank(name)) {
                throw new IllegalArgumentException("rate name can not be empty");
            }
            if (rate < 0) {
                throw new IllegalArgumentException("rate must be >0");
            }
            RRateLimiter rRateLimiter = rateLimiterMap.get(name);
            if (null==rRateLimiter) {
                RedissonClient redissonClient = (RedissonClient)SpringContextUtil.getBean("redissonClient");
                rRateLimiter = redissonClient.getRateLimiter(name);
                //根据业务选择 RateType 参数
                rRateLimiter.setRate(RateType.OVERALL, rate, 60, RateIntervalUnit.SECONDS);
                rateLimiterMap.put(name, rRateLimiter);
            }
            return rRateLimiter;
        }
    }
    

    定义切面

    @Slf4j
    @Component
    @Aspect
    public class ApiRateLimitAspect {
    
    
        @Pointcut("@annotation(ApiRateLimiter类路径)")
        public void rateLimitPoint() {
        }
    
    
        @Around("rateLimitPoint()")
        public Object aroundAop(ProceedingJoinPoint joinPoint) throws Throwable {
            Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
            ApiRateLimiter apiRateLimiter = AnnotationUtils.getAnnotation(method, ApiRateLimiter.class);
            if (null == apiRateLimiter) {
                return joinPoint.proceed();
            }
            long rate = apiRateLimiter.rate();
            String name = apiRateLimiter.name();
            RRateLimiter newRankLimiter  = RateLimiterFactory.getSingleton().get(name, rate);
            //根据业务选择 acquire 以及 tryAcquire
            newRankLimiter.acquire();
            return joinPoint.proceed();
        }
    

    相关文章

      网友评论

          本文标题:redission简单实现分布式限流组件

          本文链接:https://www.haomeiwen.com/subject/iviovrtx.html