From 4746c93c4279a3ccf7e2e99ed482c1a24afaf6c0 Mon Sep 17 00:00:00 2001 From: lizhen Date: Thu, 14 Mar 2019 15:28:19 +0800 Subject: [PATCH 1/4] optimize DefaultTpsLimiter --- .../rpc/filter/tps/DefaultTPSLimiter.java | 7 +++++ .../apache/dubbo/rpc/filter/tps/StatItem.java | 29 ++++++++++++------- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/tps/DefaultTPSLimiter.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/tps/DefaultTPSLimiter.java index a623e2e6bdf..4dfe3d89843 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/tps/DefaultTPSLimiter.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/tps/DefaultTPSLimiter.java @@ -46,6 +46,13 @@ public boolean isAllowable(URL url, Invocation invocation) { stats.putIfAbsent(serviceKey, new StatItem(serviceKey, rate, interval)); statItem = stats.get(serviceKey); + } else { + //rate has changed, rebuild + if (statItem.getRate() != rate) { + stats.put(serviceKey, + new StatItem(serviceKey, rate, interval)); + statItem = stats.get(serviceKey); + } } return statItem.isAllowable(); } else { diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/tps/StatItem.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/tps/StatItem.java index 2fcdaef82a8..78279b9e5bc 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/tps/StatItem.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/tps/StatItem.java @@ -16,7 +16,7 @@ */ package org.apache.dubbo.rpc.filter.tps; -import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.LongAdder; /** * Judge whether a particular invocation of service provider method should be allowed within a configured time interval. @@ -30,7 +30,7 @@ class StatItem { private long interval; - private AtomicInteger token; + private LongAdder token; private int rate; @@ -39,32 +39,35 @@ class StatItem { this.rate = rate; this.interval = interval; this.lastResetTime = System.currentTimeMillis(); - this.token = new AtomicInteger(rate); + this.token = buildLongAdder(rate); } public boolean isAllowable() { long now = System.currentTimeMillis(); if (now > lastResetTime + interval) { - token.set(rate); + token = buildLongAdder(rate); lastResetTime = now; } - int value = token.get(); boolean flag = false; - while (value > 0 && !flag) { - flag = token.compareAndSet(value, value - 1); - value = token.get(); + while (token.sum() > 0 && !flag) { + token.decrement(); + flag = true; } return flag; } + public int getRate() { + return rate; + } + long getLastResetTime() { return lastResetTime; } - int getToken() { - return token.get(); + long getToken() { + return token.sum(); } @Override @@ -76,4 +79,10 @@ public String toString() { .toString(); } + private LongAdder buildLongAdder(int rate) { + LongAdder adder = new LongAdder(); + adder.add(rate); + return adder; + } + } From 0de91a0bc2e5b38a189eb5a28233b3a96163fcd5 Mon Sep 17 00:00:00 2001 From: LiZhen Date: Thu, 14 Mar 2019 15:50:32 +0800 Subject: [PATCH 2/4] Update StatItem.java --- .../src/main/java/org/apache/dubbo/rpc/filter/tps/StatItem.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/tps/StatItem.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/tps/StatItem.java index 78279b9e5bc..3ad63703032 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/tps/StatItem.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/tps/StatItem.java @@ -50,7 +50,7 @@ public boolean isAllowable() { } boolean flag = false; - while (token.sum() > 0 && !flag) { + while (getToken() > 0 && !flag) { token.decrement(); flag = true; } From abecfa1770fcf993c6784e14d3ed6486696d2a6a Mon Sep 17 00:00:00 2001 From: lizhen Date: Tue, 19 Mar 2019 18:02:16 +0800 Subject: [PATCH 3/4] add DefaultTpsTest --- .../rpc/filter/tps/DefaultTPSLimiter.java | 16 ++--- .../apache/dubbo/rpc/filter/tps/StatItem.java | 14 +++-- .../rpc/filter/tps/DefaultTPSLimiterTest.java | 63 +++++++++++++++++++ .../filter/{ => tps}/TpsLimitFilterTest.java | 3 +- 4 files changed, 80 insertions(+), 16 deletions(-) create mode 100644 dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/filter/tps/DefaultTPSLimiterTest.java rename dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/filter/{ => tps}/TpsLimitFilterTest.java (96%) diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/tps/DefaultTPSLimiter.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/tps/DefaultTPSLimiter.java index 4dfe3d89843..65985bbf603 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/tps/DefaultTPSLimiter.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/tps/DefaultTPSLimiter.java @@ -31,26 +31,22 @@ */ public class DefaultTPSLimiter implements TPSLimiter { - private final ConcurrentMap stats - = new ConcurrentHashMap(); + private final ConcurrentMap stats = new ConcurrentHashMap(); @Override public boolean isAllowable(URL url, Invocation invocation) { int rate = url.getParameter(Constants.TPS_LIMIT_RATE_KEY, -1); - long interval = url.getParameter(Constants.TPS_LIMIT_INTERVAL_KEY, - Constants.DEFAULT_TPS_LIMIT_INTERVAL); + long interval = url.getParameter(Constants.TPS_LIMIT_INTERVAL_KEY, Constants.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)); + stats.putIfAbsent(serviceKey, new StatItem(serviceKey, rate, interval)); statItem = stats.get(serviceKey); } else { - //rate has changed, rebuild - if (statItem.getRate() != rate) { - stats.put(serviceKey, - new StatItem(serviceKey, rate, interval)); + //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); } } diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/tps/StatItem.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/tps/StatItem.java index 3ad63703032..9fb3fab7d91 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/tps/StatItem.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/tps/StatItem.java @@ -49,19 +49,23 @@ public boolean isAllowable() { lastResetTime = now; } - boolean flag = false; - while (getToken() > 0 && !flag) { - token.decrement(); - flag = true; + if (token.sum() < 0) { + return false; } + token.decrement(); + return true; + } - return flag; + public long getInterval() { + return interval; } + public int getRate() { return rate; } + long getLastResetTime() { return lastResetTime; } diff --git a/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/filter/tps/DefaultTPSLimiterTest.java b/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/filter/tps/DefaultTPSLimiterTest.java new file mode 100644 index 00000000000..46fb20c5b0e --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/filter/tps/DefaultTPSLimiterTest.java @@ -0,0 +1,63 @@ +package org.apache.dubbo.rpc.filter.tps; + +import org.apache.dubbo.common.Constants; +import org.apache.dubbo.common.URL; +import org.apache.dubbo.rpc.Invocation; +import org.apache.dubbo.rpc.support.MockInvocation; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +/** + * @author: lizhen + * @since: 2019-03-19 + * @description: + */ +public class DefaultTPSLimiterTest { + + private DefaultTPSLimiter defaultTPSLimiter = new DefaultTPSLimiter(); + + @Test + public void testIsAllowable() throws Exception { + Invocation invocation = new MockInvocation(); + URL url = URL.valueOf("test://test"); + url = url.addParameter(Constants.INTERFACE_KEY, "org.apache.dubbo.rpc.file.TpsService"); + url = url.addParameter(Constants.TPS_LIMIT_RATE_KEY, 2); + url = url.addParameter(Constants.TPS_LIMIT_INTERVAL_KEY, 1000); + for (int i = 0; i < 3; i++) { + Assertions.assertTrue(defaultTPSLimiter.isAllowable(url, invocation)); + } + } + + @Test + public void testIsNotAllowable() throws Exception { + Invocation invocation = new MockInvocation(); + URL url = URL.valueOf("test://test"); + url = url.addParameter(Constants.INTERFACE_KEY, "org.apache.dubbo.rpc.file.TpsService"); + url = url.addParameter(Constants.TPS_LIMIT_RATE_KEY, 2); + url = url.addParameter(Constants.TPS_LIMIT_INTERVAL_KEY, 1000); + for (int i = 0; i < 4; i++) { + if (i == 3) { + Assertions.assertFalse(defaultTPSLimiter.isAllowable(url, invocation)); + } else { + Assertions.assertTrue(defaultTPSLimiter.isAllowable(url, invocation)); + } + } + } + + + @Test + public void testConfigChange() throws Exception { + Invocation invocation = new MockInvocation(); + URL url = URL.valueOf("test://test"); + url = url.addParameter(Constants.INTERFACE_KEY, "org.apache.dubbo.rpc.file.TpsService"); + url = url.addParameter(Constants.TPS_LIMIT_RATE_KEY, 2); + url = url.addParameter(Constants.TPS_LIMIT_INTERVAL_KEY, 1000); + for (int i = 0; i < 3; i++) { + Assertions.assertTrue(defaultTPSLimiter.isAllowable(url, invocation)); + } + url = url.addParameter(Constants.TPS_LIMIT_RATE_KEY, 2000); + for (int i = 0; i < 3; i++) { + Assertions.assertTrue(defaultTPSLimiter.isAllowable(url, invocation)); + } + } +} diff --git a/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/filter/TpsLimitFilterTest.java b/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/filter/tps/TpsLimitFilterTest.java similarity index 96% rename from dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/filter/TpsLimitFilterTest.java rename to dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/filter/tps/TpsLimitFilterTest.java index e5ac973d3b5..235eeddd6e2 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/filter/TpsLimitFilterTest.java +++ b/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/filter/tps/TpsLimitFilterTest.java @@ -14,13 +14,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.rpc.filter; +package org.apache.dubbo.rpc.filter.tps; import org.apache.dubbo.common.Constants; import org.apache.dubbo.common.URL; import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.RpcException; +import org.apache.dubbo.rpc.filter.TpsLimitFilter; import org.apache.dubbo.rpc.support.MockInvocation; import org.apache.dubbo.rpc.support.MyInvoker; From c3f2f197681b450c35e89bcd70f0bda0cc1df0c5 Mon Sep 17 00:00:00 2001 From: lizhen Date: Tue, 19 Mar 2019 18:42:21 +0800 Subject: [PATCH 4/4] add license --- .../rpc/filter/tps/DefaultTPSLimiterTest.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/filter/tps/DefaultTPSLimiterTest.java b/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/filter/tps/DefaultTPSLimiterTest.java index 46fb20c5b0e..7852e42e8dc 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/filter/tps/DefaultTPSLimiterTest.java +++ b/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/filter/tps/DefaultTPSLimiterTest.java @@ -1,3 +1,19 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.apache.dubbo.rpc.filter.tps; import org.apache.dubbo.common.Constants;