强一致性方案详解
本章导读
在分布式系统中,强一致性是保证数据正确性的基石,但也意味着性能和可用性的权衡。本章深入剖析两阶段提交、Paxos、Raft等经典协议,帮助你理解如何在分布式环境中实现数据的强一致性保证。
学习目标:
- 目标1:掌握两阶段提交(2PC)和三阶段提交(3PC)的原理与实现
- 目标2:理解Paxos和Raft共识协议的工作机制
- 目标3:能够在实际项目中选择合适的强一致性方案
前置知识:熟悉分布式系统基本概念(CAP定理、BASE理论),了解多线程编程和网络通信基础
阅读时长:约 45 分钟
一、知识概述
在分布式系统中,数据一致性是核心挑战之一。强一致性(Strong Consistency)要求所有节点在任意时刻看到的数据都是相同的,任何读取操作都能读到最新的写入结果。本文将深入探讨强一致性的实现方案,包括分布式事务、共识协议以及实际应用场景。
强一致性的定义
强一致性(也称为线性一致性 Linearizability)保证:
- 原子性:操作要么成功,要么失败,不存在中间状态
- 顺序性:所有操作按真实时间顺序执行
- 即时可见性:写入完成后,所有后续读取都能看到最新值
CAP 定理的约束
根据 CAP 定理,在分布式系统中:
- C(Consistency):强一致性
- A(Availability):可用性
- P(Partition Tolerance):分区容错性
三者最多只能同时满足两个。在网络分区不可避免的情况下,强一致性需要牺牲可用性。
二、核心实现方案
2.1 两阶段提交(2PC)
原理说明
两阶段提交是最经典的分布式事务协议,包含两个阶段:
-
准备阶段(Prepare Phase)
- 协调者向所有参与者发送准备请求
- 参与者执行事务操作,写入 Undo/Redo 日志
- 参与者回复"准备就绪"或"中止"
-
提交阶段(Commit Phase)
- 如果所有参与者都准备就绪,协调者发送提交命令
- 如果有参与者无法准备,协调者发送回滚命令
- 参与者执行提交或回滚,释放资源
状态流转
协调者状态:
INIT → WAITING → PREPARED → COMMITTED
↓
ABORTED
参与者状态:
INIT → PREPARED → COMMITTED
↓
ABORTED
Java 实现
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 两阶段提交协调者
*/
public class TwoPhaseCommitCoordinator {
private final List<Participant> participants;
private final ExecutorService executor;
private final int timeout;
public TwoPhaseCommitCoordinator(List<Participant> participants, int timeoutMs) {
this.participants = participants;
this.executor = Executors.newFixedThreadPool(participants.size());
this.timeout = timeoutMs;
}
/**
* 执行分布式事务
*/
public boolean executeTransaction(Transaction transaction) {
// 阶段1:准备
boolean allPrepared = preparePhase(transaction);
if (!allPrepared) {
// 有参与者准备失败,执行回滚
rollbackPhase(transaction);
return false;
}
// 阶段2:提交
boolean allCommitted = commitPhase(transaction);
return allCommitted;
}
/**
* 准备阶段
*/
private boolean preparePhase(Transaction transaction) {
List<Future<Boolean>> futures = new ArrayList<>();
for (Participant participant : participants) {
Future<Boolean> future = executor.submit(() -> {
try {
return participant.prepare(transaction);
} catch (Exception e) {
System.err.println("Prepare failed for " + participant.getName() + ": " + e.getMessage());
return false;
}
});
futures.add(future);
}
// 等待所有参与者响应
for (Future<Boolean> future : futures) {
try {
Boolean result = future.get(timeout, TimeUnit.MILLISECONDS);
if (result == null || !result) {
return false;
}
} catch (TimeoutException e) {
System.err.println("Prepare timeout");
return false;
} catch (Exception e) {
return false;
}
}
return true;
}
/**
* 提交阶段
*/
private boolean commitPhase(Transaction transaction) {
List<Future<Boolean>> futures = new ArrayList<>();
for (Participant participant : participants) {
Future<Boolean> future = executor.submit(() -> {
try {
return participant.commit(transaction);
} catch (Exception e) {
System.err.println("Commit failed for " + participant.getName() + ": " + e.getMessage());
return false;
}
});
futures.add(future);
}
// 等待所有参与者提交完成
for (Future<Boolean> future : futures) {
try {
Boolean result = future.get(timeout, TimeUnit.MILLISECONDS);
if (result == null || !result) {
// 提交失败,需要人工介入
System.err.println("Commit failed, manual intervention required");
return false;
}
} catch (Exception e) {
return false;
}
}
return true;
}
/**
* 回滚阶段
*/
private void rollbackPhase(Transaction transaction) {
for (Participant participant : participants) {
try {
participant.rollback(transaction);
} catch (Exception e) {
System.err.println("Rollback failed for " + participant.getName() + ": " + e.getMessage());
}
}
}
public void shutdown() {
executor.shutdown();
}
}
/**
* 参与者接口
*/
interface Participant {
String getName();
boolean prepare(Transaction transaction);
boolean commit(Transaction transaction);
boolean rollback(Transaction transaction);
}
/**
* 事务定义
*/
class Transaction {
private final String transactionId;
private final Map<String, Object> data;
public Transaction(String transactionId) {
this.transactionId = transactionId;
this.data = new HashMap<>();
}
public String getTransactionId() {
return transactionId;
}
public void putData(String key, Object value) {
data.put(key, value);
}
public Object getData(String key) {
return data.get(key);
}
}
/**
* 数据库参与者实现
*/
class DatabaseParticipant implements Participant {
private final String name;
private final Map<String, Object> storage;
private final Map<String, Object> undoLog;
public DatabaseParticipant(String name) {
this.name = name;
this.storage = new ConcurrentHashMap<>();
this.undoLog = new ConcurrentHashMap<>();
}
@Override
public String getName() {
return name;
}
@Override
public boolean prepare(Transaction transaction) {
try {
// 模拟准备操作:写入 Undo 日志
String txId = transaction.getTransactionId();
Object key = transaction.getData("key");
Object oldValue = storage.get(key);
// 记录 Undo 日志
undoLog.put(txId, oldValue);
// 锁定资源
System.out.println("[" + name + "] Prepared for transaction: " + txId);
return true;
} catch (Exception e) {
return false;
}
}
@Override
public boolean commit(Transaction transaction) {
try {
String txId = transaction.getTransactionId();
Object key = transaction.getData("key");
Object value = transaction.getData("value");
// 执行实际写入
storage.put(String.valueOf(key), value);
// 清理 Undo 日志
undoLog.remove(txId);
System.out.println("[" + name + "] Committed for transaction: " + txId);
return true;
} catch (Exception e) {
return false;
}
}
@Override
public boolean rollback(Transaction transaction) {
try {
String txId = transaction.getTransactionId();
// 从 Undo 日志恢复
Object oldValue = undoLog.get(txId);
Object key = transaction.getData("key");
if (oldValue != null) {
storage.put(String.valueOf(key), oldValue);
} else {
storage.remove(String.valueOf(key));
}
// 清理 Undo 日志
undoLog.remove(txId);
System.out.println("[" + name + "] Rolled back for transaction: " + txId);
return true;
} catch (Exception e) {
return false;
}
}
public Object getValue(String key) {
return storage.get(key);
}
}
// 使用示例
public class TwoPhaseCommitDemo {
public static void main(String[] args) {
// 创建参与者
List<Participant> participants = Arrays.asList(
new DatabaseParticipant("DB-1"),
new DatabaseParticipant("DB-2"),
new DatabaseParticipant("DB-3")
);
// 创建协调者
TwoPhaseCommitCoordinator coordinator =
new TwoPhaseCommitCoordinator(participants, 5000);
// 执行分布式事务
Transaction transaction = new Transaction("tx-" + System.currentTimeMillis());
transaction.putData("key", "user-001");
transaction.putData("value", "张三");
boolean success = coordinator.executeTransaction(transaction);
System.out.println("Transaction result: " + (success ? "SUCCESS" : "FAILED"));
coordinator.shutdown();
}
}
优缺点分析
优点:
- 原理简单,易于理解
- 保证强一致性
- 广泛应用于数据库系统
缺点:
- 同步阻塞:所有参与者在等待协调者期间锁定资源
- 单点故障:协调者宕机导致事务悬挂
- 数据不一致风险:提交阶段部分失败会导致不一致
- 性能较低:网络往返次数多,延迟高
2.2 三阶段提交(3PC)
原理说明
三阶段提交在 2PC 基础上引入超时机制和预提交阶段:
-
CanCommit 阶段
- 协调者询问参与者是否可以执行事务
- 参与者检查自身状态,不锁定资源
-
PreCommit 阶段
- 如果所有参与者同意,协调者发送预提交请求
- 参与者执行事务操作,锁定资源
- 参与者进入"预提交"状态
-
DoCommit 阶段
- 协调者发送最终提交命令
- 参与者正式提交事务
Java 实现
import java.util.*;
import java.util.concurrent.*;
/**
* 三阶段提交协调者
*/
public class ThreePhaseCommitCoordinator {
private final List<Participant3PC> participants;
private final ExecutorService executor;
private final int timeout;
// 协调者状态
private enum CoordinatorState {
INIT, WAITING_CAN_COMMIT, WAITING_PRE_COMMIT, COMMITTED, ABORTED
}
// 参与者状态
public enum ParticipantState {
INIT, CAN_COMMIT, PRE_COMMITED, COMMITTED, ABORTED
}
public ThreePhaseCommitCoordinator(List<Participant3PC> participants, int timeoutMs) {
this.participants = participants;
this.executor = Executors.newFixedThreadPool(participants.size());
this.timeout = timeoutMs;
}
public boolean executeTransaction(Transaction transaction) {
CoordinatorState state = CoordinatorState.INIT;
// 阶段1:CanCommit
state = CoordinatorState.WAITING_CAN_COMMIT;
boolean canCommit = canCommitPhase(transaction);
if (!canCommit) {
abortPhase(transaction);
return false;
}
// 阶段2:PreCommit
state = CoordinatorState.WAITING_PRE_COMMIT;
boolean preCommitted = preCommitPhase(transaction);
if (!preCommitted) {
abortPhase(transaction);
return false;
}
// 阶段3:DoCommit
boolean committed = doCommitPhase(transaction);
return committed;
}
/**
* CanCommit 阶段:询问参与者是否可以执行
*/
private boolean canCommitPhase(Transaction transaction) {
List<Future<Boolean>> futures = new ArrayList<>();
for (Participant3PC participant : participants) {
Future<Boolean> future = executor.submit(() ->
participant.canCommit(transaction)
);
futures.add(future);
}
return waitForAll(futures);
}
/**
* PreCommit 阶段:预提交
*/
private boolean preCommitPhase(Transaction transaction) {
List<Future<Boolean>> futures = new ArrayList<>();
for (Participant3PC participant : participants) {
Future<Boolean> future = executor.submit(() ->
participant.preCommit(transaction)
);
futures.add(future);
}
return waitForAll(futures);
}
/**
* DoCommit 阶段:最终提交
*/
private boolean doCommitPhase(Transaction transaction) {
List<Future<Boolean>> futures = new ArrayList<>();
for (Participant3PC participant : participants) {
Future<Boolean> future = executor.submit(() ->
participant.doCommit(transaction)
);
futures.add(future);
}
return waitForAll(futures);
}
/**
* 中止事务
*/
private void abortPhase(Transaction transaction) {
for (Participant3PC participant : participants) {
try {
participant.abort(transaction);
} catch (Exception e) {
System.err.println("Abort failed for " + participant.getName());
}
}
}
private boolean waitForAll(List<Future<Boolean>> futures) {
for (Future<Boolean> future : futures) {
try {
Boolean result = future.get(timeout, TimeUnit.MILLISECONDS);
if (result == null || !result) {
return false;
}
} catch (Exception e) {
return false;
}
}
return true;
}
public void shutdown() {
executor.shutdown();
}
}
/**
* 三阶段提交参与者接口
*/
interface Participant3PC {
String getName();
boolean canCommit(Transaction transaction);
boolean preCommit(Transaction transaction);
boolean doCommit(Transaction transaction);
boolean abort(Transaction transaction);
}
/**
* 三阶段提交参与者实现
*/
class Participant3PCImpl implements Participant3PC {
private final String name;
private final Map<String, Object> storage;
private final Map<String, Object> preparedData;
private ThreePhaseCommitCoordinator.ParticipantState state;
public Participant3PCImpl(String name) {
this.name = name;
this.storage = new ConcurrentHashMap<>();
this.preparedData = new ConcurrentHashMap<>();
this.state = ThreePhaseCommitCoordinator.ParticipantState.INIT;
}
@Override
public String getName() {
return name;
}
@Override
public boolean canCommit(Transaction transaction) {
// 检查是否可以执行事务(不锁定资源)
state = ThreePhaseCommitCoordinator.ParticipantState.CAN_COMMIT;
System.out.println("[" + name + "] CanCommit: YES for " + transaction.getTransactionId());
return true;
}
@Override
public boolean preCommit(Transaction transaction) {
try {
// 执行事务操作,锁定资源,但不提交
String txId = transaction.getTransactionId();
Object key = transaction.getData("key");
Object value = transaction.getData("value");
// 保存预提交数据
preparedData.put(txId, new Object[]{key, value});
state = ThreePhaseCommitCoordinator.ParticipantState.PRE_COMMITED;
System.out.println("[" + name + "] PreCommit: OK for " + txId);
return true;
} catch (Exception e) {
return false;
}
}
@Override
public boolean doCommit(Transaction transaction) {
try {
String txId = transaction.getTransactionId();
// 从预提交数据中获取并正式提交
Object[] data = (Object[]) preparedData.remove(txId);
if (data != null) {
storage.put(String.valueOf(data[0]), data[1]);
}
state = ThreePhaseCommitCoordinator.ParticipantState.COMMITTED;
System.out.println("[" + name + "] DoCommit: SUCCESS for " + txId);
return true;
} catch (Exception e) {
return false;
}
}
@Override
public boolean abort(Transaction transaction) {
try {
String txId = transaction.getTransactionId();
// 清理预提交数据
preparedData.remove(txId);
state = ThreePhaseCommitCoordinator.ParticipantState.ABORTED;
System.out.println("[" + name + "] Abort: OK for " + txId);
return true;
} catch (Exception e) {
return false;
}
}
}
// 使用示例
public class ThreePhaseCommitDemo {
public static void main(String[] args) {
List<Participant3PC> participants = Arrays.asList(
new Participant3PCImpl("Node-A"),
new Participant3PCImpl("Node-B"),
new Participant3PCImpl("Node-C")
);
ThreePhaseCommitCoordinator coordinator =
new ThreePhaseCommitCoordinator(participants, 5000);
Transaction transaction = new Transaction("tx-3pc-" + System.currentTimeMillis());
transaction.putData("key", "product-001");
transaction.putData("value", "iPhone 15");
boolean success = coordinator.executeTransaction(transaction);
System.out.println("3PC Transaction result: " + (success ? "SUCCESS" : "FAILED"));
coordinator.shutdown();
}
}
3PC vs 2PC
| 特性 | 2PC | 3PC |
|---|---|---|
| 阶段数 | 2个 | 3个 |
| 超时机制 | 无(参与者会永久阻塞) | 有(参与者超时后可自主决定) |
| 资源锁定 | Prepare 阶段就锁定 | PreCommit 阶段才锁定 |
| 一致性保证 | 强一致 | 可能出现数据不一致 |
| 性能 | 较低 | 更低(多一次网络往返) |
| 适用场景 | 数据库分布式事务 | 对可用性要求更高的场景 |
2.3 Paxos 协议
原理说明
Paxos 是 Lamport 提出的分布式共识算法,用于在不可靠网络中达成一致。包含三种角色:
- Proposer(提议者):提出提案,包含提案编号和值
- Acceptor(接受者):投票表决,接受或拒绝提案
- Learner(学习者):获取最终达成共识的值
算法流程
阶段1:Prepare(准备)
- Proposer 选择提案编号 n,发送 Prepare(n) 给大多数 Acceptor
- Acceptor 收到 Prepare(n) 后:
- 如果 n > 之前响应过的提案编号,承诺不再接受编号小于 n 的提案
- 返回已接受的最高编号提案(如果有)
阶段2:Accept(接受)
- Proposer 收到大多数 Acceptor 的响应后:
- 如果响应中有已接受的值,选择编号最大的那个值
- 否则,可以选择自己的值
- 发送 Accept(n, value) 给 Acceptor
- Acceptor 收到 Accept(n, value) 后:
- 如果没有承诺过更大的编号,接受该提案
- 否则,拒绝
Java 实现
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicLong;
/**
* Paxos Proposer 实现
*/
public class Proposer {
private final String id;
private final List<Acceptor> acceptors;
private final AtomicLong proposalNumber;
public Proposer(String id, List<Acceptor> acceptors) {
this.id = id;
this.acceptors = acceptors;
this.proposalNumber = new AtomicLong(0);
}
/**
* 提议一个值
*/
public boolean propose(String value) {
long n = generateProposalNumber();
// 阶段1:Prepare
PrepareResponse prepareResponse = sendPrepare(n);
if (!prepareResponse.isPromised) {
System.out.println("[Proposer-" + id + "] Prepare rejected, retry with higher number");
return false;
}
// 如果有已接受的值,必须使用它
String valueToPropose = prepareResponse.acceptedValue != null
? prepareResponse.acceptedValue
: value;
// 阶段2:Accept
boolean accepted = sendAccept(n, valueToPropose);
if (accepted) {
System.out.println("[Proposer-" + id + "] Value '" + valueToPropose + "' accepted with number " + n);
}
return accepted;
}
/**
* 发送 Prepare 请求
*/
private PrepareResponse sendPrepare(long n) {
int promises = 0;
Long acceptedNumber = null;
String acceptedValue = null;
for (Acceptor acceptor : acceptors) {
Acceptor.PrepareResult result = acceptor.prepare(n);
if (result.promised) {
promises++;
// 记录已接受的最高编号提案
if (result.acceptedNumber != null) {
if (acceptedNumber == null || result.acceptedNumber > acceptedNumber) {
acceptedNumber = result.acceptedNumber;
acceptedValue = result.acceptedValue;
}
}
}
}
boolean isPromised = promises > acceptors.size() / 2;
return new PrepareResponse(isPromised, acceptedNumber, acceptedValue);
}
/**
* 发送 Accept 请求
*/
private boolean sendAccept(long n, String value) {
int accepts = 0;
for (Acceptor acceptor : acceptors) {
if (acceptor.accept(n, value)) {
accepts++;
}
}
return accepts > acceptors.size() / 2;
}
private long generateProposalNumber() {
return proposalNumber.incrementAndGet();
}
private static class PrepareResponse {
final boolean isPromised;
final Long acceptedNumber;
final String acceptedValue;
PrepareResponse(boolean isPromised, Long acceptedNumber, String acceptedValue) {
this.isPromised = isPromised;
this.acceptedNumber = acceptedNumber;
this.acceptedValue = acceptedValue;
}
}
}
/**
* Paxos Acceptor 实现
*/
public class Acceptor {
private final String id;
private long promisedNumber;
private long acceptedNumber;
private String acceptedValue;
public Acceptor(String id) {
this.id = id;
this.promisedNumber = -1;
this.acceptedNumber = -1;
this.acceptedValue = null;
}
/**
* 处理 Prepare 请求
*/
public synchronized PrepareResult prepare(long n) {
if (n > promisedNumber) {
promisedNumber = n;
System.out.println("[Acceptor-" + id + "] Promised for number " + n);
return new PrepareResult(true, acceptedNumber, acceptedValue);
} else {
System.out.println("[Acceptor-" + id + "] Rejected prepare for number " + n +
" (promised: " + promisedNumber + ")");
return new PrepareResult(false, null, null);
}
}
/**
* 处理 Accept 请求
*/
public synchronized boolean accept(long n, String value) {
if (n >= promisedNumber) {
promisedNumber = n;
acceptedNumber = n;
acceptedValue = value;
System.out.println("[Acceptor-" + id + "] Accepted: number=" + n + ", value=" + value);
return true;
} else {
System.out.println("[Acceptor-" + id + "] Rejected accept for number " + n);
return false;
}
}
public synchronized String getAcceptedValue() {
return acceptedValue;
}
public static class PrepareResult {
final boolean promised;
final Long acceptedNumber;
final String acceptedValue;
PrepareResult(boolean promised, Long acceptedNumber, String acceptedValue) {
this.promised = promised;
this.acceptedNumber = acceptedNumber;
this.acceptedValue = acceptedValue;
}
}
}
/**
* Paxos Learner 实现
*/
public class Learner {
private final String id;
private final List<Acceptor> acceptors;
private String learnedValue;
public Learner(String id, List<Acceptor> acceptors) {
this.id = id;
this.acceptors = acceptors;
this.learnedValue = null;
}
/**
* 学习已达成共识的值
*/
public String learn() {
Map<String, Integer> valueCounts = new HashMap<>();
for (Acceptor acceptor : acceptors) {
String value = acceptor.getAcceptedValue();
if (value != null) {
valueCounts.merge(value, 1, Integer::sum);
// 如果大多数 Acceptor 接受了同一个值,则达成共识
if (valueCounts.get(value) > acceptors.size() / 2) {
learnedValue = value;
System.out.println("[Learner-" + id + "] Learned value: " + value);
return value;
}
}
}
return null;
}
public String getLearnedValue() {
return learnedValue;
}
}
// Paxos 完整演示
public class PaxosDemo {
public static void main(String[] args) throws InterruptedException {
// 创建 5 个 Acceptor
List<Acceptor> acceptors = new ArrayList<>();
for (int i = 0; i < 5; i++) {
acceptors.add(new Acceptor("A" + i));
}
// 创建多个 Proposer
List<Proposer> proposers = Arrays.asList(
new Proposer("P1", acceptors),
new Proposer("P2", acceptors),
new Proposer("P3", acceptors)
);
// 创建 Learner
Learner learner = new Learner("L1", acceptors);
// 并发提议
ExecutorService executor = Executors.newFixedThreadPool(3);
String[] values = {"value-A", "value-B", "value-C"};
for (int i = 0; i < proposers.size(); i++) {
final Proposer proposer = proposers.get(i);
final String value = values[i];
executor.submit(() -> {
// 重试直到成功
while (!proposer.propose(value)) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
break;
}
}
});
}
Thread.sleep(1000);
// 学习最终值
String finalValue = learner.learn();
System.out.println("\n=== Consensus Reached ===");
System.out.println("Final value: " + finalValue);
executor.shutdown();
}
}
2.4 Raft 协议
原理说明
Raft 是更易于理解的共识算法,将一致性问题分解为三个子问题:
- Leader 选举:选出唯一领导者
- 日志复制:Leader 接收日志并复制到其他节点
- 安全性:确保所有节点最终一致
节点状态
- Follower:跟随者,被动响应 Leader 和 Candidate
- Candidate:候选人,选举过程中的临时状态
- Leader:领导者,处理所有客户端请求
选举流程
Follower --(选举超时)--> Candidate
Candidate --(获得多数票)--> Leader
Candidate --(收到更高任期)--> Follower
Leader --(发现更高任期)--> Follower
Java 实现
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
/**
* Raft 节点实现
*/
public class RaftNode {
// 节点状态
public enum State {
FOLLOWER, CANDIDATE, LEADER
}
// 节点配置
private final String nodeId;
private final List<RaftNode> peers;
private final ScheduledExecutorService scheduler;
// 持久化状态
private final AtomicLong currentTerm;
private final AtomicReference<String> votedFor;
private final List<LogEntry> log;
// 易失性状态
private volatile State state;
private volatile long commitIndex;
private volatile long lastApplied;
// Leader 状态
private Map<String, Long> nextIndex;
private Map<String, Long> matchIndex;
// 选举相关
private ScheduledFuture<?> electionTimeout;
private final Random random;
private long lastHeartbeat;
// 选举超时范围(毫秒)
private static final int ELECTION_TIMEOUT_MIN = 150;
private static final int ELECTION_TIMEOUT_MAX = 300;
private static final int HEARTBEAT_INTERVAL = 50;
public RaftNode(String nodeId) {
this.nodeId = nodeId;
this.peers = new ArrayList<>();
this.scheduler = Executors.newScheduledThreadPool(2);
this.currentTerm = new AtomicLong(0);
this.votedFor = new AtomicReference<>(null);
this.log = new CopyOnWriteArrayList<>();
this.state = State.FOLLOWER;
this.commitIndex = 0;
this.lastApplied = 0;
this.random = new Random();
this.lastHeartbeat = System.currentTimeMillis();
}
/**
* 添加同伴节点
*/
public void addPeer(RaftNode peer) {
peers.add(peer);
}
/**
* 启动节点
*/
public void start() {
resetElectionTimeout();
}
/**
* 重置选举超时
*/
private void resetElectionTimeout() {
if (electionTimeout != null) {
electionTimeout.cancel(false);
}
int timeout = ELECTION_TIMEOUT_MIN +
random.nextInt(ELECTION_TIMEOUT_MAX - ELECTION_TIMEOUT_MIN);
electionTimeout = scheduler.schedule(() -> {
if (state != State.LEADER &&
System.currentTimeMillis() - lastHeartbeat > timeout) {
startElection();
}
resetElectionTimeout();
}, timeout, TimeUnit.MILLISECONDS);
}
/**
* 开始选举
*/
private void startElection() {
state = State.CANDIDATE;
currentTerm.incrementAndGet();
votedFor.set(nodeId);
long term = currentTerm.get();
System.out.println("[Node-" + nodeId + "] Starting election for term " + term);
// 向所有同伴请求投票
AtomicInteger votes = new AtomicInteger(1); // 自己投自己
CountDownLatch latch = new CountDownLatch(peers.size());
for (RaftNode peer : peers) {
scheduler.submit(() -> {
try {
VoteResponse response = peer.requestVote(term, nodeId, log.size() - 1,
log.isEmpty() ? 0 : log.get(log.size() - 1).term);
if (response.voteGranted) {
votes.incrementAndGet();
}
} finally {
latch.countDown();
}
});
}
try {
latch.await(ELECTION_TIMEOUT_MAX, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
return;
}
// 检查是否获得多数票
if (votes.get() > (peers.size() + 1) / 2 && currentTerm.get() == term) {
becomeLeader();
}
}
/**
* 成为 Leader
*/
private void becomeLeader() {
state = State.LEADER;
System.out.println("[Node-" + nodeId + "] Became LEADER for term " + currentTerm.get());
// 初始化 Leader 状态
nextIndex = new ConcurrentHashMap<>();
matchIndex = new ConcurrentHashMap<>();
for (RaftNode peer : peers) {
nextIndex.put(peer.nodeId, (long) log.size() + 1);
matchIndex.put(peer.nodeId, 0L);
}
// 开始发送心跳
scheduler.scheduleAtFixedRate(this::sendHeartbeats,
0, HEARTBEAT_INTERVAL, TimeUnit.MILLISECONDS);
}
/**
* 发送心跳
*/
private void sendHeartbeats() {
if (state != State.LEADER) {
return;
}
for (RaftNode peer : peers) {
scheduler.submit(() -> {
peer.appendEntries(currentTerm.get(), nodeId,
log.size() - 1, log.isEmpty() ? 0 : log.get(log.size() - 1).term,
Collections.emptyList(), commitIndex);
});
}
}
/**
* 处理投票请求
*/
public synchronized VoteResponse requestVote(long term, String candidateId,
long lastLogIndex, long lastLogTerm) {
// 任期检查
if (term < currentTerm.get()) {
return new VoteResponse(currentTerm.get(), false);
}
// 如果任期更大,更新任期并转为 Follower
if (term > currentTerm.get()) {
currentTerm.set(term);
votedFor.set(null);
state = State.FOLLOWER;
}
// 检查是否已经投票
String currentVote = votedFor.get();
if (currentVote != null && !currentVote.equals(candidateId)) {
return new VoteResponse(currentTerm.get(), false);
}
// 检查日志是否至少一样新
long myLastLogIndex = log.size() - 1;
long myLastLogTerm = log.isEmpty() ? 0 : log.get(log.size() - 1).term;
boolean logIsUpToDate = (lastLogTerm > myLastLogTerm) ||
(lastLogTerm == myLastLogTerm && lastLogIndex >= myLastLogIndex);
if (!logIsUpToDate) {
return new VoteResponse(currentTerm.get(), false);
}
// 投票给候选人
votedFor.set(candidateId);
lastHeartbeat = System.currentTimeMillis();
resetElectionTimeout();
System.out.println("[Node-" + nodeId + "] Voted for " + candidateId);
return new VoteResponse(currentTerm.get(), true);
}
/**
* 处理日志追加请求(包括心跳)
*/
public synchronized boolean appendEntries(long term, String leaderId,
long prevLogIndex, long prevLogTerm, List<LogEntry> entries, long leaderCommit) {
lastHeartbeat = System.currentTimeMillis();
// 任期检查
if (term < currentTerm.get()) {
return false;
}
if (term > currentTerm.get()) {
currentTerm.set(term);
votedFor.set(null);
}
state = State.FOLLOWER;
resetElectionTimeout();
// 日志一致性检查
if (prevLogIndex >= 0 && (log.size() <= prevLogIndex ||
log.get((int) prevLogIndex).term != prevLogTerm)) {
return false;
}
// 追加日志
if (!entries.isEmpty()) {
log.addAll(entries);
System.out.println("[Node-" + nodeId + "] Appended " + entries.size() + " entries");
}
// 更新提交索引
if (leaderCommit > commitIndex) {
commitIndex = Math.min(leaderCommit, log.size() - 1);
}
return true;
}
/**
* 提交命令(仅 Leader 可调用)
*/
public boolean submitCommand(String command) {
if (state != State.LEADER) {
return false;
}
LogEntry entry = new LogEntry(currentTerm.get(), command);
log.add(entry);
System.out.println("[Node-" + nodeId + "] Received command: " + command);
// 异步复制到其他节点
for (RaftNode peer : peers) {
scheduler.submit(() -> {
List<LogEntry> entries = Collections.singletonList(entry);
peer.appendEntries(currentTerm.get(), nodeId,
log.size() - 2, log.get(log.size() - 2).term,
entries, commitIndex);
});
}
return true;
}
// Getters
public State getState() { return state; }
public long getCurrentTerm() { return currentTerm.get(); }
// 辅助类
public static class LogEntry {
final long term;
final String command;
LogEntry(long term, String command) {
this.term = term;
this.command = command;
}
}
public static class VoteResponse {
final long term;
final boolean voteGranted;
VoteResponse(long term, boolean voteGranted) {
this.term = term;
this.voteGranted = voteGranted;
}
}
public void shutdown() {
scheduler.shutdown();
}
}
// Raft 集群演示
public class RaftClusterDemo {
public static void main(String[] args) throws InterruptedException {
// 创建 5 个节点的集群
List<RaftNode> nodes = new ArrayList<>();
for (int i = 0; i < 5; i++) {
nodes.add(new RaftNode("N" + i));
}
// 设置同伴节点
for (RaftNode node : nodes) {
for (RaftNode peer : nodes) {
if (peer != node) {
node.addPeer(peer);
}
}
}
// 启动所有节点
for (RaftNode node : nodes) {
node.start();
}
// 等待选举完成
Thread.sleep(1000);
// 找到 Leader 并提交命令
RaftNode leader = null;
for (RaftNode node : nodes) {
if (node.getState() == RaftNode.State.LEADER) {
leader = node;
break;
}
}
if (leader != null) {
System.out.println("\n=== Submitting commands ===");
leader.submitCommand("SET x = 1");
leader.submitCommand("SET y = 2");
leader.submitCommand("INCR x");
}
Thread.sleep(500);
// 打印最终状态
System.out.println("\n=== Final State ===");
for (RaftNode node : nodes) {
System.out.println("Node-" + node.nodeId +
": State=" + node.getState() +
", Term=" + node.getCurrentTerm());
}
// 关闭
for (RaftNode node : nodes) {
node.shutdown();
}
}
}
三、实战应用场景
3.1 分布式数据库
场景说明
数据库分布式事务需要保证 ACID 特性,强一致性是核心要求。
实现方案
import java.sql.*;
import java.util.*;
import javax.sql.DataSource;
/**
* 分布式数据库事务管理器
*/
public class DistributedTransactionManager {
private final List<DataSource> dataSources;
private final ThreadLocal<List<Connection>> connectionsHolder;
public DistributedTransactionManager(List<DataSource> dataSources) {
this.dataSources = dataSources;
this.connectionsHolder = new ThreadLocal<>();
}
/**
* 执行分布式事务
*/
public <T> T executeInTransaction(TransactionCallback<T> callback) throws Exception {
List<Connection> connections = beginTransaction();
try {
T result = callback.doInTransaction(connections);
commit(connections);
return result;
} catch (Exception e) {
rollback(connections);
throw e;
} finally {
closeConnections(connections);
connectionsHolder.remove();
}
}
/**
* 开始分布式事务
*/
private List<Connection> beginTransaction() throws SQLException {
List<Connection> connections = new ArrayList<>();
for (DataSource ds : dataSources) {
Connection conn = ds.getConnection();
conn.setAutoCommit(false);
// 设置事务隔离级别
conn.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
connections.add(conn);
}
connectionsHolder.set(connections);
return connections;
}
/**
* 提交事务(两阶段提交)
*/
private void commit(List<Connection> connections) throws SQLException {
// 阶段1:准备
for (Connection conn : connections) {
// 注意:标准 JDBC 没有 prepare 方法
// 这里使用 XAConnection 实现
}
// 阶段2:提交
for (Connection conn : connections) {
conn.commit();
}
}
/**
* 回滚事务
*/
private void rollback(List<Connection> connections) {
for (Connection conn : connections) {
try {
conn.rollback();
} catch (SQLException e) {
// 记录日志
}
}
}
/**
* 关闭连接
*/
private void closeConnections(List<Connection> connections) {
for (Connection conn : connections) {
try {
conn.close();
} catch (SQLException e) {
// 忽略
}
}
}
@FunctionalInterface
public interface TransactionCallback<T> {
T doInTransaction(List<Connection> connections) throws Exception;
}
}
/**
* XA 分布式事务实现
*/
public class XATransactionManager {
private final List<XADataSource> xaDataSources;
public XATransactionManager(List<XADataSource> xaDataSources) {
this.xaDataSources = xaDataSources;
}
/**
* 执行 XA 分布式事务
*/
public void executeXA(XATransactionCallback callback) throws Exception {
// 生成全局事务 ID
Xid xid = createXid();
List<XAConnection> xaConnections = new ArrayList<>();
List<XAResource> xaResources = new ArrayList<>();
try {
// 获取所有资源的 XA 连接
for (XADataSource xaDs : xaDataSources) {
XAConnection xaConn = xaDs.getXAConnection();
xaConnections.add(xaConn);
xaResources.add(xaConn.getXAResource());
}
// 开始 XA 事务
for (XAResource xaRes : xaResources) {
xaRes.start(xid, XAResource.TMNOFLAGS);
}
// 执行业务逻辑
callback.execute(xaConnections);
// 结束 XA 事务
for (XAResource xaRes : xaResources) {
xaRes.end(xid, XAResource.TMSUCCESS);
}
// 阶段1:准备
for (XAResource xaRes : xaResources) {
int prepareResult = xaRes.prepare(xid);
if (prepareResult == XAResource.XA_RBROLLBACK) {
throw new RuntimeException("Prepare failed");
}
}
// 阶段2:提交
for (XAResource xaRes : xaResources) {
xaRes.commit(xid, false);
}
} catch (Exception e) {
// 回滚
for (XAResource xaRes : xaResources) {
try {
xaRes.rollback(xid);
} catch (XAException ex) {
// 记录日志
}
}
throw e;
} finally {
for (XAConnection xaConn : xaConnections) {
try {
xaConn.close();
} catch (Exception e) {
// 忽略
}
}
}
}
/**
* 创建 XID
*/
private Xid createXid() {
return new Xid() {
private final int formatId = 1;
private final byte[] globalId = UUID.randomUUID().toString().getBytes();
private final byte[] branchId = "0".getBytes();
@Override
public int getFormatId() { return formatId; }
@Override
public byte[] getGlobalTransactionId() { return globalId; }
@Override
public byte[] getBranchQualifier() { return branchId; }
};
}
@FunctionalInterface
public interface XATransactionCallback {
void execute(List<XAConnection> connections) throws Exception;
}
}
3.2 分布式锁服务
场景说明
基于 Raft 实现强一致性的分布式锁服务。
实现方案
import java.util.concurrent.*;
/**
* 基于 Raft 的分布式锁服务
*/
public class DistributedLockService {
private final RaftNode raftNode;
private final ConcurrentHashMap<String, LockInfo> locks;
private final ScheduledExecutorService scheduler;
public DistributedLockService(RaftNode raftNode) {
this.raftNode = raftNode;
this.locks = new ConcurrentHashMap<>();
this.scheduler = Executors.newScheduledThreadPool(1);
}
/**
* 获取分布式锁
*/
public LockResult tryLock(String lockKey, String clientId, long leaseTime, TimeUnit unit) {
// 只有 Leader 可以处理请求
if (raftNode.getState() != RaftNode.State.LEADER) {
return new LockResult(false, "Not leader", -1);
}
LockInfo existingLock = locks.get(lockKey);
// 检查锁是否已被持有
if (existingLock != null && !existingLock.isExpired()) {
if (existingLock.clientId.equals(clientId)) {
// 可重入锁,延长租期
existingLock.extend(leaseTime, unit);
return new LockResult(true, "Lock extended", existingLock.version);
}
return new LockResult(false, "Lock held by " + existingLock.clientId, -1);
}
// 创建新锁
LockInfo newLock = new LockInfo(
clientId,
System.currentTimeMillis() + unit.toMillis(leaseTime),
raftNode.getCurrentTerm()
);
// 提交到 Raft 日志
LockCommand command = new LockCommand("LOCK", lockKey, clientId, newLock.expireTime);
if (raftNode.submitCommand(command.toString())) {
locks.put(lockKey, newLock);
return new LockResult(true, "Lock acquired", newLock.version);
}
return new LockResult(false, "Failed to replicate", -1);
}
/**
* 释放分布式锁
*/
public boolean unlock(String lockKey, String clientId, long version) {
if (raftNode.getState() != RaftNode.State.LEADER) {
return false;
}
LockInfo lock = locks.get(lockKey);
if (lock == null) {
return false;
}
// 验证锁的所有权
if (!lock.clientId.equals(clientId)) {
return false;
}
// 验证版本号
if (lock.version != version) {
return false;
}
// 提交到 Raft 日志
LockCommand command = new LockCommand("UNLOCK", lockKey, clientId, 0);
if (raftNode.submitCommand(command.toString())) {
locks.remove(lockKey);
return true;
}
return false;
}
/**
* 锁信息
*/
static class LockInfo {
final String clientId;
volatile long expireTime;
final long version;
LockInfo(String clientId, long expireTime, long version) {
this.clientId = clientId;
this.expireTime = expireTime;
this.version = version;
}
boolean isExpired() {
return System.currentTimeMillis() > expireTime;
}
void extend(long leaseTime, TimeUnit unit) {
this.expireTime = System.currentTimeMillis() + unit.toMillis(leaseTime);
}
}
/**
* 锁命令
*/
static class LockCommand {
final String operation;
final String lockKey;
final String clientId;
final long expireTime;
LockCommand(String operation, String lockKey, String clientId, long expireTime) {
this.operation = operation;
this.lockKey = lockKey;
this.clientId = clientId;
this.expireTime = expireTime;
}
@Override
public String toString() {
return String.format("%s:%s:%s:%d", operation, lockKey, clientId, expireTime);
}
}
/**
* 锁结果
*/
static class LockResult {
final boolean success;
final String message;
final long version;
LockResult(boolean success, String message, long version) {
this.success = success;
this.message = message;
this.version = version;
}
}
}
3.3 配置中心
场景说明
强一致性的分布式配置中心,确保所有节点配置一致。
实现方案
import java.util.*;
import java.util.concurrent.*;
/**
* 强一致性配置中心
*/
public class ConfigCenter {
private final RaftNode raftNode;
private final Map<String, ConfigEntry> configs;
private final List<ConfigWatcher> watchers;
public ConfigCenter(RaftNode raftNode) {
this.raftNode = raftNode;
this.configs = new ConcurrentHashMap<>();
this.watchers = new CopyOnWriteArrayList<>();
}
/**
* 设置配置
*/
public boolean setConfig(String key, String value) {
if (raftNode.getState() != RaftNode.State.LEADER) {
throw new IllegalStateException("Only leader can set config");
}
ConfigCommand command = new ConfigCommand("SET", key, value, System.currentTimeMillis());
if (raftNode.submitCommand(command.toString())) {
// 应用配置
applyConfig(key, value, command.timestamp);
return true;
}
return false;
}
/**
* 获取配置
*/
public String getConfig(String key) {
ConfigEntry entry = configs.get(key);
return entry != null ? entry.value : null;
}
/**
* 删除配置
*/
public boolean deleteConfig(String key) {
if (raftNode.getState() != RaftNode.State.LEADER) {
throw new IllegalStateException("Only leader can delete config");
}
ConfigCommand command = new ConfigCommand("DELETE", key, null, System.currentTimeMillis());
if (raftNode.submitCommand(command.toString())) {
configs.remove(key);
notifyWatchers(key, null);
return true;
}
return false;
}
/**
* 应用配置(从 Raft 日志重放)
*/
public void applyConfig(String key, String value, long timestamp) {
if (value == null) {
configs.remove(key);
} else {
configs.put(key, new ConfigEntry(value, timestamp));
}
notifyWatchers(key, value);
}
/**
* 注册监听器
*/
public void addWatcher(ConfigWatcher watcher) {
watchers.add(watcher);
}
/**
* 通知监听器
*/
private void notifyWatchers(String key, String value) {
for (ConfigWatcher watcher : watchers) {
try {
watcher.onConfigChange(key, value);
} catch (Exception e) {
// 记录日志
}
}
}
/**
* 配置条目
*/
static class ConfigEntry {
final String value;
final long timestamp;
ConfigEntry(String value, long timestamp) {
this.value = value;
this.timestamp = timestamp;
}
}
/**
* 配置命令
*/
static class ConfigCommand {
final String operation;
final String key;
final String value;
final long timestamp;
ConfigCommand(String operation, String key, String value, long timestamp) {
this.operation = operation;
this.key = key;
this.value = value;
this.timestamp = timestamp;
}
@Override
public String toString() {
return String.format("CONFIG:%s:%s:%s:%d", operation, key, value, timestamp);
}
}
/**
* 配置监听器
*/
interface ConfigWatcher {
void onConfigChange(String key, String value);
}
}
// 使用示例
public class ConfigCenterDemo {
public static void main(String[] args) throws InterruptedException {
// 创建 Raft 集群
List<RaftNode> nodes = new ArrayList<>();
for (int i = 0; i < 3; i++) {
RaftNode node = new RaftNode("ConfigNode-" + i);
nodes.add(node);
}
for (RaftNode node : nodes) {
for (RaftNode peer : nodes) {
if (peer != node) {
node.addPeer(peer);
}
}
node.start();
}
Thread.sleep(1000);
// 找到 Leader
RaftNode leader = nodes.stream()
.filter(n -> n.getState() == RaftNode.State.LEADER)
.findFirst()
.orElseThrow();
// 创建配置中心
ConfigCenter configCenter = new ConfigCenter(leader);
// 注册监听器
configCenter.addWatcher((key, value) -> {
System.out.println("Config changed: " + key + " = " + value);
});
// 设置配置
configCenter.setConfig("database.url", "jdbc:mysql://localhost:3306/mydb");
configCenter.setConfig("cache.ttl", "3600");
// 读取配置
System.out.println("database.url = " + configCenter.getConfig("database.url"));
System.out.println("cache.ttl = " + configCenter.getConfig("cache.ttl"));
// 关闭
for (RaftNode node : nodes) {
node.shutdown();
}
}
}
四、总结与最佳实践
强一致性方案对比
| 方案 | 一致性保证 | 可用性 | 性能 | 适用场景 |
|---|---|---|---|---|
| 2PC | 强一致 | 低(阻塞) | 低 | 数据库分布式事务 |
| 3PC | 较强一致 | 中 | 低 | 金融交易系统 |
| Paxos | 强一致 | 中 | 中 | 分布式存储、配置中心 |
| Raft | 强一致 | 中 | 中 | 分布式锁、配置中心、日志复制 |
最佳实践
1. 选择合适的方案
/**
* 一致性方案选择指南
*/
public class ConsistencyStrategySelector {
public ConsistencyStrategy select(Requirement requirement) {
// 需要强一致 + 可接受性能损失
if (requirement.strongConsistency &&
requirement.canTolerateLatency) {
return ConsistencyStrategy.TWO_PHASE_COMMIT;
}
// 需要强一致 + 高可用
if (requirement.strongConsistency &&
requirement.highAvailability) {
return ConsistencyStrategy.RAFT;
}
// 允许短暂不一致 + 高性能
if (requirement.eventualConsistency) {
return ConsistencyStrategy.EVENTUAL;
}
return ConsistencyStrategy.RAFT;
}
}
enum ConsistencyStrategy {
TWO_PHASE_COMMIT,
THREE_PHASE_COMMIT,
PAXOS,
RAFT,
EVENTUAL
}
2. 异常处理
/**
* 分布式事务异常处理器
*/
public class TransactionRecoveryHandler {
private final TransactionLog transactionLog;
/**
* 恢复悬挂事务
*/
public void recoverPendingTransactions() {
List<Transaction> pendingTxs = transactionLog.findPendingTransactions();
for (Transaction tx : pendingTxs) {
try {
// 查询所有参与者状态
TransactionStatus status = queryTransactionStatus(tx);
switch (status) {
case PREPARED:
// 所有参与者已准备,执行提交
commitTransaction(tx);
break;
case ABORTED:
// 有参与者已中止,执行回滚
rollbackTransaction(tx);
break;
case UNKNOWN:
// 状态未知,人工介入
markForManualIntervention(tx);
break;
}
} catch (Exception e) {
// 记录日志,稍后重试
transactionLog.markForRetry(tx);
}
}
}
/**
* 超时处理
*/
public void handleTimeout(Transaction tx) {
// 根据事务状态决定回滚或提交
if (tx.getState() == TransactionState.PREPARED) {
// 准备阶段超时,回滚
rollbackTransaction(tx);
} else if (tx.getState() == TransactionState.COMMITTING) {
// 提交阶段超时,重试
retryCommit(tx);
}
}
}
3. 监控与告警
/**
* 一致性监控指标
*/
public class ConsistencyMetrics {
private final MeterRegistry meterRegistry;
// 事务指标
private final Counter transactionSuccess;
private final Counter transactionFailure;
private final Timer transactionLatency;
// Raft 指标
private final Gauge leaderTerm;
private final Gauge commitIndex;
private final Counter electionTimeout;
public ConsistencyMetrics(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
this.transactionSuccess = Counter.builder("transaction.success")
.description("Successful transactions")
.register(meterRegistry);
this.transactionFailure = Counter.builder("transaction.failure")
.description("Failed transactions")
.register(meterRegistry);
this.transactionLatency = Timer.builder("transaction.latency")
.description("Transaction latency")
.register(meterRegistry);
this.leaderTerm = Gauge.builder("raft.leader.term", this::getLeaderTerm)
.description("Current leader term")
.register(meterRegistry);
this.commitIndex = Gauge.builder("raft.commit.index", this::getCommitIndex)
.description("Current commit index")
.register(meterRegistry);
this.electionTimeout = Counter.builder("raft.election.timeout")
.description("Election timeouts")
.register(meterRegistry);
}
public void recordTransactionSuccess() {
transactionSuccess.increment();
}
public void recordTransactionFailure() {
transactionFailure.increment();
}
public Timer.Sample startTransactionTimer() {
return Timer.start(meterRegistry);
}
public void recordTransactionLatency(Timer.Sample sample) {
sample.stop(transactionLatency);
}
private double getLeaderTerm() {
// 返回当前 Leader 任期
return 0;
}
private double getCommitIndex() {
// 返回当前提交索引
return 0;
}
}
关键要点
- 理解 CAP 权衡:强一致性需要牺牲可用性,根据业务需求选择
- 超时机制必不可少:避免资源长时间锁定
- 幂等设计:重试操作必须幂等
- 监控告警:及时发现一致性问题
- 人工介入机制:极端情况下的兜底方案
六、思考与练习
思考题
- 基础题:两阶段提交(2PC)为什么会出现阻塞问题?三阶段提交(3PC)是如何改进的?
- 进阶题:Paxos协议中,为什么需要多数派(Quorum)才能达成共识?如果网络分区发生,Paxos如何保证安全性?
- 实战题:在一个电商系统中,订单服务和库存服务分别部署在不同机房,如何设计强一致性的库存扣减方案?
编程练习
练习:基于Raft协议实现一个简单的分布式键值存储系统,要求:
- 支持SET/GET/DELETE操作
- Leader选举和日志复制
- 客户端请求转发到Leader
章节关联
- 前置章节:《分布式系统基础概念》
- 后续章节:《最终一致性方案详解》
- 扩展阅读:Lamport《Paxos Made Simple》、Raft论文《In Search of an Understandable Consensus Algorithm》
📝 下一章预告
下一章将探讨最终一致性方案,学习如何在允许短暂不一致的前提下,实现更高性能和可用性的分布式系统,包括事件溯源、CQRS、Saga模式等核心内容。
本章完