目录

syntax="proto2";
package example;
option cc_generic_services = true;

message BlockRequest {
    required int64 offset = 1;
    optional int32 size = 2;
}

message BlockResponse {
    required bool success = 1;
    optional string redirect = 2;
}

service BlockService {
    rpc write(BlockRequest) returns(BlockResponse);
    rpc read(BlockRequest) returns(BlockResponse);
};

server

类关系

classDiagram class Block { -Node* _node -int64_t _leader_term -SharedFD* _fd +start() +write() +read() +shutdown() +join() } class BlockServiceImpl { -Block* _block +write() +read() } class BlockClosure { -Block* _block -BlockRequest* _request -BlockResponse* _response -butil::IOBuf* _data -google::protobuf::Closure* _done +BlockClosure(Block*, BlockRequest*, BlockResponse*, IOBuf*, Closure*) +~BlockClosure() +const BlockRequest* request() +BlockResponse* response() +butil::IOBuf* data() +void Run() } class braft_Closure { <<interface>> +Run()* } BlockClosure --|> braft_Closure BlockServiceImpl --> Block BlockClosure --> Block
graph TD A[main函数] --> B[创建Block实例] B --> C[创建BlockServiceImpl] C --> D[启动BRPC Server] D --> E[启动Block服务] E --> F[等待退出信号] F --> G[关闭服务]

Block类

主要作用

graph TD A[Block类] --> B[状态机管理] A --> C[数据读写] A --> D[快照管理] B --> B1[Leader选举] B --> B2[状态同步] C --> C1[写操作] C --> C2[读操作] D --> D1[保存快照] D --> D2[加载快照]

uml类图

classDiagram class StateMachine { <<interface>> +on_apply(Iterator& iter)* +on_shutdown() +on_snapshot_save(SnapshotWriter*, Closure*) +on_snapshot_load(SnapshotReader*) +on_leader_start(int64_t term) +on_leader_stop(Status&) +on_error(Error&) +on_configuration_committed(Configuration&) +on_stop_following(LeaderChangeContext&) +on_start_following(LeaderChangeContext&) } class Block { -butil::Mutex _fd_mutex -braft::Node* volatile _node -butil::atomic<int64_t> _leader_term -scoped_fd _fd +Block() +~Block() +int start() +void write(BlockRequest*, BlockResponse*, IOBuf*, Closure*) +void read(BlockRequest*, BlockResponse*, IOBuf*) +bool is_leader() +void shutdown() +void join() -void redirect(BlockResponse*) #void on_apply(Iterator&) #void on_snapshot_save(SnapshotWriter*, Closure*) #int on_snapshot_load(SnapshotReader*) #void on_leader_start(int64_t) #void on_leader_stop(Status&) #void on_shutdown() #void on_error(Error&) #void on_configuration_committed(Configuration&) #void on_stop_following(LeaderChangeContext&) #void on_start_following(LeaderChangeContext&) } class SharedFD { -int _fd +explicit SharedFD(int fd) +int fd() -~SharedFD() } class SnapshotArg { +scoped_fd fd +SnapshotWriter* writer +Closure* done } Block --|> StateMachine Block *-- SharedFD Block *-- SnapshotArg

主要功能流程

写入流程:

sequenceDiagram Client->>BlockServiceImpl: write请求 BlockServiceImpl->>Block: 转发请求 Block->>RAFT: 提交日志 RAFT-->>Block: 应用日志 Block->>Storage: 写入数据 Block-->>Client: 返回结果

sequenceDiagram Client->>BlockServiceImpl: read请求 BlockServiceImpl->>Block: 转发请求 Block->>Block: 检查是否Leader Block->>Storage: 读取数据 Block-->>Client: 返回数据

BlockClosure 类

这个类在整个系统中扮演着重要的桥接角色,它将异步的RAFT操作与RPC请求响应关联起来,并确保资源的正确释放。

主要职责

生命周期

sequenceDiagram participant Client participant Block participant BlockClosure participant RAFT Client->>Block: 发起写请求 Block->>BlockClosure: 创建Closure Block->>RAFT: 提交任务 RAFT-->>BlockClosure: 调用Run() BlockClosure-->>Client: 返回结果 Note over BlockClosure: 自动销毁

要点

  • 一致性保证:
    • 写操作必须通过RAFT日志复制
    • 读操作只在Leader节点处理
    • 支持Leader切换和重定向
  • 快照机制:
    • 定期保存状态机快照
    • 支持快照恢复
    • 通过硬链接优化快照存储
  • 错误处理:
    • 支持请求重定向
    • 磁盘错误处理
    • Leader切换通知
graph LR A[配置项] --> B[端口] A --> C[选举超时] A --> D[快照间隔] A --> E[数据目录] A --> F[集群配置]

tricks

expected_term避免ABA问题

  1. 请求只能在发起时的term中被处理
  • 如果节点经历了Leader身份变化,即使term值相同,请求也会被拒绝
  • 客户端可以重试请求,确保在正确的Leader上处理

这样就有效避免了ABA问题带来的数据一致性风险。

让我解释一下RAFT中的ABA问题以及为什么设置expected_term可以避免它:

sequenceDiagram participant C as Client participant N1 as Node1(Term=1) participant N2 as Node2 participant N3 as Node3 Note over N1: 初始Leader C->>N1: 写请求(term=1) Note over N1: 失去Leader地位 Note over N2: 成为Leader(term=2) Note over N1: 重新成为Leader(term=3) Note over N1: 继续处理之前的请求

不设置expected_term时的ABA问题:

sequenceDiagram participant Client participant Node as Node(Leader) Note over Node: Term=1 (A状态) Client->>Node: 发送写请求 Note over Node: Term变为2 (B状态) Note over Node: Term重新变为1 (A状态) Note over Node: 继续处理旧请求 Note right of Node: 危险!请求可能在错误的term被处理

设置expected_term后:

sequenceDiagram participant Client participant Node as Node(Leader) Note over Node: Term=1 Client->>Node: 发送写请求(expected_term=1) Note over Node: Term变为2 Note over Node: Term重新变为1 Note over Node: 检查expected_term Node-->>Client: 拒绝请求(term不匹配)

解释:

    • 可能导致旧请求在新的term中被错误处理
    • 违反RAFT的安全性保证
    • 可能导致数据不一致
    • expected_term如何解决
    • 记录发送请求时的term
    • 处理请求时检查当前term是否与expected_term相同
    • 即使term值相同,只要中间发生过变化,term的历史就不同
    • 通过比较确保请求只能在原始term中处理

    内存序参数使用

    graph TD A[内存序类型] --> B[Relaxed] A --> C[Acquire] A --> D[Release] B --> B1[最宽松的内存序] B --> B2[只保证原子性] B --> B3[不提供同步] C --> C1[读取操作使用] C --> C2[保证后续读写不会重排到acquire之前] D --> D1[写入操作使用] D --> D2[保证之前的读写不会重排到release之后]

    memory_order_relaxed的使用

    const int64_t term = _leader_term.load(butil::memory_order_relaxed);

    在write()函数中使用

      memory_order_acquire的使用

      bool is_leader() const { 
          return _leader_term.load(butil::memory_order_acquire) > 0; 
      }
      
      • 在检查leader状态时使用
      • 确保读取到leader状态后,能看到之前所有的写入
      • 防止后续操作重排到这个读取之前

      void on_leader_start(int64_t term) {
          _leader_term.store(term, butil::memory_order_release);
          LOG(INFO) << "Node becomes leader";
      }
      
      • 在更改leader状态时使用
      • 确保之前的所有写入对其他线程可见
      • 防止之前的操作重排到这个写入之后

      同步关系示意:

      sequenceDiagram participant T1 as Thread1 participant M as Memory participant T2 as Thread2 Note over T1,T2: Release-Acquire 配对 T1->>M: store(term, release) Note over T1: 所有之前的写入 Note over T1: 不能重排到此后 M->>T2: load(acquire) Note over T2: 所有后续的读写 Note over T2: 不能重排到此前

      使用这些内存序的原因:

      1. 正确性保证

      graph LR A[Leader变更] --> B[Release写入] B --> C[Acquire读取] C --> D[后续操作] E[普通检查] --> F[Relaxed读取]
      1. 性能考虑
      graph TD A[内存序强度] --> B[性能开销] B --> C[Relaxed<Release/Acquire<Seq_cst]