You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ratis.apache.org by dr...@apache.org on 2022/08/22 12:12:16 UTC

[ratis] 03/03: RATIS-1638. Separate first election timeout (#713)

This is an automated email from the ASF dual-hosted git repository.

dragonyliu pushed a commit to branch branch-2
in repository https://gitbox.apache.org/repos/asf/ratis.git

commit 87d7d0144ed0d059afa824d44d96d65e0b01075e
Author: William Song <48...@users.noreply.github.com>
AuthorDate: Fri Aug 19 23:18:29 2022 +0800

    RATIS-1638. Separate first election timeout (#713)
    
    
    (cherry picked from commit e49687aba20cad70c576900f1be59bb8fcd55d10)
---
 .../main/java/org/apache/ratis/conf/ConfUtils.java | 14 +++++++-
 .../apache/ratis/server/RaftServerConfigKeys.java  | 39 +++++++++++++++++++---
 .../apache/ratis/server/impl/RaftServerImpl.java   | 17 ++++++++++
 .../org/apache/ratis/server/impl/ServerState.java  |  1 +
 4 files changed, 66 insertions(+), 5 deletions(-)

diff --git a/ratis-common/src/main/java/org/apache/ratis/conf/ConfUtils.java b/ratis-common/src/main/java/org/apache/ratis/conf/ConfUtils.java
index 681c0dc67..629d5a389 100644
--- a/ratis-common/src/main/java/org/apache/ratis/conf/ConfUtils.java
+++ b/ratis-common/src/main/java/org/apache/ratis/conf/ConfUtils.java
@@ -214,6 +214,17 @@ public interface ConfUtils {
     return value;
   }
 
+  @SafeVarargs
+  static TimeDuration getTimeDuration(
+        BiFunction<String, TimeDuration, TimeDuration> getter,
+        String key, TimeDuration defaultValue, String fallbackKey, TimeDuration fallbackValue,
+        Consumer<String> logger, BiConsumer<String, TimeDuration>... assertions) {
+    final TimeDuration value = get(getter, key, defaultValue, fallbackKey, fallbackValue, logger, assertions);
+    requireNonNegativeTimeDuration().accept(key, value);
+    return value;
+  }
+
+
   static TlsConf getTlsConf(
       Function<String, TlsConf> tlsConfGetter,
       String key, Consumer<String> logger) {
@@ -236,10 +247,11 @@ public interface ConfUtils {
     T value = get(getter, key, defaultValue, null, assertions);
     if (value != defaultValue) {
       logGet(key, value, defaultValue, logger);
+      return value;
     } else {
       logFallback(key, fallbackKey, fallbackValue, logger);
+      return fallbackValue;
     }
-    return value;
   }
 
   static InetSocketAddress getInetSocketAddress(
diff --git a/ratis-server-api/src/main/java/org/apache/ratis/server/RaftServerConfigKeys.java b/ratis-server-api/src/main/java/org/apache/ratis/server/RaftServerConfigKeys.java
index 6d0c5d41b..e24631378 100644
--- a/ratis-server-api/src/main/java/org/apache/ratis/server/RaftServerConfigKeys.java
+++ b/ratis-server-api/src/main/java/org/apache/ratis/server/RaftServerConfigKeys.java
@@ -619,9 +619,12 @@ public interface RaftServerConfigKeys {
 
     String TIMEOUT_MIN_KEY = PREFIX + ".timeout.min";
     TimeDuration TIMEOUT_MIN_DEFAULT = TimeDuration.valueOf(150, TimeUnit.MILLISECONDS);
-    static TimeDuration timeoutMin(RaftProperties properties) {
+    static TimeDuration timeoutMin(RaftProperties properties, Consumer<String> logger) {
       return getTimeDuration(properties.getTimeDuration(TIMEOUT_MIN_DEFAULT.getUnit()),
-          TIMEOUT_MIN_KEY, TIMEOUT_MIN_DEFAULT, getDefaultLog());
+          TIMEOUT_MIN_KEY, TIMEOUT_MIN_DEFAULT, logger);
+    }
+    static TimeDuration timeoutMin(RaftProperties properties) {
+      return timeoutMin(properties, getDefaultLog());
     }
     static void setTimeoutMin(RaftProperties properties, TimeDuration minDuration) {
       setTimeDuration(properties::setTimeDuration, TIMEOUT_MIN_KEY, minDuration);
@@ -629,14 +632,42 @@ public interface RaftServerConfigKeys {
 
     String TIMEOUT_MAX_KEY = PREFIX + ".timeout.max";
     TimeDuration TIMEOUT_MAX_DEFAULT = TimeDuration.valueOf(300, TimeUnit.MILLISECONDS);
-    static TimeDuration timeoutMax(RaftProperties properties) {
+    static TimeDuration timeoutMax(RaftProperties properties, Consumer<String> logger) {
       return getTimeDuration(properties.getTimeDuration(TIMEOUT_MAX_DEFAULT.getUnit()),
-          TIMEOUT_MAX_KEY, TIMEOUT_MAX_DEFAULT, getDefaultLog());
+          TIMEOUT_MAX_KEY, TIMEOUT_MAX_DEFAULT, logger);
+    }
+    static TimeDuration timeoutMax(RaftProperties properties) {
+      return timeoutMax(properties, getDefaultLog());
     }
     static void setTimeoutMax(RaftProperties properties, TimeDuration maxDuration) {
       setTimeDuration(properties::setTimeDuration, TIMEOUT_MAX_KEY, maxDuration);
     }
 
+    /** separate first timeout so that the startup unavailable time can be reduced */
+    String FIRST_ELECTION_TIMEOUT_MIN_KEY = PREFIX + ".first-election.timeout.min";
+    TimeDuration FIRST_ELECTION_TIMEOUT_MIN_DEFAULT = null;
+    static TimeDuration firstElectionTimeoutMin(RaftProperties properties) {
+      final TimeDuration fallbackFirstElectionTimeoutMin = Rpc.timeoutMin(properties, null);
+      return getTimeDuration(properties.getTimeDuration(fallbackFirstElectionTimeoutMin.getUnit()),
+          FIRST_ELECTION_TIMEOUT_MIN_KEY, FIRST_ELECTION_TIMEOUT_MIN_DEFAULT,
+          Rpc.TIMEOUT_MIN_KEY, fallbackFirstElectionTimeoutMin, getDefaultLog());
+    }
+    static void setFirstElectionTimeoutMin(RaftProperties properties, TimeDuration firstMinDuration) {
+      setTimeDuration(properties::setTimeDuration, FIRST_ELECTION_TIMEOUT_MIN_KEY, firstMinDuration);
+    }
+
+    String FIRST_ELECTION_TIMEOUT_MAX_KEY = PREFIX + ".first-election.timeout.max";
+    TimeDuration FIRST_ELECTION_TIMEOUT_MAX_DEFAULT = null;
+    static TimeDuration firstElectionTimeoutMax(RaftProperties properties) {
+      final TimeDuration fallbackFirstElectionTimeoutMax = Rpc.timeoutMax(properties, null);
+      return getTimeDuration(properties.getTimeDuration(fallbackFirstElectionTimeoutMax.getUnit()),
+          FIRST_ELECTION_TIMEOUT_MAX_KEY, FIRST_ELECTION_TIMEOUT_MAX_DEFAULT,
+          Rpc.TIMEOUT_MAX_KEY, fallbackFirstElectionTimeoutMax, getDefaultLog());
+    }
+    static void setFirstElectionTimeoutMax(RaftProperties properties, TimeDuration firstMaxDuration) {
+      setTimeDuration(properties::setTimeDuration, FIRST_ELECTION_TIMEOUT_MAX_KEY, firstMaxDuration);
+    }
+
     String REQUEST_TIMEOUT_KEY = PREFIX + ".request.timeout";
     TimeDuration REQUEST_TIMEOUT_DEFAULT = TimeDuration.valueOf(3000, TimeUnit.MILLISECONDS);
     static TimeDuration requestTimeout(RaftProperties properties) {
diff --git a/ratis-server/src/main/java/org/apache/ratis/server/impl/RaftServerImpl.java b/ratis-server/src/main/java/org/apache/ratis/server/impl/RaftServerImpl.java
index ee314dbe2..1994fa8de 100644
--- a/ratis-server/src/main/java/org/apache/ratis/server/impl/RaftServerImpl.java
+++ b/ratis-server/src/main/java/org/apache/ratis/server/impl/RaftServerImpl.java
@@ -187,6 +187,8 @@ class RaftServerImpl implements RaftServer.Division,
   private final ExecutorService serverExecutor;
   private final ExecutorService clientExecutor;
 
+  private final AtomicBoolean firstElectionSinceStartup = new AtomicBoolean(true);
+
   RaftServerImpl(RaftGroup group, StateMachine stateMachine, RaftServerProxy proxy) throws IOException {
     final RaftPeerId id = proxy.getId();
     LOG.info("{}: new RaftServerImpl for {} with {}", id, group, stateMachine);
@@ -245,11 +247,22 @@ class RaftServerImpl implements RaftServer.Division,
   }
 
   TimeDuration getRandomElectionTimeout() {
+    if (firstElectionSinceStartup.get()) {
+      return getFirstRandomElectionTimeout();
+    }
     final int min = properties().minRpcTimeoutMs();
     final int millis = min + ThreadLocalRandom.current().nextInt(properties().maxRpcTimeoutMs() - min + 1);
     return TimeDuration.valueOf(millis, TimeUnit.MILLISECONDS);
   }
 
+  private TimeDuration getFirstRandomElectionTimeout() {
+    final RaftProperties properties = proxy.getProperties();
+    final int min = RaftServerConfigKeys.Rpc.firstElectionTimeoutMin(properties).toIntExact(TimeUnit.MILLISECONDS);
+    final int max = RaftServerConfigKeys.Rpc.firstElectionTimeoutMax(properties).toIntExact(TimeUnit.MILLISECONDS);
+    final int mills = min + ThreadLocalRandom.current().nextInt(max - min + 1);
+    return TimeDuration.valueOf(mills, TimeUnit.MILLISECONDS);
+  }
+
   TimeDuration getLeaderStepDownWaitTime() {
     return leaderStepDownWaitTime;
   }
@@ -1725,4 +1738,8 @@ class RaftServerImpl implements RaftServer.Division,
           .collect(Collectors.toList());
     }
   }
+
+  void onGroupLeaderElected() {
+    this.firstElectionSinceStartup.set(false);
+  }
 }
diff --git a/ratis-server/src/main/java/org/apache/ratis/server/impl/ServerState.java b/ratis-server/src/main/java/org/apache/ratis/server/impl/ServerState.java
index 34e9cb92c..1ee2cab5e 100644
--- a/ratis-server/src/main/java/org/apache/ratis/server/impl/ServerState.java
+++ b/ratis-server/src/main/java/org/apache/ratis/server/impl/ServerState.java
@@ -315,6 +315,7 @@ class ServerState implements Closeable {
       leaderId = newLeaderId;
       if (leaderId != null) {
         server.finishTransferLeadership();
+        server.onGroupLeaderElected();
       }
     }
   }