前言
在前面的三次学习中,我们学习了一些重要的数据结构,今天主要探讨一下重要的接口,这些接口使得整个raft得以健康地运行。
Node
Node接口承载了应用层与raft协议层的桥梁这个角色,相互传递消息和命令。
// Node represents a node in a raft cluster.
type Node interface {
// Tick 主要传递应用层的心跳和选举给raft协议层
Tick()
// Campaign 致使节点状态转换到候选状态并开始竞选成为领导者
Campaign(ctx context.Context) error
// Propose 上传用户的数据给raft协议层,这个接口可以接收额外的消息错误消息
//if wait {
// pm.result = make(chan error, 1)
//}
Propose(ctx context.Context, data []byte) error
// ProposeConfChange proposes a configuration change. Like any proposal, the
// configuration change may be dropped with or without an error being
// returned. In particular, configuration changes are dropped unless the
// leader has certainty that there is no prior unapplied configuration
// change in its log.
//
// The method accepts either a pb.ConfChange (deprecated) or pb.ConfChangeV2
// message. The latter allows arbitrary configuration changes via joint
// consensus, notably including replacing a voter. Passing a ConfChangeV2
// message is only allowed if all Nodes participating in the cluster run a
// version of this library aware of the V2 API. See pb.ConfChangeV2 for
// usage details and semantics.
ProposeConfChange(ctx context.Context, cc pb.ConfChangeI) error
// Step 上报消息给状态机,通过context返回错误
Step(ctx context.Context, msg pb.Message) error
// Ready 返回当前的状态信息给应用层
Ready() <-chan Ready
// Advance 通知该节点的raft,应用层已经保存了上一个Ready,可以返回下一个ready内容了。
Advance()
// ApplyConfChange applies a config change (previously passed to
// ProposeConfChange) to the node. This must be called whenever a config
// change is observed in Ready.CommittedEntries, except when the app decides
// to reject the configuration change (i.e. treats it as a noop instead), in
// which case it must not be called.
//
// Returns an opaque non-nil ConfState protobuf which must be recorded in
// snapshots.
ApplyConfChange(cc pb.ConfChangeI) *pb.ConfState
// TransferLeadership 切主,由lead切为transferee
TransferLeadership(ctx context.Context, lead, transferee uint64)
// ReadIndex request a read state. The read state will be set in the ready.
// Read state has a read index. Once the application advances further than the read
// index, any linearizable read requests issued before the read request can be
// processed safely. The read state will have the same rctx attached.
// Note that request can be lost without notice, therefore it is user's job
// to ensure read index retries.
ReadIndex(ctx context.Context, rctx []byte) error
// Status 返回当前raft的状态
Status() Status
// ReportUnreachable 报告当前给与的节点不可达
ReportUnreachable(id uint64)
// ReportSnapshot 报告当前的发送的快照信息,谁发送谁接受,成功还是失败,失败原因。
// reports the status of the sent snapshot. The id is the raft ID of the follower
// who is meant to receive the snapshot, and the status is SnapshotFinish or SnapshotFailure.
// Calling ReportSnapshot with SnapshotFinish is a no-op. But, any failure in applying a
// snapshot (for e.g., while streaming it from leader to follower), should be reported to the
// leader with SnapshotFailure. When leader sends a snapshot to a follower, it pauses any raft
// log probes until the follower can apply the snapshot and advance its state. If the follower
// can't do that, for e.g., due to a crash, it could end up in a limbo, never getting any
// updates from the leader. Therefore, it is crucial that the application ensures that any
// failure in snapshot sending is caught and reported back to the leader; so it can resume raft
// log probing in the follower.
ReportSnapshot(id uint64, status SnapshotStatus)
// Stop 停止当前节点
Stop()
}
Storage
代表Raft日志底层存储模块,保存持久化的数据,它提供了持久化日志相关的接口操作,如果有一个接口方法错误,这个raft实例将无法操作和拒绝参与选举,应用负责清理和恢复这个状态。
// Storage is an interface that may be implemented by the application to retrieve log entries from storage.
type Storage interface {
// TODO(tbg): split this into two interfaces, LogStorage and StateStorage.
// InitialState 返回持久化的HardState和ConfState信息。
InitialState() (pb.HardState, pb.ConfState, error)
// Entries 返回日志片段,包括lo,不包括high.
Entries(lo, hi, maxSize uint64) ([]pb.Entry, error)
// Term 返回一条日志记录的任期,这条日志必须在[FirstIndex()-1, LastIndex()].
Term(i uint64) (uint64, error)
// LastIndex 返回日志记录中的最后一条记录的index
LastIndex() (uint64, error)
// FirstIndex 返回日志记录中的第一条日志;
FirstIndex() (uint64, error)
// Snapshot 返回最近的快照,如果快照临时不可用,应该返回 ErrSnapshotTemporarilyUnavailable, 从而raft知道状态机能够知道Storage 需要一些时间来准备快照,并稍后调用
Snapshot() (pb.Snapshot, error)
}