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() {
}
}