2020 6.824 的 Raft Lab 4A

前言

做2020的MIT6.824,完成了实验 Lab4A,通过了测试,对于之前的Raft实现的实验请参考Lab 2ALab 2BLab 2CLab 3A 以及 Lab 3B

Lab4A主要是做DB的分片,也就是Client向Server请求,Server根据不同的Request类型,向不同的DB获取/更改数据。实验重点需要完成master对DB server的Join/Leave/Move的三个操作,并且实验Client对Server的configs查询的操作。

整个实验有三个点需要注意

  1. load balance的算法
  2. config需要拷贝而不是引用
  3. labgob需要注册JoinArgs,LeaveArgs,MoveArgs 和 QueryArgs

一、Overview

1.1 架构图

实验是通过数据库分片来提升性能的,Master负责数据库的分片,大概架构如下
在这里插入图片描述

1.2 架构细节

第一,对于本次分片来说,最多可以有10个Group,这里Common文件可以看出来

// The number of shards.
const NShards = 10

第二,对于Master来说,也是有多个servers的,所以需要通过Raft保证shards configuration的一致性,从config可以看出来,一个有三个属性需要维护的,其中Shards就是分片configuration, 初始是[0,0,0,0,0,0,0,0,0,0],Groups就是对应每个shard分片中Raft servers的information,比如Group1 -> server[a, b, c]

type Config struct {
   
	Num    int              // config number
	Shards [NShards]int     // shard -> gid
	Groups map[int][]string // gid -> servers[]
}

举个例子,shards初始为[0,0,0,0,0,0,0,0,0,0],那么Join了Group1 -> servers[a, b, c] 之后,整个系统就有1个Group了,那么,shards就会变成[1,1,1,1,1,1,1,1,1,1],如果JoinGroup2 -> servers[e, f, g]之后,整个系统就有2个groups了,那么,10个shards就需要尽量平均分配给两个Groups,也就是[1,1,1,1,1,2,2,2,2,2]

这里也就是涉及到了load balance的算法,我的算法实现参考了 网上 的方法,并没有用到高级的数据结构比如heap来实现


二、client

这个跟kvraft中client的实现非常相似,基本搬过来就行

其中,Clerk的构造函数

type Clerk struct {
   
	servers []*labrpc.ClientEnd

	mu         sync.Mutex
	leaderId   int
	clientId   int64
	sequenceId int64

	// Your data here.
}
func MakeClerk(servers []*labrpc.ClientEnd) *Clerk {
   
	ck := new(Clerk)
	ck.servers = servers
	// Your code here.
	ck.clientId = nrand()
	return ck
}

增加一些新的属性, 主要就是ClientId很SequenceId

type JoinArgs struct {
   
	Servers    map[int][]string // new GID -> servers mappings
	ClientId   int64
	SequenceId int64
}

type LeaveArgs struct {
   
	GIDs       []int
	ClientId   int64
	SequenceId int64
}

type MoveArgs struct {
   
	Shard      int
	GID        int
	ClientId   int64
	SequenceId int64
}

type QueryArgs struct {
   
	Num        int // desired config number
	ClientId   int64
	SequenceId int64
}

Join/Move/Leave/Query 的实现,对于Join/Move/Leave 基本都是一样的

func (ck *Clerk) Query(num int) Config {
   
	args := &QueryArgs{
   }
	// Your code here.
	args.Num = num
	args.ClientId = ck.clientId
	args.SequenceId = atomic.AddInt64(&ck.sequenceId, 1)

	for {
   
		reply := QueryReply{
   }
		if ck.servers[ck.currentLeader()].Call("ShardMaster.Query", args, &reply) && !reply.WrongLeader {
   
			return reply.Config
		}
		ck.leaderId = ck.changeLeader()
		time.Sleep(100 * time.Millisecond)
	}
}

func (ck *Clerk) Join(servers map[int][]string) {
   
	args := &JoinArgs{
   }
	args.Servers = servers
	args.ClientId = ck.clientId
	args.SequenceId = atomic.AddInt64(&ck.sequenceId, 1)

	for {
   
		reply := JoinReply{
   }
		if ck.servers[ck.currentLeader()].Call("ShardMaster.Join", args, &reply) && !reply.WrongLeader {
   
			return
		}
		ck.leaderId = ck.changeLeader()
		time.Sleep(100 * time.Millisecond)
	}
}


三、Master server

3

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值