55-强一致性方案详解

17 阅读20分钟

强一致性方案详解

本章导读

在分布式系统中,强一致性是保证数据正确性的基石,但也意味着性能和可用性的权衡。本章深入剖析两阶段提交、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)

原理说明

两阶段提交是最经典的分布式事务协议,包含两个阶段:

  1. 准备阶段(Prepare Phase)

    • 协调者向所有参与者发送准备请求
    • 参与者执行事务操作,写入 Undo/Redo 日志
    • 参与者回复"准备就绪"或"中止"
  2. 提交阶段(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 基础上引入超时机制和预提交阶段:

  1. CanCommit 阶段

    • 协调者询问参与者是否可以执行事务
    • 参与者检查自身状态,不锁定资源
  2. PreCommit 阶段

    • 如果所有参与者同意,协调者发送预提交请求
    • 参与者执行事务操作,锁定资源
    • 参与者进入"预提交"状态
  3. 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
特性2PC3PC
阶段数2个3个
超时机制无(参与者会永久阻塞)有(参与者超时后可自主决定)
资源锁定Prepare 阶段就锁定PreCommit 阶段才锁定
一致性保证强一致可能出现数据不一致
性能较低更低(多一次网络往返)
适用场景数据库分布式事务对可用性要求更高的场景

2.3 Paxos 协议

原理说明

Paxos 是 Lamport 提出的分布式共识算法,用于在不可靠网络中达成一致。包含三种角色:

  1. Proposer(提议者):提出提案,包含提案编号和值
  2. Acceptor(接受者):投票表决,接受或拒绝提案
  3. 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 是更易于理解的共识算法,将一致性问题分解为三个子问题:

  1. Leader 选举:选出唯一领导者
  2. 日志复制:Leader 接收日志并复制到其他节点
  3. 安全性:确保所有节点最终一致
节点状态
  • 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;
    }
}

关键要点

  1. 理解 CAP 权衡:强一致性需要牺牲可用性,根据业务需求选择
  2. 超时机制必不可少:避免资源长时间锁定
  3. 幂等设计:重试操作必须幂等
  4. 监控告警:及时发现一致性问题
  5. 人工介入机制:极端情况下的兜底方案

六、思考与练习

思考题

  1. 基础题:两阶段提交(2PC)为什么会出现阻塞问题?三阶段提交(3PC)是如何改进的?
  2. 进阶题:Paxos协议中,为什么需要多数派(Quorum)才能达成共识?如果网络分区发生,Paxos如何保证安全性?
  3. 实战题:在一个电商系统中,订单服务和库存服务分别部署在不同机房,如何设计强一致性的库存扣减方案?

编程练习

练习:基于Raft协议实现一个简单的分布式键值存储系统,要求:

  1. 支持SET/GET/DELETE操作
  2. Leader选举和日志复制
  3. 客户端请求转发到Leader

章节关联

  • 前置章节:《分布式系统基础概念》
  • 后续章节:《最终一致性方案详解》
  • 扩展阅读:Lamport《Paxos Made Simple》、Raft论文《In Search of an Understandable Consensus Algorithm》

📝 下一章预告

下一章将探讨最终一致性方案,学习如何在允许短暂不一致的前提下,实现更高性能和可用性的分布式系统,包括事件溯源、CQRS、Saga模式等核心内容。


本章完