• Java 对IP请求进行限流.


    高并发系统下, 有三把利器 缓存 降级 限流.

    • 缓存: 将常用数据缓存起来, 减少数据库或者磁盘IO
    • 降级: 保护核心系统, 降低非核心业务请求响应
    • 限流: 在某一个时间窗口内对请求进行限速, 保护系统

     本文主要介绍限流, 常见限流算法中又分为计数器算法, 漏桶算法, 令牌桶算法.

    计数器算法

    比较简单, 直接用一个map + counter即可实现. 请求来了, 以IP为key,

    查询下之前响应次数, 如果调用次数超出MAX_COUT, 返回失败, 属于简单粗暴型选手.

    漏桶算法

    请求全部进入漏桶, 漏桶恒定速率输出反馈. 这样可以保证数据传输平滑,

    但是无法预防突发大量请求, 一秒来了100个请求, 都要阻塞排队, 从小水管输出数据.

     

    令牌桶算法

    令牌桶是以固定速度往桶里存令牌, 例如一秒存1000个令牌, 业务请求来了, 直接从桶里获取令牌响应输出.

    跟漏桶的差异在于, 他可以预存令牌, 如果一秒钟来了100个请求, 桶里有100个令牌,

    那么可以立刻响应给客户端, 而不是排队输出.

     

    令牌桶的实现

    guava中提供了令牌桶的一个封装实现RateLimiter, 可以直接调用, 省的我们自己包装ConcurrentHashMap + Timer.

    我们预设的场景是服务器端提供一个API供不同客户端查询, 要限流每个IP每秒只能调用两次该API.

    首先要定义一个服务器端的缓存, 定期清理即可, 缓存 IP : 令牌桶

     1     // 根据IP分不同的令牌桶, 每天自动清理缓存
     2     private static LoadingCache<String, RateLimiter> caches = CacheBuilder.newBuilder()
     3             .maximumSize(1000)
     4             .expireAfterWrite(1, TimeUnit.DAYS)
     5             .build(new CacheLoader<String, RateLimiter>() {
     6                 @Override
     7                 public RateLimiter load(String key) throws Exception {
     8                     // 新的IP初始化 (限流每秒两个令牌响应)
     9                     return RateLimiter.create(2);
    10                 }
    11             });

    然后在业务代码中进行限流调用

     1     private static void login(int i) throws ExecutionException {
     2         // 模拟IP的key
     3         String ip = String.valueOf(i).charAt(0) + "";
     4         RateLimiter limiter = caches.get(ip);
     5 
     6         if (limiter.tryAcquire()) {
     7             System.out.println(i + " success " + new SimpleDateFormat("HH:mm:ss.sss").format(new Date()));
     8         } else {
     9             System.out.println(i + " failed " + new SimpleDateFormat("HH:mm:ss.sss").format(new Date()));
    10         }
    11     }

    模拟客户端调用

    1         for (int i = 0; i < 1000; i++) {
    2             // 模拟实际业务请求
    3             Thread.sleep(100);
    4             login(i);
    5         }

    完整代码

     1 public class doLimit {
     2 
     3     // 根据IP分不同的令牌桶, 每天自动清理缓存
     4     private static LoadingCache<String, RateLimiter> caches = CacheBuilder.newBuilder()
     5             .maximumSize(1000)
     6             .expireAfterWrite(1, TimeUnit.DAYS)
     7             .build(new CacheLoader<String, RateLimiter>() {
     8                 @Override
     9                 public RateLimiter load(String key) throws Exception {
    10                     // 新的IP初始化 (限流每秒两个令牌响应)
    11                     return RateLimiter.create(2);
    12                 }
    13             });
    14 
    15     public static void main(String[] args) throws InterruptedException, ExecutionException {
    16         for (int i = 0; i < 1000; i++) {
    17             // 模拟实际业务请求
    18             Thread.sleep(100);
    19             login(i);
    20         }
    21     }
    22 
    23     private static void login(int i) throws ExecutionException {
    24         // 模拟IP的key
    25         String ip = String.valueOf(i).charAt(0) + "";
    26         RateLimiter limiter = caches.get(ip);
    27 
    28         if (limiter.tryAcquire()) {
    29             System.out.println(i + " success " + new SimpleDateFormat("HH:mm:ss.sss").format(new Date()));
    30         } else {
    31             System.out.println(i + " failed " + new SimpleDateFormat("HH:mm:ss.sss").format(new Date()));
    32         }
    33     }
    34 }
    View Code
  • 相关阅读:
    http响应状态码大全
    Internet protocol security (ipsec) packet processing for multiple clients sharing a single network address
    linq.js的用法
    linq.js的用法
    程序员每天应该思考的5个问题,你有思考过吗?
    程序员每天应该思考的5个问题,你有思考过吗?
    程序员每天应该思考的5个问题,你有思考过吗?
    Win10 owerShell Get命令大全
    Win10 owerShell Get命令大全
    Win10 owerShell Get命令大全
  • 原文地址:https://www.cnblogs.com/xdecode/p/8275804.html
Copyright © 2020-2023  润新知