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

jianbin pushed a commit to branch 2.x
in repository https://gitbox.apache.org/repos/asf/incubator-seata.git


The following commit(s) were added to refs/heads/2.x by this push:
     new 22f9c4785d bugfix: after scaling down a Raft cluster, the metadata 
still contains the removed node (#6855)
22f9c4785d is described below

commit 22f9c4785da174ebc2de3125712cf1ecfe5f2861
Author: funkye <jian...@apache.org>
AuthorDate: Mon Sep 16 16:31:26 2024 +0800

    bugfix: after scaling down a Raft cluster, the metadata still contains the 
removed node (#6855)
---
 changes/en-us/2.x.md                               |  2 +-
 changes/zh-cn/2.x.md                               |  3 +-
 .../org/apache/seata/common/metadata/Node.java     |  1 -
 .../server/cluster/raft/RaftStateMachine.java      | 68 +++++++++++++---------
 4 files changed, 44 insertions(+), 30 deletions(-)

diff --git a/changes/en-us/2.x.md b/changes/en-us/2.x.md
index 8d39a6320f..07eb237f33 100644
--- a/changes/en-us/2.x.md
+++ b/changes/en-us/2.x.md
@@ -45,7 +45,7 @@ Add changes here for all PR submitted to the 2.x branch.
 - [[#6840](https://github.com/apache/incubator-seata/pull/6840)] Fix the issue 
of unsafe deserialization in ProcessorYaml.java
 - [[#6843](https://github.com/apache/incubator-seata/pull/6843)] Fix 403 error 
when sending a POST request from the console
 - [[#6850](https://github.com/apache/incubator-seata/pull/6850)] raft mode is 
backward compatible with version 2.0
-
+- [[#6855](https://github.com/apache/incubator-seata/pull/6855)] after scaling 
down a Raft cluster, the metadata still contains the removed node
 
 
 ### optimize:
diff --git a/changes/zh-cn/2.x.md b/changes/zh-cn/2.x.md
index 736f85a52b..e0f6cd0604 100644
--- a/changes/zh-cn/2.x.md
+++ b/changes/zh-cn/2.x.md
@@ -45,7 +45,8 @@
 - [[#6845](https://github.com/apache/incubator-seata/pull/6845)] 修复rocksdb 
open相同文件多次的问题
 - [[#6840](https://github.com/apache/incubator-seata/pull/6840)] 
修复ProcessorYaml中不安全的反序列化
 - [[#6843](https://github.com/apache/incubator-seata/pull/6843)] 
修复从控制台发送POST请求时出现的403错误
-- [[#6850](https://github.com/apache/incubator-seata/pull/6850)] raft mode is 
backward compatible with version 2.0
+- [[#6850](https://github.com/apache/incubator-seata/pull/6850)] 
raft模式向下兼容2.0版本
+- [[#6855](https://github.com/apache/incubator-seata/pull/6855)] 
修复raft缩容后元数据中残留该节点的问题(需先升级到2.2再进行缩容)
 
 
 ### optimize:
diff --git a/common/src/main/java/org/apache/seata/common/metadata/Node.java 
b/common/src/main/java/org/apache/seata/common/metadata/Node.java
index 8a4a75f60c..92d43c366f 100644
--- a/common/src/main/java/org/apache/seata/common/metadata/Node.java
+++ b/common/src/main/java/org/apache/seata/common/metadata/Node.java
@@ -122,7 +122,6 @@ public class Node {
         return Objects.equals(control, node.control) && 
Objects.equals(transaction, node.transaction);
     }
 
-
     // convert to String
     public String toJsonString(ObjectMapper objectMapper) {
         try {
diff --git 
a/server/src/main/java/org/apache/seata/server/cluster/raft/RaftStateMachine.java
 
b/server/src/main/java/org/apache/seata/server/cluster/raft/RaftStateMachine.java
index 3f876b63f3..9b49ba011f 100644
--- 
a/server/src/main/java/org/apache/seata/server/cluster/raft/RaftStateMachine.java
+++ 
b/server/src/main/java/org/apache/seata/server/cluster/raft/RaftStateMachine.java
@@ -237,6 +237,9 @@ public class RaftStateMachine extends StateMachineAdapter {
                     SeataClusterContext.unbindGroup();
                 }
             });
+            Configuration conf = 
RouteTable.getInstance().getConfiguration(group);
+            // A member change might trigger a leader re-election. At this 
point, it’s necessary to filter out non-existent members and synchronize again.
+            changePeers(conf);
         }
     }
 
@@ -262,28 +265,40 @@ public class RaftStateMachine extends StateMachineAdapter 
{
     public void onConfigurationCommitted(Configuration conf) {
         LOGGER.info("groupId: {}, onConfigurationCommitted: {}.", group, conf);
         RouteTable.getInstance().updateConfiguration(group, conf);
+        // After a member change, the metadata needs to be synchronized again.
+        initSync.compareAndSet(true, false);
         if (isLeader()) {
-            lock.lock();
-            try {
-                List<PeerId> newFollowers = conf.getPeers();
-                Set<PeerId> newLearners = conf.getLearners();
-                List<Node> currentFollowers = 
raftClusterMetadata.getFollowers();
-                if (CollectionUtils.isNotEmpty(newFollowers)) {
-                    raftClusterMetadata.setFollowers(currentFollowers.stream()
-                        .filter(node -> contains(node, 
newFollowers)).collect(Collectors.toList()));
-                }
-                if (CollectionUtils.isNotEmpty(newLearners)) {
-                    
raftClusterMetadata.setLearner(raftClusterMetadata.getLearner().stream()
-                        .filter(node -> contains(node, 
newLearners)).collect(Collectors.toList()));
-                }
-                syncMetadata();
-            } finally {
-                lock.unlock();
+            changePeers(conf);
+        }
+    }
+
+    private void changePeers(Configuration conf) {
+        lock.lock();
+        try {
+            List<PeerId> newFollowers = conf.getPeers();
+            Set<PeerId> newLearners = conf.getLearners();
+            List<Node> currentFollowers = raftClusterMetadata.getFollowers();
+            if (CollectionUtils.isNotEmpty(newFollowers)) {
+                
raftClusterMetadata.setFollowers(currentFollowers.stream().filter(node -> 
contains(node, newFollowers))
+                    .collect(Collectors.toList()));
+            }
+            if (CollectionUtils.isNotEmpty(newLearners)) {
+                
raftClusterMetadata.setLearner(raftClusterMetadata.getLearner().stream()
+                    .filter(node -> contains(node, 
newLearners)).collect(Collectors.toList()));
+            } else {
+                raftClusterMetadata.setLearner(Collections.emptyList());
             }
+            CompletableFuture.runAsync(this::syncMetadata, 
RESYNC_METADATA_POOL);
+        } finally {
+            lock.unlock();
         }
     }
 
     private boolean contains(Node node, Collection<PeerId> list) {
+        // This indicates that the node is of a lower version.
+        // When scaling up or down on a higher version
+        // you need to ensure that the cluster is consistent first
+        // otherwise, the lower version nodes may be removed.
         if (node.getInternal() == null) {
             return true;
         }
@@ -367,17 +382,16 @@ public class RaftStateMachine extends StateMachineAdapter 
{
     }
 
     private void syncCurrentNodeInfo(String group) {
-        if (initSync.get()) {
-            return;
-        }
-        try {
-            
RouteTable.getInstance().refreshLeader(RaftServerManager.getCliClientServiceInstance(),
 group, 1000);
-            PeerId peerId = RouteTable.getInstance().selectLeader(group);
-            if (peerId != null) {
-                syncCurrentNodeInfo(peerId);
+        if (initSync.compareAndSet(false, true)) {
+            try {
+                
RouteTable.getInstance().refreshLeader(RaftServerManager.getCliClientServiceInstance(),
 group, 1000);
+                PeerId peerId = RouteTable.getInstance().selectLeader(group);
+                if (peerId != null) {
+                    syncCurrentNodeInfo(peerId);
+                }
+            } catch (Exception e) {
+                LOGGER.error(e.getMessage(), e);
             }
-        } catch (Exception e) {
-            LOGGER.error(e.getMessage(), e);
         }
     }
 
@@ -385,7 +399,7 @@ public class RaftStateMachine extends StateMachineAdapter {
         try {
             // Ensure that the current leader must be version 2.1 or later to 
synchronize the operation
             Node leader = raftClusterMetadata.getLeader();
-            if (leader != null && StringUtils.isNotBlank(leader.getVersion()) 
&& initSync.compareAndSet(false, true)) {
+            if (leader != null && StringUtils.isNotBlank(leader.getVersion())) 
{
                 RaftServer raftServer = RaftServerManager.getRaftServer(group);
                 PeerId cureentPeerId = raftServer.getServerId();
                 Node node = raftClusterMetadata.createNode(XID.getIpAddress(), 
XID.getPort(), cureentPeerId.getPort(),


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscr...@seata.apache.org
For additional commands, e-mail: notifications-h...@seata.apache.org

Reply via email to