限制ip访问频率

需求是每1000毫秒内,只允许同一个ip访问2次

效果如图:

在这里插入图片描述

代码如下:


import java.text.SimpleDateFormat;
import java.time.Instant;
import java.util.Calendar;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ConcurrentSkipListMap;

import java.util.concurrent.atomic.AtomicInteger;

class RequestRecord {
    private final Instant timestamp;
    private final AtomicInteger count = new AtomicInteger(1);

    public RequestRecord(Instant timestamp) {
        this.timestamp = timestamp;
    }

    public Instant getTimestamp() {
        return timestamp;
    }

    public int getCount() {
        return count.get();
    }

    public void increment() {
        count.incrementAndGet();
    }
}


class SlidingWindowRateLimiter {
    private final ConcurrentSkipListMap<Instant, RequestRecord> records;
    private final long windowSizeInMillis;
    private final int limit;

    public SlidingWindowRateLimiter(long windowSizeInMillis, int limit) {
        this.records = new ConcurrentSkipListMap<>();
        this.windowSizeInMillis = windowSizeInMillis;
        this.limit = limit;
    }

    public synchronized boolean allowRequest() {
        Instant now = Instant.now();
        // 移除窗口外的旧记录
        records.headMap(now.minusMillis(windowSizeInMillis)).clear();

        // 检查当前窗口内是否已达到请求限制
        int totalRequests = records.values().stream().mapToInt(RequestRecord::getCount).sum();
        if (totalRequests >= limit) {
            return false;
        }

        // 添加当前请求记录
        records.compute(now, (key, value) -> {
            if (value == null) {
                return new RequestRecord(now);
            } else {
                value.increment();
                return value;
            }
        });
        return true;
    }
}

public class IPBasedSlidingWindowRateLimiter {
    private final ConcurrentMap<String, SlidingWindowRateLimiter> ipRateLimiters;
    private final long windowSizeInMillis;
    private final int limitPerWindow;

    public IPBasedSlidingWindowRateLimiter(long windowSizeInMillis, int limitPerWindow) {
        this.ipRateLimiters = new ConcurrentHashMap<>();
        this.windowSizeInMillis = windowSizeInMillis;
        this.limitPerWindow = limitPerWindow;
    }

    public synchronized boolean allowRequest(String ipAddress) {
        SlidingWindowRateLimiter limiter = ipRateLimiters.computeIfAbsent(ipAddress,
                k -> new SlidingWindowRateLimiter(windowSizeInMillis, limitPerWindow));
        return limiter.allowRequest();
    }

    public static String curDateTimeStr() {
        Calendar calendar2 = Calendar.getInstance();
        SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return sdf2.format(calendar2.getTime());
    }


    public static void main(String[] args) throws InterruptedException {
        // http请求根据ip限制频率
        IPBasedSlidingWindowRateLimiter rateLimiter = new IPBasedSlidingWindowRateLimiter(1000, 2);
        String ip = "1.1.1.1";
        String ip2 = "2.2.2.2";
        for (int i = 0; i < 200; i++) {
            if (rateLimiter.allowRequest(ip)) {
                System.out.println("["+curDateTimeStr()+"] "+i+":允许访问"+ip);
            } else {
                System.out.println("["+curDateTimeStr()+"] "+i+":访问受限"+ip + "," + (rateLimiter.allowRequest(ip2) ? "允许访问"+ip2 : "访问受限"+ip2));
                Thread.sleep(2000L);
            }
        }
    }
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值