6.824 Lab 3: Fault-tolerant Key/Value Service Part-A

Introduction

該實(shí)驗(yàn)是mit 6.824課程的第3個(gè)實(shí)驗(yàn)椿肩,基于raft協(xié)議完成一個(gè)key-value系統(tǒng)

實(shí)驗(yàn)分為A和B兩個(gè)部分,在Part A中:我們不考慮日志的大小,在Part B中會(huì)完成快照功能

完整的代碼地址
課程地址
實(shí)驗(yàn)地址
已經(jīng)有的實(shí)驗(yàn)地址:
Lab 1: MapReduce6.824 Lab 1: MapReduce(2016)
Lab 2: Raftraft 系列解讀(2) 之 測(cè)試用例
Lab 3: KV Raft Part-A6.824 Lab 3: Fault-tolerant Key/Value Service Part-A

Part A: Key/value service without log compaction

支持3個(gè)操作

Put(key, value):改變key的值

Append(key, arg):給key的值新增value

Get(key):返回值

任務(wù)

當(dāng)沒有丟包和servers fail的情況下進(jìn)行實(shí)現(xiàn),需要提供客戶端順序一致性的api,調(diào)用Put落蝙,Append和Get3個(gè)api,在所有的server以相同的順序執(zhí)行暂幼,并且具有at-most-once的語義

一個(gè)建議的計(jì)劃是:先完成server.go中的Op結(jié)構(gòu)筏勒,然后完成server.go中的PutAppend()Get()操作,在操作中旺嬉,應(yīng)該先調(diào)用Start()管行,當(dāng)日志commit的時(shí)候,回復(fù)客戶端

提示

  1. 調(diào)用Start()后邪媳,kvraft servers 會(huì)等待raft log達(dá)成一致病瞳,通過applyCh獲取一致的命令,我們需要考慮怎么安排代碼悲酷,才能持續(xù)讀取applyCh套菜,而其他命令也能執(zhí)行
  2. 我們需要處理case:leader調(diào)用了Start(),但是在log commit之前设易,丟失了leadership逗柴,這種情況下,代碼應(yīng)該將請(qǐng)求重新發(fā)送給新的leader顿肺。一種方式是戏溺,server需要檢測(cè)出自己已經(jīng)不是leader了,通過查看相同的start在index上返回一個(gè)不用的請(qǐng)求屠尊,另一種方式是通過調(diào)用GetState()旷祸,但是如果出現(xiàn)網(wǎng)絡(luò)分區(qū),可能不知道自己已經(jīng)不是leader了讼昆,這種情況下client和server都處在網(wǎng)絡(luò)分區(qū)中托享,因此可以無限的等待下去,直到網(wǎng)絡(luò)恢復(fù)
  3. A kvraft server不應(yīng)該完成Get()操作如果得不到majority浸赫,因?yàn)檫@樣子可能會(huì)得不到最新的數(shù)據(jù)

任務(wù):

需要處理重復(fù)請(qǐng)求闰围,保證滿足at-most-once的語義

提示:

  1. 需要對(duì)每個(gè)client請(qǐng)求編號(hào)
  2. 要保證快速的釋放內(nèi)存,因此可以在下一個(gè)請(qǐng)求帶上下一個(gè)請(qǐng)求

實(shí)際設(shè)計(jì)中出現(xiàn)的問題

頻繁變化leader

func (ck *Clerk) Get(key string) string {

   args := GetArgs{Key:key}

   for {

      for _,c := range ck.servers {

         time.Sleep(time.Millisecond*1000)

         reply := GetReply{}

         ok := c.Call("RaftKV.Get", &args, &reply)

         if ok && !reply.WrongLeader {

            return reply.Value

         }

      }

   }

   // You will have to modify this function.

   return ""

}

此處如果沒有sleep的話既峡,相當(dāng)于客戶端一直不斷的在START羡榴,導(dǎo)致的一個(gè)問題是:server不斷在處理START命令,導(dǎo)致正常的心跳都完成不了了运敢,就出現(xiàn)了頻繁的變化leader了校仑,問題很嚴(yán)重忠售,那應(yīng)該怎么做呢?

后來做了優(yōu)化迄沫,對(duì)于讀操作不走 chan稻扬,這就沒問題了

index := -1

term := -1

isLeader := true

if rf.state != StateLeader {

   isLeader = false

   return index, term, isLeader

}

這樣就有個(gè)初判斷了

通過labrpc傳遞的數(shù)據(jù)不對(duì)

func StartKVServer(servers []*labrpc.ClientEnd, me int, persister *raft.Persister, maxraftstate int) *RaftKV {

   // call gob.Register on structures you want

   // Go's RPC library to marshall/unmarshall.

   gob.Register(Op{})

如果沒有 gob.Register(Op{}) 這就錯(cuò)誤,為什么要加上這句話呢邢滑?

出現(xiàn)阻塞

分析:此處阻塞了為什么呢?因?yàn)樵趃et上的時(shí)候愿汰,有一個(gè)沒有收到apply困后?好奇怪

// TODO:優(yōu)化超時(shí)的邏輯

select {

case op := <-ch:

   commited := op == entry

   kv.logger.Debug("index:%d commited:%v",index,commited)

   return commited

case <- time.After(AppendTimeOut):

   kv.logger.Info("index:%d %s timeout after %v",index, entry.Type,AppendTimeOut)

   return false

}

加上上面的超時(shí)邏輯后,就可以解決阻塞的問題衬廷,但是一旦超時(shí)

2016/10/26 14:37:45 I index:323 Append timeout after 1s

2016/10/26 14:37:45 0: client new get 0

2016/10/26 14:37:45 get wrong value, key 0, wanted:

就會(huì)出現(xiàn)問題摇予,會(huì)重復(fù)執(zhí)行 Append操作,因?yàn)槠鋵?shí)已經(jīng)apply了這個(gè)請(qǐng)求了

那怎么解決呢吗跋?我現(xiàn)在去除這個(gè)超時(shí)限制侧戴,在獲取Apply的時(shí)候邏輯變?yōu)橄旅娴模?/p>

// 通知結(jié)果

ch, ok := kv.result[index]

if ok {

   select {

   case <-ch:

   default:

   }

}else {

   // 沒人讀就有了數(shù)據(jù)?

   ch = make(chan Op,1)

   kv.result[index] = ch

}

ch <- op

此時(shí)就不會(huì)有超時(shí)的問題了跌宛,為什么呢酗宋?

很反人類的問題:因?yàn)楫?dāng)調(diào)用



func (kv *RaftKV)AppendLog(entry Op) bool {

   index, _, isLeader := kv.rf.Start(entry)

此時(shí)可能沒等到執(zhí)行下面的去讀chan的時(shí)候,已經(jīng)apply成功了疆拘,因此我們就需要事先往chan里面存入數(shù)據(jù)

TestUnreliable

?  kvraft [master] ? go test -run TestUnreliable

Test: unreliable ...

2016/10/26 14:59:42 get wrong value, key 3, wanted:

x 3 0 yx 3 1 y

, got

x 3 0 yx 3 0 yx 3 1 y

很容易看出問題:一個(gè)請(qǐng)求重復(fù)執(zhí)行了蜕猫,我們需要在客戶端去重

對(duì)于每個(gè)客戶端都給編號(hào),然后每個(gè)請(qǐng)求都順序增長(zhǎng)

TestManyPartitionsManyClients

測(cè)試出現(xiàn)阻塞

select {

case op := <-ch:

   commited := op == entry

   kv.logger.Debug("index:%d commited:%v", index, commited)

   return commited

   // 此處超時(shí)其實(shí)也很好理解哎迄,因?yàn)閯傞_始是leader回右,但是在log得到commit之前,丟失了leadership漱挚,此時(shí)

   // 如果沒有超時(shí)機(jī)制翔烁,則會(huì)一直阻塞下去

   // 或者由于此時(shí)的leader是一個(gè)分區(qū)里面的leader,則只可能一直阻塞下去了

   // 因此也需要超時(shí)

case <-time.After(AppendTimeOut):

   //kv.logger.Info("index:%d %s timeout after %v", index, entry.Type, AppendTimeOut)

   return false

}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末旨涝,一起剝皮案震驚了整個(gè)濱河市蹬屹,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌白华,老刑警劉巖哩治,帶你破解...
    沈念sama閱讀 218,525評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異衬鱼,居然都是意外死亡业筏,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門鸟赫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蒜胖,“玉大人消别,你說我怎么就攤上這事√ㄐ唬” “怎么了寻狂?”我有些...
    開封第一講書人閱讀 164,862評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)朋沮。 經(jīng)常有香客問我蛇券,道長(zhǎng),這世上最難降的妖魔是什么樊拓? 我笑而不...
    開封第一講書人閱讀 58,728評(píng)論 1 294
  • 正文 為了忘掉前任纠亚,我火速辦了婚禮,結(jié)果婚禮上筋夏,老公的妹妹穿的比我還像新娘蒂胞。我一直安慰自己,他們只是感情好条篷,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,743評(píng)論 6 392
  • 文/花漫 我一把揭開白布骗随。 她就那樣靜靜地躺著,像睡著了一般赴叹。 火紅的嫁衣襯著肌膚如雪鸿染。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,590評(píng)論 1 305
  • 那天乞巧,我揣著相機(jī)與錄音牡昆,去河邊找鬼。 笑死摊欠,一個(gè)胖子當(dāng)著我的面吹牛丢烘,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播些椒,決...
    沈念sama閱讀 40,330評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼播瞳,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了免糕?” 一聲冷哼從身側(cè)響起赢乓,我...
    開封第一講書人閱讀 39,244評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎石窑,沒想到半個(gè)月后牌芋,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,693評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡松逊,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,885評(píng)論 3 336
  • 正文 我和宋清朗相戀三年躺屁,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片经宏。...
    茶點(diǎn)故事閱讀 40,001評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡犀暑,死狀恐怖驯击,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情耐亏,我是刑警寧澤徊都,帶...
    沈念sama閱讀 35,723評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站广辰,受9級(jí)特大地震影響暇矫,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜择吊,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,343評(píng)論 3 330
  • 文/蒙蒙 一李根、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧干发,春花似錦朱巨、人聲如沸史翘。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)琼讽。三九已至必峰,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間钻蹬,已是汗流浹背吼蚁。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留问欠,地道東北人肝匆。 一個(gè)月前我還...
    沈念sama閱讀 48,191評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像顺献,于是被迫代替她去往敵國(guó)和親旗国。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,955評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容