[MIT6.824] Lab 3: Fault-tolerant Key/Value Service
目标
通过在Lab2中实现的Raft库,构建一个可容灾的KV数据库。
需要实现的服务有三种操作:
-
Put(key, value)key和value都是string,put设置指定key的value. -
Append(key, arg)将arg append到key对应的value。上,如果没有该key,相当于put操作。 -
Get(key)返回值,如果没有该key,返回空字符串。
strong consistency
If called one at a time, the Get/Put/Append methods should act as if the system had only one copy of its state, and each call should observe the modifications to the state implied by the preceding sequence of calls.
需要实现linearizability.
实验介绍:
This lab has two parts. In part A, you will implement the service without worrying that the Raft log can grow without bound. In part B, you will implement snapshots
在A中实现基本功能, B中实现快照。
We supply you with skeleton code and tests in
src/kvraft. You will need to modifykvraft/client.go,kvraft/server.go, and perhapskvraft/common.go.
Part A: Key/value service without snapshots
Each of your key/value servers (“kvservers”) will have an associated Raft peer.
每个kv服务器对应一个raft peer。
Clerks send
Put(),Append(), andGet()RPCs to the kvserver whose associated Raft is the leader.
clerk 将请求发送给raft leader之上的kvserver。然后kvserver将operation的log交给raft leader(通过之前的start)。
All of the kvservers execute operations from the Raft log in order, applying the operations to their key/value databases
回想之前的applymsg,kvserver通过raft,获取apply的log,并应用到kv数据库中。
A
Clerksometimes doesn’t know which kvserver is the Raft leader. If theClerksends an RPC to the wrong kvserver, or if it cannot reach the kvserver, theClerkshould re-try by sending to a different kvserver.
Clerk可能判断错误谁是raft的leader,如果发错了rpc,应当充实。
If the key/value service commits the operation to its Raft log (and hence applies the operation to the key/value state machine), the leader reports the result to the
Clerkby responding to its RPC.
需要commit才能返回clerk的RPC.
If the operation failed to commit (for example, if the leader was replaced), the server reports an error, and the
Clerkretries with a different server.
如果没有commit,应当report error(我认为此处是RPC携带错误信息)。
Your kvservers should not directly communicate; they should only interact with each other through Raft.
kvserver之前不应当直接交流,而是通过Raft库。(类似于网络分层)。
You’ll need to add RPC-sending code to the Clerk Put/Append/Get methods in
client.go, and implementPutAppend()andGet()RPC handlers inserver.go. These handlers should enter anOpin the Raft log usingStart();
在server.go中实现RPC的handler。
you should fill in the
Opstruct definition inserver.goso that it describes a Put/Append/Get operation. Each server should executeOpcommands as Raft commits them, i.e. as they appear on theapplyCh. An RPC handler should notice when Raft commits itsOp, and then reply to the RPC.
当raft提交op时,返回给RPC。
Client
You have completed this task when you reliably pass the first test in the test suite: “One client”.
在没有网络问题的情况下,首先开始实现只有一个客户端的测试了=。
首先看测试用例
func TestBasic3A(t *testing.T) {
// Test: one client (3A) ...
GenericTest(t, "3A", 1, 5, false, false, false, -1, false)
}
开启一个客户端,5个服务器,没有RPC fail的情况,服务器不会崩溃,没有网络分区,不需要快照。
在测试里面,通过Append,Get(),Put()函数调用clerk的对应函数,并记录相应的log.
func Get(cfg *config, ck *Clerk, key string, log *OpLog, cli int) string {
start := time.Now().UnixNano()
v := ck.Get(key)
end := time.Now().UnixNano()
cfg.op()
if log != nil {
log.Append(porcupine.Operation{
Input: models.KvInput{
Op: 0, Key: key},
Output: models.KvOutput{
Value: v},
Call: start,
Return: end,
ClientId: cli,
})
}
return v
}
那么首先实现client.go/Clerk中的对应接口。
func (ck *Clerk) Get(key string) string {
// You will have to modify this function.
commandId := ck.lastAppliedCommandId + 1
args := GetArgs{
Key: key,
ClientId: ck.clientId,
CommandId: commandId,
}
serverId := ck.lastFoundLeader
serverNum := len(ck.servers)
for ;<


1069

被折叠的 条评论
为什么被折叠?



