package com.zeng.ratelimit; /** * @Description:限流器工厂 * @Author jerry * Date 2020/1/3 9:52 上午 **/ public class RateLimiterFactory { public static SimpleRateLimiter getSimpleRateLimiter(RateLimiterParam rateLimiterParam) { if (RateLimiterType.SEMAPHORE.equals(rateLimiterParam.getRateLimiterType())) { return new SemaphoreRateLimiter(rateLimiterParam); } else { return new TokenBucketRateLimiter(rateLimiterParam); } } }
package com.zeng.ratelimit; import java.util.Objects; import java.util.concurrent.TimeUnit; /** * @Description:限流器 * @Author jerry * Date 2020/1/3 9:53 上午 **/ public class RateLimiterParam { private RateLimiterType rateLimiterType = RateLimiterType.TOKEN_BUCKET; private int threshold = 50; private long timeout = 3000; private TimeUnit unit = TimeUnit.MILLISECONDS; public int getThreshold() { return threshold; } public RateLimiterParam setThreshold(int threshold) { this.threshold = threshold; return this; } public long getTimeout() { return timeout; } public RateLimiterParam setTimeout(long timeout) { this.timeout = timeout; return this; } public TimeUnit getUnit() { return unit; } public RateLimiterParam setUnit(TimeUnit unit) { this.unit = unit; return this; } public RateLimiterType getRateLimiterType() { return rateLimiterType; } public void setRateLimiterType(RateLimiterType rateLimiterType) { this.rateLimiterType = rateLimiterType; } @Override public String toString() { return "RateLimiterParam{" + "rateLimiterType=" + rateLimiterType + ", threshold=" + threshold + ", timeout=" + timeout + ", unit=" + unit + '}'; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } RateLimiterParam that = (RateLimiterParam) o; return threshold == that.threshold && timeout == that.timeout && rateLimiterType == that.rateLimiterType && unit == that.unit; } @Override public int hashCode() { return Objects.hash(rateLimiterType, threshold, timeout, unit); } }
package com.zeng.ratelimit; /** * @Description:限流器类型枚举 * @Author jerry * Date 2020/1/3 10:01 上午 **/ public enum RateLimiterType { SEMAPHORE(1, "并发限流"), TOKEN_BUCKET(2, "令牌桶限流"); private int code; private String desc; RateLimiterType(int code, String desc) { this.code = code; this.desc = desc; } public int getCode() { return code; } public void setCode(int code) { this.code = code; } public String getDesc() { return desc; } public void setDesc(String desc) { this.desc = desc; } }
package com.zeng.ratelimit; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; /** * @Description:计数器限流 * @Author jerry * Date 2020/1/3 10:12 上午 **/ public class SemaphoreRateLimiter extends SimpleRateLimiter { private Semaphore semaphore; public SemaphoreRateLimiter(RateLimiterParam rateLimiterParam) { super(rateLimiterParam); this.semaphore = new Semaphore(rateLimiterParam.getThreshold()); } @Override public long acquire() { try { long start = System.currentTimeMillis(); semaphore.acquire(); return TimeUnit.NANOSECONDS.toMicros(System.currentTimeMillis() - start); } catch (InterruptedException e) { throw new RateLimiterException("rate limiter is interrupted by others"); } } @Override public boolean tryAcquire(long timeout, TimeUnit unit) { try { return semaphore.tryAcquire(timeout, unit); } catch (InterruptedException e) { throw new RateLimiterException("rate limiter is interrupted by others"); } } @Override public void supply() { semaphore.release(); } }
package com.zeng.ratelimit; import com.google.common.base.Preconditions; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Objects; import java.util.concurrent.TimeUnit; /** * @Description:简单限流器基类 * @Author jerry * Date 2020/1/3 9:53 上午 **/ public abstract class SimpleRateLimiter { protected static final Logger log = LoggerFactory.getLogger(SimpleRateLimiter.class); protected RateLimiterParam rateLimiterParam = new RateLimiterParam(); public SimpleRateLimiter(RateLimiterParam rateLimiterParam) { Preconditions.checkNotNull(rateLimiterParam, "限流参数不能为空!"); setRateLimiterParam(rateLimiterParam); } public RateLimiterParam getRateLimiterParam() { return rateLimiterParam; } private void setRateLimiterParam(RateLimiterParam rateLimiterParam) { if (rateLimiterParam.getThreshold() < 0) { log.warn("ratelimiter threshold set to " + rateLimiterParam.getThreshold() + ", is less than zero, will have no effect."); } else { this.rateLimiterParam.setThreshold(rateLimiterParam.getThreshold()); } if (rateLimiterParam.getTimeout() < 0) { log.warn("ratelimiter timeout set to " + rateLimiterParam.getThreshold() + ", is less than zero, will have no effect."); } else { this.rateLimiterParam.setTimeout(rateLimiterParam.getTimeout()); } if (Objects.isNull(rateLimiterParam.getUnit())) { log.warn("ratelimiter timeUnit is null, will have no effect."); } else { this.rateLimiterParam.setUnit(rateLimiterParam.getUnit()); } this.rateLimiterParam.setRateLimiterType(rateLimiterParam.getRateLimiterType()); } public abstract long acquire(); public boolean tryDefaultAcquire() { return tryAcquire(rateLimiterParam.getTimeout(), rateLimiterParam.getUnit()); } public abstract boolean tryAcquire(long timeout, TimeUnit unit); public abstract void supply(); }
package com.zeng.ratelimit; import com.google.common.util.concurrent.RateLimiter; import java.util.concurrent.TimeUnit; /** * @Description:令牌桶限流 * @Author jerry * Date 2020/1/3 10:12 上午 **/ public class TokenBucketRateLimiter extends SimpleRateLimiter { private RateLimiter limiter; public TokenBucketRateLimiter(RateLimiterParam rateLimiterParam) { super(rateLimiterParam); this.limiter = RateLimiter.create(rateLimiterParam.getThreshold()); } @Override public long acquire() { long start = System.currentTimeMillis(); limiter.acquire(); return TimeUnit.NANOSECONDS.toMicros(System.currentTimeMillis() - start); } @Override public boolean tryAcquire(long timeout, TimeUnit unit) { return limiter.tryAcquire(timeout, unit); } @Override public void supply() { } }