分佈式系統——Raft的實現

接上一個對於Raft的分析,這是文章的鏈接地址:https://blog.csdn.net/karry_zzj/article/details/102943617
我們這一文章主要分析一下我們的作業的代碼。

作業主要就是在一個框架下實現相關算法。

論文中提供了一張簡要的raft算法總結圖(論文figure 2),可以作爲我們代碼實現的指導。

從這張圖我們可以具體分析一下有如下幾個主要內容:

  • State:即服務器的狀態
  • RequestVote RPC:投票請求的RPC
  • AppendEntries RPC:附加日誌的RPC
  • Rules for Servers:服務器的規則

等會我們具體來分析。


項目結構

首先我們來看一下這個作業項目的結構:

其中我們主要用到如下文件:

  • labrpc 文件夾下的 labrpc.go, test_test.go
  • raft 文件夾下的 config.goraft.go

我們首先打開test_test.go 文件,我們可以發現有如下函數,而此函數就是整個項目測試leader election的入口處

func TestInitialElection(t *testing.T) {
	servers := 3
	cfg := make_config(t, servers, false)
	defer cfg.cleanup()

	fmt.Printf("Test: initial election ...\n")

	// is a leader elected?
	cfg.checkOneLeader()

	// does the leader+term stay the same there is no failure?
	term1 := cfg.checkTerms()
	time.Sleep(2 * RaftElectionTimeout)
	term2 := cfg.checkTerms()
	if term1 != term2 {
		fmt.Printf("warning: term changed even though there were no failures")
	}

	fmt.Printf("  ... Passed\n")
}

我們看到有這一行代碼:

cfg := make_config(t, servers, false)

當我們點進去make_config這個函數,其實就進入到了 config.go 這個文件中。

其中有三行是創建 Rafts :

	// create a full set of Rafts.
	for i := 0; i < cfg.n; i++ {
		cfg.logs[i] = map[int]int{}
		cfg.start1(i)
	}

我們再點進去 start1 這個函數,發現有這樣的一行:

rf := Make(ends, i, cfg.saved[i], applyCh)

而這個Make函數就是在 raft.go 文件中寫的,所以我們這樣便知道了整個項目的一個運行流程:

TestInitialElection
make_config
start1
Make

而Make就是我們需要寫的一個函數,其中需要gorutine進行leader election。

Raft State

論文figure2 中有標註了State的參數:

那麼我們首先要在 Raft 結構體中加入如下參數,代碼如下:

//
// A Go object implementing a single Raft peer.
//
type Raft struct {
	mu        sync.Mutex
	peers     []*labrpc.ClientEnd
	persister *Persister
	me        int // index into peers[]
	// Your data here.
	// Look at the paper's Figure 2 for a description of what
	// state a Raft server must maintain.
	state		State       // Raft的狀態
	leaderid    int
	// Persistent state on all servers:
	currentTerm int         // 服務器最後知道的任期號
	votedFor 	int			// 在當前任期內收到選票的候選人 id
	logs	    []LogEntry  // 日誌條目: 每個條目包含狀態機的要執行命令和從領導人處收到時的任期號

	// Volatile state on all servers:
	commitIndex int // 已知的被提交的最大日誌條目的索引值
	lastApplied int // 被狀態機執行的最大日誌條目的索引值

	// Volatile state on leaders
	nextIndex  []int // 對於每一個服務器,記錄需要發給它的下一個日誌條目的索引
	matchIndex []int // 對於每一個服務器,記錄已經複製到該服務器的日誌的最高索引值

	// two timeout settings which control elections
	electionTimeout  int
	heartbeatPeriod int

	latestIssueTime	int64		// 最新的leader發送心跳的時間
	latestHeardTime	int64		// 最新的收到leader的AppendEntries RPC(包括heartbeat)

	//snapshottedIndex int
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章