MIT 6.5840 2023 Lab 4 Shard KV Server TaskA, TaskB, Challenge
前言
这波是终于写完了MIT 6.5840 的所有lab了。lab均是独立完成,没有任何参考,哈哈,还是挺有成就感的。lab4其实在上周就已经写完了,不过比较懒,拖了一周才开始写总结。
本次lab4,在所有lab中,个人认为难度仅次于lab2,也就是仅次于Raft。由于是在已经实现lab3的情况下,因此工作量不是特别大。这次的shard分区感觉还是挺有意思的。废话不多说,直接进入正题吧。
一些小细节
其实这次试验,由于有了lab3的经验,思路其实还是比较清晰的。
-
对于TaskA,也就是config服务的实现,和lab3基本没啥区别,而且还没snapshot的要求,因此还是较为简单的。主要需要解决的问题就是如何实现 最少步数 的shard转移。为什么要实现最小呢?这是因为实现了最小步数后,节点之间的转移就必然形成了一个 有向无环图(DAG) 或者 DAG集合,这个性质在TaskB中很重要,因此需要实现 最小。如何实现最小,其实很简单,贪心就行了。每次选择shard数最大的节点Max(server id 升序),以及shard数最小的节点(server id降序),然后将Max中的一个shard转移给Min中的一个shard即可,直到平衡。至于为什么和server id有关,这是因为转移需要确定性,而golang中的map遍历的顺序是不确定的。
-
对于TaskB,Challenge:所有操作无脑写日志搞进Raft里面来实现线性化即可。由于我在一开始考虑了challenge进行设计,因此这里就和Challenge的内容一起简单写了。TaskB中,主要的问题其实就是状态机状态类型的添加(config状态,转移状态等),同时在转移的时候,还需要将节点的幂等性状态一同转移(也就是记录client相关内容,用于识别client重复提交的内容)。要实现Challenge,主要就是要实现转移的分片,我是根据转移目标进行分片,也就是新的config来了之后,我会解析现有config与新config之间的差别从而建立转移规则,然后对于每个目标节点,分别将log塞入raft,最后在commit时进行转移(主从节点均要转移)。有一个小细节,所有节点必须全部经历所有config(从config 0 到 最新的config),不能跨config更新。每次发送时,当前节点对于目标节点就是一个client,用client请求的处理逻辑来处理转移请求即可。client收到(也就是转出节点)转移成功请求后,取消对对应所有shard的服务,从而完成Challenge,同时接收方接收后开始服务Shard。此时,之前提到的幂等性状态的同时转移就很重要了。同时中,由于转移是在commit时完成的,因此在转移过程中需要接锁。同时,TaskA中的 最小 从而实现的 DAG 也在此处避免了分布式死锁。
过多的工程细节这里就不说了,有小伙伴有问题的话可以评论区留言或者私信,我会尽量解答的。(看番去了,润!)