dubboのTPSLimiterについて話します
4669 ワード
シーケンス
本文は主にdubboのTPSLimiterを研究する
TPSLimiter
dubbo-2.7.2/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/tps/TPSLimiter.java TPSLimiterはisAllowableメソッド を定義する
DefaultTPSLimiter
dubbo-2.7.2/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/tps/DefaultTPSLimiter.java DefaultTPSLimiterは、ConcurrentHashMapを使用してStatItemを格納するTPSLimiterを実現し、keyはURLのserviceKeyである.isAllowableメソッドはURLからtpsパラメータを読み出し、デフォルトは-1、0未満はConcurrentHashMapから削除し、0より大きいとStatItemを作成または取得し、StatItemのisAllowable( を呼び出す.
StatItem
dubbo-2.7.2/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/tps/StatItem.java StatItemはLongAdderタイプのtokenを定義し、isAllowableメソッドはtokenをリセットする必要があるかどうかを判断し、必要であればbuildLongAdderを使用してtokenをリセットし、必要でなければ を減算する
小結 TPSLimiterはisAllowableメソッド を定義する DefaultTPSLimiterは、ConcurrentHashMapを使用してStatItemを格納するTPSLimiterを実現し、keyはURLのserviceKeyである.isAllowableメソッドはURLからtpsパラメータを読み出し、デフォルトは-1、0未満はConcurrentHashMapから削除し、0より大きいとStatItemを作成または取得し、StatItemのisAllowable( を呼び出す. StatItemはLongAdderタイプのtokenを定義し、isAllowableメソッドはtokenをリセットする必要があるかどうかを判断し、必要であればbuildLongAdderを使用してtokenをリセットし、必要でなければ を減算する
doc TPSLimiter DefaultTPSLimiter StatItem
本文は主にdubboのTPSLimiterを研究する
TPSLimiter
dubbo-2.7.2/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/tps/TPSLimiter.java
public interface TPSLimiter {
/**
* judge if the current invocation is allowed by TPS rule
*
* @param url url
* @param invocation invocation
* @return true allow the current invocation, otherwise, return false
*/
boolean isAllowable(URL url, Invocation invocation);
}
DefaultTPSLimiter
dubbo-2.7.2/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/tps/DefaultTPSLimiter.java
public class DefaultTPSLimiter implements TPSLimiter {
private final ConcurrentMap stats = new ConcurrentHashMap();
@Override
public boolean isAllowable(URL url, Invocation invocation) {
int rate = url.getParameter(TPS_LIMIT_RATE_KEY, -1);
long interval = url.getParameter(TPS_LIMIT_INTERVAL_KEY, DEFAULT_TPS_LIMIT_INTERVAL);
String serviceKey = url.getServiceKey();
if (rate > 0) {
StatItem statItem = stats.get(serviceKey);
if (statItem == null) {
stats.putIfAbsent(serviceKey, new StatItem(serviceKey, rate, interval));
statItem = stats.get(serviceKey);
} else {
//rate or interval has changed, rebuild
if (statItem.getRate() != rate || statItem.getInterval() != interval) {
stats.put(serviceKey, new StatItem(serviceKey, rate, interval));
statItem = stats.get(serviceKey);
}
}
return statItem.isAllowable();
} else {
StatItem statItem = stats.get(serviceKey);
if (statItem != null) {
stats.remove(serviceKey);
}
}
return true;
}
}
token
)StatItem
dubbo-2.7.2/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/tps/StatItem.java
class StatItem {
private String name;
private long lastResetTime;
private long interval;
private LongAdder token;
private int rate;
StatItem(String name, int rate, long interval) {
this.name = name;
this.rate = rate;
this.interval = interval;
this.lastResetTime = System.currentTimeMillis();
this.token = buildLongAdder(rate);
}
public boolean isAllowable() {
long now = System.currentTimeMillis();
if (now > lastResetTime + interval) {
token = buildLongAdder(rate);
lastResetTime = now;
}
if (token.sum() < 0) {
return false;
}
token.decrement();
return true;
}
public long getInterval() {
return interval;
}
public int getRate() {
return rate;
}
long getLastResetTime() {
return lastResetTime;
}
long getToken() {
return token.sum();
}
@Override
public String toString() {
return new StringBuilder(32).append("StatItem ")
.append("[name=").append(name).append(", ")
.append("rate = ").append(rate).append(", ")
.append("interval = ").append(interval).append("]")
.toString();
}
private LongAdder buildLongAdder(int rate) {
LongAdder adder = new LongAdder();
adder.add(rate);
return adder;
}
}
token.sum() < 0
でfalseを返し、0以上であればtoken 小結
token
)token.sum() < 0
でfalseを返し、0以上であればtoken doc