From 770c252549d6a22dd682f1d051b2b4ac4d31be53 Mon Sep 17 00:00:00 2001 From: xiuyuhang <442367943@qq.com> Date: Tue, 22 Jan 2019 11:17:51 +0800 Subject: [PATCH 1/4] Optimize heartbeat. We should cancel the timeout when the client or server is close. --- .../support/header/HeaderExchangeClient.java | 24 ++++++++++++++++--- .../support/header/HeaderExchangeServer.java | 24 +++++++++++++++++-- 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeClient.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeClient.java index a28d53ec51a..5feb1058abb 100644 --- a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeClient.java +++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeClient.java @@ -19,7 +19,9 @@ import org.apache.dubbo.common.Constants; import org.apache.dubbo.common.URL; import org.apache.dubbo.common.timer.HashedWheelTimer; +import org.apache.dubbo.common.timer.Timeout; import org.apache.dubbo.common.utils.Assert; +import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.common.utils.NamedThreadFactory; import org.apache.dubbo.remoting.ChannelHandler; import org.apache.dubbo.remoting.Client; @@ -30,7 +32,11 @@ import org.apache.dubbo.remoting.exchange.ResponseFuture; import java.net.InetSocketAddress; +import java.util.ArrayList; import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; /** @@ -43,9 +49,11 @@ public class HeaderExchangeClient implements ExchangeClient { private int heartbeat; private int idleTimeout; - private static HashedWheelTimer idleCheckTimer = new HashedWheelTimer(new NamedThreadFactory("dubbo-client-idleCheck", true), 1, + private static final HashedWheelTimer IDLE_CHECK_TIMER = new HashedWheelTimer(new NamedThreadFactory("dubbo-client-idleCheck", true), 1, TimeUnit.SECONDS, Constants.TICKS_PER_WHEEL); + private static final Map> CLIENT_TASKS = new ConcurrentHashMap<>(); + public HeaderExchangeClient(Client client, boolean needHeartbeat) { Assert.notNull(client, "Client can't be null"); this.client = client; @@ -183,11 +191,21 @@ private void startIdleCheckTask() { ReconnectTimerTask reconnectTimerTask = new ReconnectTimerTask(cp, heartbeatTimeoutTick, idleTimeout); // init task and start timer. - idleCheckTimer.newTimeout(heartBeatTimerTask, heartbeatTick, TimeUnit.MILLISECONDS); - idleCheckTimer.newTimeout(reconnectTimerTask, heartbeatTimeoutTick, TimeUnit.MILLISECONDS); + Timeout heartBeatTimeout = IDLE_CHECK_TIMER.newTimeout(heartBeatTimerTask, heartbeatTick, TimeUnit.MILLISECONDS); + Timeout reconnectTimeout = IDLE_CHECK_TIMER.newTimeout(reconnectTimerTask, heartbeatTimeoutTick, TimeUnit.MILLISECONDS); + + List t = CLIENT_TASKS.computeIfAbsent(this, c -> new ArrayList<>()); + t.add(heartBeatTimeout); + t.add(reconnectTimeout); } private void doClose() { + List t = CLIENT_TASKS.remove(this); + if (CollectionUtils.isNotEmpty(t)) { + for (Timeout timeout : t) { + timeout.cancel(); + } + } } /** diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeServer.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeServer.java index 4609d2ab529..21472101855 100644 --- a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeServer.java +++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeServer.java @@ -22,6 +22,7 @@ import org.apache.dubbo.common.logger.Logger; import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.common.timer.HashedWheelTimer; +import org.apache.dubbo.common.timer.Timeout; import org.apache.dubbo.common.utils.Assert; import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.common.utils.NamedThreadFactory; @@ -36,6 +37,9 @@ import java.net.InetSocketAddress; import java.util.ArrayList; import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; @@ -53,9 +57,11 @@ public class HeaderExchangeServer implements ExchangeServer { private int idleTimeout; private AtomicBoolean closed = new AtomicBoolean(false); - private static HashedWheelTimer idleCheckTimer = new HashedWheelTimer(new NamedThreadFactory("dubbo-server-idleCheck", true), 1, + private static final HashedWheelTimer IDLE_CHECK_TIMER = new HashedWheelTimer(new NamedThreadFactory("dubbo-server-idleCheck", true), 1, TimeUnit.SECONDS, Constants.TICKS_PER_WHEEL); + private static final Map> SERVER_TASKS = new ConcurrentHashMap<>(); + public HeaderExchangeServer(Server server) { Assert.notNull(server, "server == null"); this.server = server; @@ -148,6 +154,16 @@ private void doClose() { if (!closed.compareAndSet(false, true)) { return; } + cancelCloseTimeout(); + } + + private void cancelCloseTimeout() { + List t = SERVER_TASKS.remove(this); + if (CollectionUtils.isNotEmpty(t)) { + for (Timeout timeout : t) { + timeout.cancel(); + } + } } @Override @@ -214,6 +230,8 @@ public void reset(URL url) { heartbeat = h; idleTimeout = t; + // we need cancel the exist closeTimeout first. + cancelCloseTimeout(); startIdleCheckTask(); } } @@ -264,7 +282,9 @@ private void startIdleCheckTask() { CloseTimerTask closeTimerTask = new CloseTimerTask(cp, idleTimeoutTick, idleTimeout); // init task and start timer. - idleCheckTimer.newTimeout(closeTimerTask, idleTimeoutTick, TimeUnit.MILLISECONDS); + Timeout closeTimeout = IDLE_CHECK_TIMER.newTimeout(closeTimerTask, idleTimeoutTick, TimeUnit.MILLISECONDS); + List t = SERVER_TASKS.computeIfAbsent(this, s -> new ArrayList<>()); + t.add(closeTimeout); } } From e2e550096a859a1496abe489f6e98c49418390b4 Mon Sep 17 00:00:00 2001 From: xiuyuhang <442367943@qq.com> Date: Tue, 22 Jan 2019 11:21:54 +0800 Subject: [PATCH 2/4] change the hashedWheelTimer's ticks --- .../src/main/java/org/apache/dubbo/common/Constants.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/Constants.java b/dubbo-common/src/main/java/org/apache/dubbo/common/Constants.java index b0df6360c07..ab0b09f59a8 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/Constants.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/Constants.java @@ -296,9 +296,9 @@ public class Constants { public static final long LEAST_HEARTBEAT_DURATION = 1000; /** - * ticks per wheel. Currently only contains two tasks, so 16 locations are enough + * ticks per wheel. */ - public static final int TICKS_PER_WHEEL = 16; + public static final int TICKS_PER_WHEEL = 128; public static final String HEARTBEAT_TIMEOUT_KEY = "heartbeat.timeout"; From 9cb5f96a5fe3f7df1daa9cba6b15e17d406949f7 Mon Sep 17 00:00:00 2001 From: xiuyuhang <442367943@qq.com> Date: Tue, 22 Jan 2019 14:53:11 +0800 Subject: [PATCH 3/4] Optimize tasks keeper. --- .../support/header/HeaderExchangeClient.java | 15 ++++++--------- .../support/header/HeaderExchangeServer.java | 13 +++++-------- 2 files changed, 11 insertions(+), 17 deletions(-) diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeClient.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeClient.java index 5feb1058abb..f2cd39ec167 100644 --- a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeClient.java +++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeClient.java @@ -35,8 +35,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; /** @@ -52,7 +50,7 @@ public class HeaderExchangeClient implements ExchangeClient { private static final HashedWheelTimer IDLE_CHECK_TIMER = new HashedWheelTimer(new NamedThreadFactory("dubbo-client-idleCheck", true), 1, TimeUnit.SECONDS, Constants.TICKS_PER_WHEEL); - private static final Map> CLIENT_TASKS = new ConcurrentHashMap<>(); + private List tasks = new ArrayList<>(); public HeaderExchangeClient(Client client, boolean needHeartbeat) { Assert.notNull(client, "Client can't be null"); @@ -194,17 +192,16 @@ private void startIdleCheckTask() { Timeout heartBeatTimeout = IDLE_CHECK_TIMER.newTimeout(heartBeatTimerTask, heartbeatTick, TimeUnit.MILLISECONDS); Timeout reconnectTimeout = IDLE_CHECK_TIMER.newTimeout(reconnectTimerTask, heartbeatTimeoutTick, TimeUnit.MILLISECONDS); - List t = CLIENT_TASKS.computeIfAbsent(this, c -> new ArrayList<>()); - t.add(heartBeatTimeout); - t.add(reconnectTimeout); + tasks.add(heartBeatTimeout); + tasks.add(reconnectTimeout); } private void doClose() { - List t = CLIENT_TASKS.remove(this); - if (CollectionUtils.isNotEmpty(t)) { - for (Timeout timeout : t) { + if (CollectionUtils.isNotEmpty(tasks)) { + for (Timeout timeout : tasks) { timeout.cancel(); } + tasks.clear(); } } diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeServer.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeServer.java index 21472101855..27df2eacb64 100644 --- a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeServer.java +++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeServer.java @@ -38,8 +38,6 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; @@ -60,7 +58,7 @@ public class HeaderExchangeServer implements ExchangeServer { private static final HashedWheelTimer IDLE_CHECK_TIMER = new HashedWheelTimer(new NamedThreadFactory("dubbo-server-idleCheck", true), 1, TimeUnit.SECONDS, Constants.TICKS_PER_WHEEL); - private static final Map> SERVER_TASKS = new ConcurrentHashMap<>(); + private List tasks = new ArrayList<>(); public HeaderExchangeServer(Server server) { Assert.notNull(server, "server == null"); @@ -158,11 +156,11 @@ private void doClose() { } private void cancelCloseTimeout() { - List t = SERVER_TASKS.remove(this); - if (CollectionUtils.isNotEmpty(t)) { - for (Timeout timeout : t) { + if (CollectionUtils.isNotEmpty(tasks)) { + for (Timeout timeout : tasks) { timeout.cancel(); } + tasks.clear(); } } @@ -283,8 +281,7 @@ private void startIdleCheckTask() { // init task and start timer. Timeout closeTimeout = IDLE_CHECK_TIMER.newTimeout(closeTimerTask, idleTimeoutTick, TimeUnit.MILLISECONDS); - List t = SERVER_TASKS.computeIfAbsent(this, s -> new ArrayList<>()); - t.add(closeTimeout); + tasks.add(closeTimeout); } } From 2393ea120e3f5c9c021a00e2e02ba01e03d5acce Mon Sep 17 00:00:00 2001 From: xiuyuhang <442367943@qq.com> Date: Wed, 23 Jan 2019 10:33:00 +0800 Subject: [PATCH 4/4] fix timeout cancel to task cancel. keep task directly. --- .../support/header/AbstractTimerTask.java | 10 +++++++ .../support/header/HeaderExchangeClient.java | 26 +++++++------------ .../support/header/HeaderExchangeServer.java | 21 +++++---------- 3 files changed, 27 insertions(+), 30 deletions(-) diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/AbstractTimerTask.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/AbstractTimerTask.java index 003af243d86..befa6887806 100644 --- a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/AbstractTimerTask.java +++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/AbstractTimerTask.java @@ -34,6 +34,8 @@ public abstract class AbstractTimerTask implements TimerTask { private final Long tick; + protected volatile boolean cancel = false; + AbstractTimerTask(ChannelProvider channelProvider, Long tick) { if (channelProvider == null || tick == null) { throw new IllegalArgumentException(); @@ -54,11 +56,19 @@ static Long now() { return System.currentTimeMillis(); } + public void cancel() { + this.cancel = true; + } + private void reput(Timeout timeout, Long tick) { if (timeout == null || tick == null) { throw new IllegalArgumentException(); } + if (cancel) { + return; + } + Timer timer = timeout.timer(); if (timer.isStop() || timeout.isCancelled()) { return; diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeClient.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeClient.java index f2cd39ec167..65862b6d6af 100644 --- a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeClient.java +++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeClient.java @@ -19,9 +19,7 @@ import org.apache.dubbo.common.Constants; import org.apache.dubbo.common.URL; import org.apache.dubbo.common.timer.HashedWheelTimer; -import org.apache.dubbo.common.timer.Timeout; import org.apache.dubbo.common.utils.Assert; -import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.common.utils.NamedThreadFactory; import org.apache.dubbo.remoting.ChannelHandler; import org.apache.dubbo.remoting.Client; @@ -32,9 +30,7 @@ import org.apache.dubbo.remoting.exchange.ResponseFuture; import java.net.InetSocketAddress; -import java.util.ArrayList; import java.util.Collections; -import java.util.List; import java.util.concurrent.TimeUnit; /** @@ -50,7 +46,9 @@ public class HeaderExchangeClient implements ExchangeClient { private static final HashedWheelTimer IDLE_CHECK_TIMER = new HashedWheelTimer(new NamedThreadFactory("dubbo-client-idleCheck", true), 1, TimeUnit.SECONDS, Constants.TICKS_PER_WHEEL); - private List tasks = new ArrayList<>(); + private HeartbeatTimerTask heartBeatTimerTask; + + private ReconnectTimerTask reconnectTimerTask; public HeaderExchangeClient(Client client, boolean needHeartbeat) { Assert.notNull(client, "Client can't be null"); @@ -188,21 +186,17 @@ private void startIdleCheckTask() { HeartbeatTimerTask heartBeatTimerTask = new HeartbeatTimerTask(cp, heartbeatTick, heartbeat); ReconnectTimerTask reconnectTimerTask = new ReconnectTimerTask(cp, heartbeatTimeoutTick, idleTimeout); - // init task and start timer. - Timeout heartBeatTimeout = IDLE_CHECK_TIMER.newTimeout(heartBeatTimerTask, heartbeatTick, TimeUnit.MILLISECONDS); - Timeout reconnectTimeout = IDLE_CHECK_TIMER.newTimeout(reconnectTimerTask, heartbeatTimeoutTick, TimeUnit.MILLISECONDS); + this.heartBeatTimerTask = heartBeatTimerTask; + this.reconnectTimerTask = reconnectTimerTask; - tasks.add(heartBeatTimeout); - tasks.add(reconnectTimeout); + // init task and start timer. + IDLE_CHECK_TIMER.newTimeout(heartBeatTimerTask, heartbeatTick, TimeUnit.MILLISECONDS); + IDLE_CHECK_TIMER.newTimeout(reconnectTimerTask, heartbeatTimeoutTick, TimeUnit.MILLISECONDS); } private void doClose() { - if (CollectionUtils.isNotEmpty(tasks)) { - for (Timeout timeout : tasks) { - timeout.cancel(); - } - tasks.clear(); - } + heartBeatTimerTask.cancel(); + reconnectTimerTask.cancel(); } /** diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeServer.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeServer.java index 27df2eacb64..65b0836fcc8 100644 --- a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeServer.java +++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeServer.java @@ -22,7 +22,6 @@ import org.apache.dubbo.common.logger.Logger; import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.common.timer.HashedWheelTimer; -import org.apache.dubbo.common.timer.Timeout; import org.apache.dubbo.common.utils.Assert; import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.common.utils.NamedThreadFactory; @@ -37,7 +36,6 @@ import java.net.InetSocketAddress; import java.util.ArrayList; import java.util.Collection; -import java.util.List; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; @@ -58,7 +56,7 @@ public class HeaderExchangeServer implements ExchangeServer { private static final HashedWheelTimer IDLE_CHECK_TIMER = new HashedWheelTimer(new NamedThreadFactory("dubbo-server-idleCheck", true), 1, TimeUnit.SECONDS, Constants.TICKS_PER_WHEEL); - private List tasks = new ArrayList<>(); + private CloseTimerTask closeTimerTask; public HeaderExchangeServer(Server server) { Assert.notNull(server, "server == null"); @@ -152,16 +150,11 @@ private void doClose() { if (!closed.compareAndSet(false, true)) { return; } - cancelCloseTimeout(); + cancelCloseTask(); } - private void cancelCloseTimeout() { - if (CollectionUtils.isNotEmpty(tasks)) { - for (Timeout timeout : tasks) { - timeout.cancel(); - } - tasks.clear(); - } + private void cancelCloseTask() { + closeTimerTask.cancel(); } @Override @@ -229,7 +222,7 @@ public void reset(URL url) { idleTimeout = t; // we need cancel the exist closeTimeout first. - cancelCloseTimeout(); + cancelCloseTask(); startIdleCheckTask(); } } @@ -278,10 +271,10 @@ private void startIdleCheckTask() { long idleTimeoutTick = calculateLeastDuration(idleTimeout); CloseTimerTask closeTimerTask = new CloseTimerTask(cp, idleTimeoutTick, idleTimeout); + this.closeTimerTask = closeTimerTask; // init task and start timer. - Timeout closeTimeout = IDLE_CHECK_TIMER.newTimeout(closeTimerTask, idleTimeoutTick, TimeUnit.MILLISECONDS); - tasks.add(closeTimeout); + IDLE_CHECK_TIMER.newTimeout(closeTimerTask, idleTimeoutTick, TimeUnit.MILLISECONDS); } }