Java lettuce实现分布式限流

Lettuce Client Util

package com.zjw.utils;

import io.lettuce.core.RedisClient;
import io.lettuce.core.RedisURI;
import io.lettuce.core.api.StatefulRedisConnection;

import java.time.Duration;

/**
 * @author zjwblog <cn.zjwblog@gmail.com>
 * @version 1.0
 */
public class LettuceSentinelRedisUtil {
  private static RedisURI redisUri = null;
  private static RedisClient client;
  static {
    String[] sentinels = "127.0.0.1:26371,127.0.0.1:26372,127.0.0.1:26373".split(",");
    RedisURI.Builder builder = null;
    if(sentinels.length > 0) {
      String[] hostAndPort = sentinels[0].split(":");
      builder = RedisURI.Builder.sentinel(hostAndPort[0], Integer.parseInt(hostAndPort[1]),
          "my_redis_sentinel");
    }
    for (int i = 1; i < sentinels.length; i++) {
      String[] hostAndPort = sentinels[i].split(":");
      builder.withSentinel(hostAndPort[0], Integer.parseInt(hostAndPort[1]));
    }
    if(builder!=null) {
      builder.withTimeout(Duration.ofMillis(200));
      builder.withPassword("123456".toCharArray());
      builder.withDatabase(0);
      redisUri = builder.build();
    }

    client = RedisClient.create(redisUri);
  }

  public static RedisClient getClient() {
    return client;
  }

  public static StatefulRedisConnection<String, String> getConn() {
    return client.connect();
  }
}

ScrollWindowLimiter

package com.zjw.utils;

import io.lettuce.core.Range;
import io.lettuce.core.api.StatefulRedisConnection;
import io.lettuce.core.api.sync.RedisCommands;

import java.util.Date;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @author zjwblog <cn.zjwblog@gmail.com>
 * @version 1.0
 * @desc 滚动窗口实现分布式限流
 */
public class ScrollWindowLimiter {
  private static final StatefulRedisConnection<String, String> conn = LettuceSentinelRedisUtil.getConn();
  private static final RedisCommands<String, String> commands = conn.sync();
  private static final long intervalTime = 1000L;

  public static boolean tryAccess(String bucket, Integer qps) {
    long currentTime = new Date().getTime();
    long lower = currentTime/1000 * 1000;
    long upper = currentTime/1000 * 1000 + 1000;
    boolean exists = commands.exists(bucket) > 0;
    if (exists) {
      Range<Long> currentWindow = Range.create(lower, upper);
      Range<Long> beforeWindow = Range.create(0L, lower);
      Long count = commands.zcount(bucket, currentWindow);
      System.out.println(count);
      // 删除过期的时间戳
      commands.zremrangebyscore(bucket, beforeWindow);
      if (count != null && count > qps) {
        return false;
      } else {
        // 加入当前的时间戳
        commands.zadd(bucket, currentTime, UUID.randomUUID().toString());
        return true;
      }
    } else {
      // 加入当前的时间戳
      commands.zadd(bucket, currentTime, UUID.randomUUID().toString());
      return true;
    }
  }

  public static void main(String[] args) throws InterruptedException {
    Random r = new Random();
    for (; ; ) {
      boolean b = tryAccess("jobmd_job4resume", 10);
      System.out.println("滚动窗口限流-是否通过:" + b);
      int sleepTime = r.nextInt(170);
      TimeUnit.MILLISECONDS.sleep(sleepTime);
    }
  }
}

SlidingWindowLimiter

package com.zjw.utils;

import io.lettuce.core.Range;
import io.lettuce.core.api.StatefulRedisConnection;
import io.lettuce.core.api.sync.RedisCommands;

import java.util.Date;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @author zjwblog <cn.zjwblog@gmail.com>
 * @version 1.0
 * @desc 滑动窗口实现分布式限流
 */
public class SlidingWindowLimiter {
  private static final StatefulRedisConnection<String, String> conn = LettuceSentinelRedisUtil.getConn();
  private static final RedisCommands<String, String> commands = conn.sync();
  private static final long intervalTime = 1000L;

  public static boolean tryAccess(String bucket, Integer qps) {
    long currentTime = new Date().getTime();
    boolean exists = commands.exists(bucket) > 0;
    if (exists) {
      Range<Long> inWindowRange = Range.create(currentTime - intervalTime, currentTime);
      Range<Long> outWindowRange = Range.create(0L, currentTime - intervalTime);
      Long count = commands.zcount(bucket, inWindowRange);
      System.out.println(count);
      // 删除过期的时间戳
      commands.zremrangebyscore(bucket, outWindowRange);
      if (count != null && count > qps) {
        return false;
      } else {
        // 加入当前的时间戳
        commands.zadd(bucket, currentTime, UUID.randomUUID().toString());
        return true;
      }
    } else {
      // 加入当前的时间戳
      commands.zadd(bucket, currentTime, UUID.randomUUID().toString());
      return true;
    }
  }

  public static void main(String[] args) throws InterruptedException {
    Random r = new Random();
    for (; ; ) {
      boolean b = tryAccess("jobmd_job4job", 10);
      System.out.println("滑动窗口-是否通过:" + b);
      int sleepTime = r.nextInt(170);
      TimeUnit.MILLISECONDS.sleep(sleepTime);
    }
  }
}

TokenLimiter

package com.zjw.utils;

import io.lettuce.core.api.StatefulRedisConnection;
import io.lettuce.core.api.sync.RedisCommands;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

/**
 * @author zjwblog <cn.zjwblog@gmail.com>
 * @version 1.0
 * @desc 令牌桶实现分布式限流
 */
public class TokenLimiter {
  private static final StatefulRedisConnection<String, String> conn = LettuceSentinelRedisUtil.getConn();
  private static final RedisCommands<String, String> commands = conn.sync();

  private static final Timer timer = new Timer();
  // 桶: qps
  private static final ConcurrentHashMap<String, Integer> config = new ConcurrentHashMap<>();

  // 放入令牌 每250ms向令牌桶里面放满 1/4 的QPS,相当于每1秒放满令牌桶
  static {
    timer.schedule(new TimerTask() {
      @Override
      public void run() {
        for (Map.Entry<String, Integer> entry : config.entrySet()) {
          for (int i = 0; i < entry.getValue() / 4; i++) {
            if (commands.llen(entry.getKey()) < entry.getValue()) {
              commands.rpush(entry.getKey(), UUID.randomUUID().toString());
            }
          }
        }
      }
    }, 0, 250);

  }

  public static void setConfig(String bucket, Integer qps) {
    config.put(bucket, qps);
  }

  public static void delConfig(String bucket) {
    config.remove(bucket);
  }

  public static boolean tryAccess(String bucket) {
    Object result = commands.lpop(bucket);

    return result != null;
  }

  public static void main(String[] args) throws InterruptedException {
    TokenLimiter.setConfig("jobmd_resume4job", 10);
    Random r = new Random();
    for (; ; ) {
      boolean b = TokenLimiter.tryAccess("jobmd_resume4job");
      System.out.println("令牌桶限流-是否通过:" + b);
      int sleepTime = r.nextInt(170);
      TimeUnit.MILLISECONDS.sleep(sleepTime);
    }
  }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值