美文网首页
基于计数器的服务接口限流实例

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

作者: 文景大大 | 来源:发表于2019-12-21 13:31 被阅读0次

计数器限流是服务接口限流策略中最为基本和简单的方式。本实例将实现不同接口设置不同的限流方案。

首先我们需要需要定义一个限流枚举类,用来存储各个接口需要设置的限流信息。

public enum LimitEnum {
    /**
     * 获取邮箱信息的接口限制,每秒最多被调用3次
     * */
    GET_MAIL_INFO_LIMIT("/getMailInfo", 3, 1),
    /**
     * 获取用户信息的接口限制,每2秒最多被调用5次
     * */
    GET_USER_INFO_LIMIT("/getUserInfo", 5, 2);

    private String urlName;
    private Integer maxCount;
    private Integer timePeriod;

    LimitEnum(String urlName, Integer maxCount, Integer timePeriod) {
        this.urlName = urlName;
        this.maxCount = maxCount;
        this.timePeriod = timePeriod;
    }

    public String getUrlName() {
        return urlName;
    }

    public Integer getMaxCount() {
        return maxCount;
    }

    public Integer getTimePeriod() {
        return timePeriod;
    }
}

然后,我们需要一个接口限流实体类,用来记录内存中的每个接口实时限流信息。

@Data
public class LimitDTO {
    /**
     * 单位时间内最大调用次数
     * */
    private Integer maxCount;
    /**
     * 自定义单位时间
     * */
    private Long expireTime;
    /**
     * 当前单位时间内的已调用次数
     * */
    private Integer currentCount;
}

下面,就是计数器限流的核心代码:

@Slf4j
public class CountLimiter {
    /**
     * 存放所有URL的计数器
     */
    private static Map<String, LimitDTO> limitMap = new ConcurrentHashMap<>();

    public static Boolean acquire(LimitEnum limitEnum) {
        LimitDTO limitDTO = limitMap.get(limitEnum.getUrlName());

        // 该URL首次使用限流或者限流信息已经过期,则需要初始化该URL的限流信息
        if (null == limitDTO || limitDTO.getExpireTime() < System.currentTimeMillis()) {
            limitMap.put(limitEnum.getUrlName(), resetLimitInfo(limitEnum, limitDTO));
            return true;
        }

        // 该URL非首次使用限流,且限流信息未过期
        if(limitDTO.getCurrentCount() >= limitEnum.getMaxCount()){
            log.warn("{}超出了调用限制,在{}秒内最多只能调用{}次,当前已经调用{}次!"
            , limitEnum.getUrlName(), limitEnum.getTimePeriod()
            , limitEnum.getMaxCount(), limitDTO.getCurrentCount());
            return false;
        }

        limitDTO.setCurrentCount(limitDTO.getCurrentCount() + 1);
        limitMap.put(limitEnum.getUrlName(), limitDTO);
        return true;
    }

    private static LimitDTO resetLimitInfo(LimitEnum limitEnum, LimitDTO limitDTO) {
        if (null == limitDTO) {
            limitDTO = new LimitDTO();
        }
        limitDTO.setMaxCount(limitEnum.getMaxCount());
        limitDTO.setExpireTime(limitEnum.getTimePeriod() * 1000 + System.currentTimeMillis());
        limitDTO.setCurrentCount(1);
        return limitDTO;
    }
}

最后,我们对外提供接口,在接口被调用的时候,我们需要使用同步的方式获取对计数器的读写权限。

@Slf4j
@RestController("/limit")
public class LimitRest {

    @GetMapping("/getMailInfo")
    public String getMailInfo(){
        Boolean limitFlag = false;
        synchronized (LimitRest.class){
            limitFlag = CountLimiter.acquire(LimitEnum.GET_MAIL_INFO_LIMIT);
        }
        if(!limitFlag){
            return "调用太频繁啦,请稍后再试!";
        }
        return "OK";
    }

    @GetMapping("/getUserInfo")
    public String getUserInfo(){
        Boolean limitFlag = false;
        synchronized (LimitRest.class){
            limitFlag = CountLimiter.acquire(LimitEnum.GET_USER_INFO_LIMIT);
        }
        if(!limitFlag){
            return "调用太频繁啦,请稍后再试!";
        }
        return "OK";
    }
}

计数器限流方案的特点是,在单位时间内只允许固定数量的请求得到服务,其余的全部失败。但是这些固定数量的得到服务的请求可以是第一个毫秒就全部发生的,也可以是在单位时间内均匀发生的。

所以,我们无法控制请求的发生频率,造成的结果就是,在整个单位时间内,有的时间段服务器很忙,疲惫不堪;有的时间段服务器却很闲。

全文完。

相关文章

  • 基于信号量Semaphore的服务接口限流实例

    前景回顾:《基于计数器的服务接口限流实例》《基于RateLimiter的服务接口限流实例》 一、Semaphore...

  • 基于RateLimiter的服务接口限流实例

    前景回顾:《基于计数器的服务接口限流实例》 一、RateLimit中acquire的使用 在前面这篇文章中,我们使...

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

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

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

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

  • (9)弹力设计篇之“限流设计”

    1、限流的策略 2、限流的算法:计数器、队列、漏斗和令牌桶。 3、如何基于响应时间来限流。 4、限流设计的要点 限...

  • 限流算法

    限流的算法 常见的限流算法有:计数器、漏桶和令牌桶算法。 计数器 设定单位时间限制接口的请求数量为n,单位时间内的...

  • 接口限流

    接口限流 简述 有时候,接口对外提供服务的时候,需要保护我们的接口,避免并发过大导致系统瘫痪。 限流算法 常用的限...

  • Guava RateLimiter的实现

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

  • RateLimiter源码解析

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

  • 分布式限流 - 基于redis

    1,基于redis计数器 1)普通redis incr限流。不能保证原子性image.png2)lua脚本实现计数...

网友评论

      本文标题:基于计数器的服务接口限流实例

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