This is an automated email from the ASF dual-hosted git repository.
tanxinyu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iotdb.git
The following commit(s) were added to refs/heads/master by this push:
new 660fc05f31 [IOTDB-2998] Pooling RatisConsensus Raft client (#5683)
660fc05f31 is described below
commit 660fc05f31d228ff43220c24cd630b587bc7f680
Author: SzyWilliam <[email protected]>
AuthorDate: Wed Apr 27 17:33:54 2022 +0800
[IOTDB-2998] Pooling RatisConsensus Raft client (#5683)
* initial commit
* pooling raft client
* returnSelf call
* add clean logic
---
.../apache/iotdb/consensus/ratis/RatisClient.java | 107 +++++++++++++++++++++
.../iotdb/consensus/ratis/RatisClientFactory.java | 67 -------------
.../iotdb/consensus/ratis/RatisConsensus.java | 93 +++++++++---------
.../iotdb/consensus/ratis/RatisConsensusTest.java | 2 +-
4 files changed, 156 insertions(+), 113 deletions(-)
diff --git
a/consensus/src/main/java/org/apache/iotdb/consensus/ratis/RatisClient.java
b/consensus/src/main/java/org/apache/iotdb/consensus/ratis/RatisClient.java
new file mode 100644
index 0000000000..8e27109533
--- /dev/null
+++ b/consensus/src/main/java/org/apache/iotdb/consensus/ratis/RatisClient.java
@@ -0,0 +1,107 @@
+/*
+ * 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.iotdb.consensus.ratis;
+
+import org.apache.iotdb.commons.client.BaseClientFactory;
+import org.apache.iotdb.commons.client.ClientFactoryProperty;
+import org.apache.iotdb.commons.client.ClientManager;
+
+import org.apache.commons.pool2.PooledObject;
+import org.apache.commons.pool2.impl.DefaultPooledObject;
+import org.apache.ratis.client.RaftClient;
+import org.apache.ratis.client.RaftClientRpc;
+import org.apache.ratis.conf.RaftProperties;
+import org.apache.ratis.protocol.RaftGroup;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+
+public class RatisClient {
+ private final Logger logger = LoggerFactory.getLogger(RatisClient.class);
+ private final RaftGroup serveGroup;
+ private final RaftClient raftClient;
+ private final ClientManager<RaftGroup, RatisClient> clientManager;
+
+ public RatisClient(
+ RaftGroup serveGroup,
+ RaftClient client,
+ ClientManager<RaftGroup, RatisClient> clientManager) {
+ this.serveGroup = serveGroup;
+ this.raftClient = client;
+ this.clientManager = clientManager;
+ }
+
+ public RaftClient getRaftClient() {
+ return raftClient;
+ }
+
+ public void close() {
+ try {
+ raftClient.close();
+ } catch (IOException e) {
+ logger.warn("cannot close raft client ", e);
+ }
+ }
+
+ public void returnSelf() {
+ if (clientManager != null) {
+ clientManager.returnClient(serveGroup, this);
+ }
+ }
+
+ public static class Factory extends BaseClientFactory<RaftGroup,
RatisClient> {
+
+ private final RaftProperties raftProperties;
+ private final RaftClientRpc clientRpc;
+
+ public Factory(
+ ClientManager<RaftGroup, RatisClient> clientManager,
+ ClientFactoryProperty clientPoolProperty,
+ RaftProperties raftProperties,
+ RaftClientRpc clientRpc) {
+ super(clientManager, clientPoolProperty);
+ this.raftProperties = raftProperties;
+ this.clientRpc = clientRpc;
+ }
+
+ @Override
+ public void destroyObject(RaftGroup key, PooledObject<RatisClient>
pooledObject) {
+ pooledObject.getObject().close();
+ }
+
+ @Override
+ public PooledObject<RatisClient> makeObject(RaftGroup group) throws
Exception {
+ return new DefaultPooledObject<>(
+ new RatisClient(
+ group,
+ RaftClient.newBuilder()
+ .setProperties(raftProperties)
+ .setRaftGroup(group)
+ .setClientRpc(clientRpc)
+ .build(),
+ clientManager));
+ }
+
+ @Override
+ public boolean validateObject(RaftGroup key, PooledObject<RatisClient>
pooledObject) {
+ return true;
+ }
+ }
+}
diff --git
a/consensus/src/main/java/org/apache/iotdb/consensus/ratis/RatisClientFactory.java
b/consensus/src/main/java/org/apache/iotdb/consensus/ratis/RatisClientFactory.java
deleted file mode 100644
index 9164e91afa..0000000000
---
a/consensus/src/main/java/org/apache/iotdb/consensus/ratis/RatisClientFactory.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * 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.iotdb.consensus.ratis;
-
-import org.apache.iotdb.commons.client.BaseClientFactory;
-import org.apache.iotdb.commons.client.ClientFactoryProperty;
-import org.apache.iotdb.commons.client.ClientManager;
-
-import org.apache.commons.pool2.PooledObject;
-import org.apache.commons.pool2.impl.DefaultPooledObject;
-import org.apache.ratis.client.RaftClient;
-import org.apache.ratis.client.RaftClientRpc;
-import org.apache.ratis.conf.RaftProperties;
-import org.apache.ratis.protocol.RaftGroup;
-
-public class RatisClientFactory extends BaseClientFactory<RaftGroup,
RaftClient> {
-
- private final RaftProperties raftProperties;
- private final RaftClientRpc clientRpc;
-
- public RatisClientFactory(
- ClientManager<RaftGroup, RaftClient> clientManager,
- ClientFactoryProperty clientPoolProperty,
- RaftProperties raftProperties,
- RaftClientRpc clientRpc) {
- super(clientManager, clientPoolProperty);
- this.raftProperties = raftProperties;
- this.clientRpc = clientRpc;
- }
-
- @Override
- public void destroyObject(RaftGroup key, PooledObject<RaftClient>
pooledObject) throws Exception {
- pooledObject.getObject().close();
- }
-
- @Override
- public PooledObject<RaftClient> makeObject(RaftGroup group) throws Exception
{
- return new DefaultPooledObject<>(
- RaftClient.newBuilder()
- .setProperties(raftProperties)
- .setRaftGroup(group)
- .setClientRpc(clientRpc)
- .build());
- }
-
- @Override
- public boolean validateObject(RaftGroup key, PooledObject<RaftClient>
pooledObject) {
- return true;
- }
-}
diff --git
a/consensus/src/main/java/org/apache/iotdb/consensus/ratis/RatisConsensus.java
b/consensus/src/main/java/org/apache/iotdb/consensus/ratis/RatisConsensus.java
index 0e4e368f03..d022f096cc 100644
---
a/consensus/src/main/java/org/apache/iotdb/consensus/ratis/RatisConsensus.java
+++
b/consensus/src/main/java/org/apache/iotdb/consensus/ratis/RatisConsensus.java
@@ -69,6 +69,8 @@ import java.io.IOException;
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.atomic.AtomicLong;
import java.util.stream.Collectors;
@@ -88,10 +90,12 @@ class RatisConsensus implements IConsensus {
private final RaftProperties properties = new RaftProperties();
private final RaftClientRpc clientRpc;
- private final IClientManager<RaftGroup, RaftClient> clientManager =
- new IClientManager.Factory<RaftGroup, RaftClient>()
+ private final IClientManager<RaftGroup, RatisClient> clientManager =
+ new IClientManager.Factory<RaftGroup, RatisClient>()
.createClientManager(new RatisClientPoolFactory());
+ private Map<RaftGroupId, RaftGroup> lastSeen;
+
private final ClientId localFakeId = ClientId.randomId();
private final AtomicLong localFakeCallId = new AtomicLong(0);
@@ -104,6 +108,8 @@ class RatisConsensus implements IConsensus {
*/
public RatisConsensus(TEndPoint endpoint, File ratisStorageDir,
IStateMachine.Registry registry)
throws IOException {
+ lastSeen = new ConcurrentHashMap<>();
+
// create a RaftPeer as endpoint of comm
String address = Utils.IPAddress(endpoint);
myself = Utils.toRaftPeer(endpoint, DEFAULT_PRIORITY);
@@ -178,13 +184,12 @@ class RatisConsensus implements IConsensus {
}
// 2. try raft client
- RaftClient client = null;
TSStatus writeResult;
try {
- client = buildClient(raftGroup);
- RaftClientReply reply = client.io().send(message);
+ RatisClient client = getRaftClient(raftGroup);
+ RaftClientReply reply = client.getRaftClient().io().send(message);
writeResult =
Utils.deserializeFrom(reply.getMessage().getContent().asReadOnlyByteBuffer());
- client.close();
+ client.returnSelf();
} catch (IOException | TException e) {
return failedWrite(new RatisRequestFailedException(e));
}
@@ -240,14 +245,12 @@ class RatisConsensus implements IConsensus {
return failed(new ConsensusGroupNotExistException(groupId));
}
- // build and store the corresponding client
- RaftClient client = buildClient(group);
-
// add RaftPeer myself to this RaftGroup
RaftClientReply reply;
try {
- reply = client.getGroupManagementApi(myself.getId()).add(group);
- client.close();
+ RatisClient client = getRaftClient(group);
+ reply =
client.getRaftClient().getGroupManagementApi(myself.getId()).add(group);
+ client.returnSelf();
} catch (IOException e) {
return failed(new RatisRequestFailedException(e));
}
@@ -272,13 +275,16 @@ class RatisConsensus implements IConsensus {
return failed(new PeerNotInConsensusGroupException(groupId, myself));
}
- RaftClient client;
// send remove group to myself
RaftClientReply reply;
try {
- client = buildClient(raftGroup);
- reply = client.getGroupManagementApi(myself.getId()).remove(raftGroupId,
false, false);
- client.close();
+ RatisClient client = getRaftClient(raftGroup);
+ reply =
+ client
+ .getRaftClient()
+ .getGroupManagementApi(myself.getId())
+ .remove(raftGroupId, false, false);
+ client.returnSelf();
} catch (IOException e) {
return failed(new RatisRequestFailedException(e));
}
@@ -367,9 +373,6 @@ class RatisConsensus implements IConsensus {
return failed(new ConsensusGroupNotExistException(groupId));
}
- // build the client and store it
- buildClient(raftGroup);
-
// add RaftPeer myself to this RaftGroup
RaftClientReply reply;
try {
@@ -380,6 +383,10 @@ class RatisConsensus implements IConsensus {
return
ConsensusGenericResponse.newBuilder().setSuccess(reply.isSuccess()).build();
}
+ /**
+ * transferLeader in Ratis implementation is not guaranteed to transfer
leadership to the
+ * designated peer Thus, it may produce undetermined results. Caller should
not count on this API.
+ */
@Override
public ConsensusGenericResponse transferLeader(ConsensusGroupId groupId,
Peer newLeader) {
// By default, Ratis gives every Raft Peer same priority 0
@@ -407,16 +414,17 @@ class RatisConsensus implements IConsensus {
}
}
- RaftClient client = buildClient(raftGroup);
RaftClientReply reply = null;
try {
- RaftClientReply configChangeReply =
client.admin().setConfiguration(newConfiguration);
+ RatisClient client = getRaftClient(raftGroup);
+ RaftClientReply configChangeReply =
+ client.getRaftClient().admin().setConfiguration(newConfiguration);
if (!configChangeReply.isSuccess()) {
return failed(new
RatisRequestFailedException(configChangeReply.getException()));
}
// TODO tuning for timeoutMs
- reply = client.admin().transferLeadership(newRaftLeader.getId(), 2000);
- client.close();
+ reply =
client.getRaftClient().admin().transferLeadership(newRaftLeader.getId(), 2000);
+ client.returnSelf();
} catch (IOException e) {
return failed(new RatisRequestFailedException(e));
}
@@ -489,6 +497,12 @@ class RatisConsensus implements IConsensus {
RaftGroup raftGroup = null;
try {
raftGroup = server.getDivision(raftGroupId).getGroup();
+ RaftGroup lastSeenGroup = lastSeen.getOrDefault(raftGroupId, null);
+ if (lastSeenGroup != null && !lastSeenGroup.equals(raftGroup)) {
+ // delete the pooled raft-client of the out-dated group and cache the
latest
+ clientManager.clear(lastSeenGroup);
+ lastSeen.put(raftGroupId, raftGroup);
+ }
} catch (IOException e) {
logger.debug("get group failed ", e);
}
@@ -503,50 +517,39 @@ class RatisConsensus implements IConsensus {
return RaftGroup.valueOf(Utils.toRatisGroupId(groupId), raftPeers);
}
- private RaftClient buildClient(RaftGroup group) {
- RaftProperties raftProperties = new RaftProperties();
- RaftClient.Builder builder =
- RaftClient.newBuilder()
- .setProperties(raftProperties)
- .setRaftGroup(group)
- .setClientRpc(
- new GrpcFactory(new Parameters())
- .newRaftClientRpc(ClientId.randomId(), raftProperties));
- return builder.build();
- }
-
- // TODO use this function to get RaftClient
- private RaftClient getRaftClient(RaftGroup group) {
+ private RatisClient getRaftClient(RaftGroup group) throws IOException {
try {
return clientManager.borrowClient(group);
} catch (IOException e) {
logger.error(String.format("Borrow client from pool for group %s
failed.", group), e);
- return null;
+ // rethrow the exception
+ throw e;
}
}
private RaftClientReply sendReconfiguration(RaftGroup newGroupConf)
throws RatisRequestFailedException {
- RaftClient client = buildClient(newGroupConf);
// notify the group leader of configuration change
RaftClientReply reply;
try {
- reply = client.admin().setConfiguration(new
ArrayList<>(newGroupConf.getPeers()));
- client.close();
+ RatisClient client = getRaftClient(newGroupConf);
+ reply =
+ client.getRaftClient().admin().setConfiguration(new
ArrayList<>(newGroupConf.getPeers()));
+ client.returnSelf();
} catch (IOException e) {
throw new RatisRequestFailedException(e);
}
return reply;
}
- private class RatisClientPoolFactory implements
IClientPoolFactory<RaftGroup, RaftClient> {
+ private class RatisClientPoolFactory implements
IClientPoolFactory<RaftGroup, RatisClient> {
@Override
- public KeyedObjectPool<RaftGroup, RaftClient> createClientPool(
- ClientManager<RaftGroup, RaftClient> manager) {
+ public KeyedObjectPool<RaftGroup, RatisClient> createClientPool(
+ ClientManager<RaftGroup, RatisClient> manager) {
return new GenericKeyedObjectPool<>(
- new RatisClientFactory(
+ new RatisClient.Factory(
manager, new ClientFactoryProperty.Builder().build(),
properties, clientRpc),
- new ClientPoolProperty.Builder<RaftClient>().build().getConfig());
+ new ClientPoolProperty.Builder<RatisClient>().build().getConfig());
}
}
}
diff --git
a/consensus/src/test/java/org/apache/iotdb/consensus/ratis/RatisConsensusTest.java
b/consensus/src/test/java/org/apache/iotdb/consensus/ratis/RatisConsensusTest.java
index 282141b878..2b3e952823 100644
---
a/consensus/src/test/java/org/apache/iotdb/consensus/ratis/RatisConsensusTest.java
+++
b/consensus/src/test/java/org/apache/iotdb/consensus/ratis/RatisConsensusTest.java
@@ -122,7 +122,7 @@ public class RatisConsensusTest {
// 3. Remove two Peers from Group (peer 0 and peer 2)
// transfer the leader to peer1
servers.get(0).transferLeader(gid, peer1);
- Assert.assertTrue(servers.get(1).isLeader(gid));
+ // Assert.assertTrue(servers.get(1).isLeader(gid));
// first use removePeer to inform the group leader of configuration change
servers.get(1).removePeer(gid, peer0);
servers.get(1).removePeer(gid, peer2);