美文网首页
简单限流器封装

简单限流器封装

作者: 川流不息attitude | 来源:发表于2022-07-05 10:47 被阅读0次

简单限流器封装

开发过程中有时候 我们会做一些简单的限流 操作,比如 告警提醒,发送验证码 等,希望在 一段时间 只许调用几次。

下面基于redis incr 命令通用封装
@RequiredArgsConstructor
@Getter
public enum LimitTypeEnum {

    SECOND(1,"秒"),MINUTE(60,"分"),HOUR(60*60,"小时"),DAY(60*60*24,"天");
    /**
     * 类型
     */
    private final int time;

    /**
     * 描述
     */
    private final String description;
}
 * 限制调用次数
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Limit {
    /**
     * 限制次数
     * @return
     */
    long count() default 1L;

    /**
     * 提示消息
     * @return
     */
    String msg() default "请求过于频繁";

    /**
     * 是否带方法参数 md5(类名+方法名+方法参数)
     * @return
     */
    boolean param() default true;
    /**
     * 限制类型
     * @return
     */
    LimitTypeEnum limitType() default LimitTypeEnum.SECOND;
}
@Aspect
@Component
public class LimitAspect {

    private static final String LOCK_REPEATED_SUBMIT = "limit:";

    @Autowired
    private RedisTemplate redisTemplate;

    @Around("@annotation(limit)")
    public Object around(ProceedingJoinPoint pjp, Limit limit) throws Throwable {
        try {
            //获取当前执行类
            String className = pjp.getSignature().getDeclaringTypeName();
            //获取当前执行类中的执行方法
            String methodName = pjp.getSignature().getName();
            String key = className + methodName;
            if(limit.param()){
                // 参数
                Map<String, Object> params = getRequestParams(pjp);
                key = key + JSON.toJSONString(params);
            }
            String md5 = SecureUtil.md5(key);
            String redisKey = LOCK_REPEATED_SUBMIT + md5;
            redisTemplate.opsForValue().setIfAbsent(redisKey, CommonConstants.ZERO,limit.limitType().getTime(),TimeUnit.SECONDS);
            Long count = redisTemplate.opsForValue().increment(redisKey);
            if(count <= limit.count()){
                Object result = pjp.proceed();
                return result;
            }
            throw new BusinessException(limit.msg());
        } catch (Throwable e) {
            throw e;
        }
    }


    /**
     * 获取入参
     * @param proceedingJoinPoint
     *
     * @return
     * */
    private Map<String, Object> getRequestParams(ProceedingJoinPoint proceedingJoinPoint) {
        Map<String, Object> requestParams = new HashMap<>();
        //参数名
        String[] paramNames =
                ((MethodSignature)proceedingJoinPoint.getSignature()).getParameterNames();
        //参数值
        Object[] paramValues = proceedingJoinPoint.getArgs();

        for (int i = 0; i < paramNames.length; i++) {
            Object value = paramValues[i];
            //如果是文件对象
            if (value instanceof MultipartFile) {
                MultipartFile file = (MultipartFile) value;
                //获取文件名
                value = file.getOriginalFilename();
            }
            if(value instanceof HttpServletResponse){
                continue;
            }
            if(value instanceof HttpServletRequest){
                continue;
            }
            requestParams.put(paramNames[i], value);
        }

        return requestParams;
    }
}
使用
image.png

测试

image.png image.png

可见并发测试的时候,有5 次请求 被拒绝了,限流成功。

限流还有其他 方式 令牌桶,漏桶,滑动窗口 等

有兴趣 参考 Guava, redisson https://github.com/redisson/redisson/wiki/6.-%E5%88%86%E5%B8%83%E5%BC%8F%E5%AF%B9%E8%B1%A1#612-%E9%99%90%E6%B5%81%E5%99%A8ratelimiter (令牌桶)

相关文章

  • 简单限流器封装

    简单限流器封装 开发过程中有时候 我们会做一些简单的限流 操作,比如 告警提醒,发送验证码 等,希望在 一段时间 ...

  • 单机限流 - 限流算法及隔离策略

    限流算法 - 计数器 计数器是一种比较简单的限流算法,用途比较广泛,在接口层面,很多地方使用这种方式限流。在一段时...

  • 基于计数器的服务接口限流实例

    计数器限流是服务接口限流策略中最为基本和简单的方式。本实例将实现不同接口设置不同的限流方案。 首先我们需要需要定义...

  • 高可用实践-限流算法

    限流算法 常见的限流算法有计数器算法、漏桶算法和令牌桶算法。 计数器法 计数器算法“简单粗暴”。该算法会维护一个c...

  • 限流器的简单实现

    问题分析 场景 场景如下:我们有10w台设备,这10w台设备会不定时向服务端上报数据,如果消息的并发量比较大的话,...

  • 经典限流算法:令牌桶算法

    Guava 的限流器使用上还是很简单的,那它是如何实现的呢?Guava 采用的是令牌桶算法,其核心是要想通过限流器...

  • 限流算法实现

    并发数限流 1. 计数器并发数限流 2. 信号量(Semaphore) 其实最简单的方法就是用信号量来实现: QP...

  • 限流降级方案

    限流算法 并发数限流 计数器并发数限流:使用共享变量实现 信号量:使用java中的Semaphore QPS限流 ...

  • Guava RateLimiter的实现

    限流 高并发系统有三大利器:缓存 、限流 、降级。对于限流的实现,有多种算法:计数器,漏桶法,令牌桶法。计数器法无...

  • RateLimiter源码解析

    计数器限流 最原始的代码 但是计数器限流无法对相邻两秒都是高qps进行限流,比如1:29:29.999有100qp...

网友评论

      本文标题:简单限流器封装

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