6.584-Lab5B
6.584-Lab5B
- Reference Code
- Reference Blog
- Homework
- Myself Code
Sharded Key/Value Service 梗概

这个图是我从上面参考blog中拿来的,觉得做的不错,借助这张图来讲解一下需要一个什么样的 Service。
ShardCtrler Client:
接收来自客户发出的命令(作业中是test程序/ShardKV Client/Server),四种命令Join/Leave/Move/Query,具体含义看Homework。
shardctrler client 接收到命令后通过 RPC 交给自己下面的 shardctrler cluster/server。
ShardCtrler cluster/server:
接收到来自 shardctrler client 发送包含具体命令的 RPC 后,封装命令并交付给自己下面的 Raft 来实现分布式的一致性。
接着从相应的通道接收 Raft 提交(Appliy)的命令,执行接收到的命令Join/Leave/Move/Query,并生成新的 Configuration。
ShardKV Client:
接收来自客户发出的命令(实际生产中的用户,作业中是test程序),作业中实现的是KV Service 所以命令只包含Put/Get/Append三种命令。
将接收到的命令通过 RPC 交给自己下面的 ShardKV cluster/server。
ShardKV cluster/server:
除了接收来自 shardKV Client 发送来的关于 KV 的三种命令外,还需要定时向 ShardCtrler Client 发送 Query 命令来获取最新的配置,用以得知 Shards 被哪些 group 包含。
Reference Code实现了以下命令:
Shard 的状态有
Serving/GCing/Pulling/BePulling,分别表示为正在服务、垃圾清理、从别的 group 拉取 data、被别的 group 拉取。
applyConfiguration:得到最新的 Configuration 后应用到本地,更新每个 Shard 的状态。每个 shardKV server 会检查新的 Config 中的每个 shard 所处的 Group,如果这个 shard 现在在自己这但新的 Config 中显示在别的 group 中则会将该 shard 标记为BePulling;反之现在不在自己这但新的 Config 显示在自己这则标记为Pulling。applyInsertShards:将标记为BePulling的 shard 插入到应在的 group 中(在新的 Config 会显示),插入完成后原来拥有这个 shard 的 group 会将这个 shard 标记为GCing,后续进行垃圾清理。applyDeleteShards:将被标记为GCing的 shard 清理掉(初始化为一个 NewShard)。applyEmptyShards:当下层的 Raft 进入新的 Term 后,没有任何“命令”作为 log 发送到 Raft的情况下,发送一个空的命令到 Raft,让其作为一个 log 进行占位。
ShardKV cluster/server 发送上述的7种命令到下层的 Raft 层来实现分布式的一致性。等这些命令在下层 Raft “转”一圈后,通过相应的通道接收从 Raft 发来的已经应用(Apply)的命令后再采取相应逻辑执行。
部分代码讲解&踩的坑
以下是我在阅读Reference Code时记录的一些疑问:
Q1:
normal command即 put、get、append是由 Client 发送的;但Configuration/InsertShards/DeleteShards/EmptyShards是从哪里发送的?
A:在server.go启动函数StartServer中,会设置监视器Monitor来定时去看是否需要发送这些命令到函数Execute去进一步执行。
Q2:
Server 中处理normal command即Put/Get/Append命令的函数applyOperation中,判断 Server 是否能处理这个 Command 的函数canServe中为什么分片处于垃圾清理状态仍可以shardstatus == GCing处理这个 Command ?
为什么在server.go的applyInsertShards中,从别的 Shard 加载完 ShardData 后要把状态从Pulling改为GCing?刚拉取完 新的信息就要进行垃圾清理进行清空?
A:
在applyInsertShards中确实是把Pulling之后的 Shard 状态设置为了GCing,但是在后面的垃圾清理函数gcAction中,先查找状态为GCing的 Shard 都位于那些 Gid 中,我们看一下这个查找函数getShardIDsByStatus:可以看到是在旧的 Config 中找到这个 Shard 所处的 Gid。所以传给垃圾清理函数gcAction中的 Gid 就是要删除 shard 的 Gid。举个例子:在 Gid_1 中数组
shard[2].satus = Pulling,Gid_2 中数组shard[2].satus = BePulling,表明 shard2 在 Gid_2 中。此时 Gid_1 已经拉取了 shard2 的 data,Gid_1 中数组shard[2].satus = GCing,在垃圾清理的时候,找到 shard2 在旧的 Config 的位置也就是 Gid_2,把 Gid_2 中的Shard2 = NewShard初始化为一个空的shard。后面在垃圾清理函数gcAction中遇到状态为GCing的 shard 时,会再次改回Serving。
所以虽然 Gid_1 中shard[2].satus = GCing,却找的是要清理的 Shard2 的正确的位置即 Gid_2。所以 Gid_1 中shard[2].satus = GCing表示的不是清理 Gid1 中的 shard2,而表示的是要清理 shard2 之前带过的 Gid2 中的 shard2。所以状态为
GCing的 shard 是刚接收完新的 data,后面也不会被垃圾清理,当然可以处理Put/Get/Append命令。
Q3: server.go中为什么ShardKVa中需要设置一个 lastConfig 字段?
A:在server.go的函数migrationAction()中,可能给出了答案,在执行分片迁移的时候,此时currentConfig已经是下一个最新的 configuration 了,但是分片迁移的任务还是需要位于上个 configuration 的 server 去执行的,才能变为下个 configuration 也就是currentConfig
Q4: 在
server.go的函数migrationAction()中并发时搭配匿名函数的传参方式不同的区别?
A:参考GPT。
- 简单来说,goroutine并发的匿名函数直接使用外部变量(闭包)的话,goroutine中使用的外部变量会被goroutine外部改变:
i是主 goroutine 的变量,而 goroutines 是在独立的线程中执行的。- 当 goroutines 执行时,
i的值可能已经被主循环改变,因此打印的结果可能是多个相同的值或不可预测的值。
func main() {for i := 0; i < 5; i++ {go func() {fmt.Println(i) // 闭包变量}()}time.Sleep(time.Second)
}// OutPUt:
4
4
4
4
4
- 将变量作为参数传递给匿名函数,可以避免闭包问题:
i的值在每次迭代时被复制并传递给匿名函数,因此每个 goroutine 都有自己独立的副本。- 结果是确定的。
func main() {for i := 0; i < 5; i++ {go func(n int) {fmt.Println(n) // 使用传递的参数}(i) // 显式传递 i}time.Sleep(time.Second)
}//OutPut:
0
1
2
3
4
- 通过闭包捕获局部变量的副本
在每次循环中创建一个新的局部变量,并让匿名函数捕获该变量:
- 类似于将变量显式传递,
n是每次循环的局部变量,匿名函数捕获的是该变量的副本。 - 结果也是确定的。
func main() {for i := 0; i < 5; i++ {n := i // 创建新的局部变量go func() {fmt.Println(n)}()}time.Sleep(time.Second)
}OutPut:
0
1
2
3
4
踩的坑/需要注意的点
在 Reference Code 的函数applier中,比较了从 Raft 层接收到命令的开始的Termmessage.CommandTerm与当前 Raft Leader 所处的 TermcurrentTerm。但是我们之前实现的 Raft 传出的命令是没有CommandTerm的字段的,秉持少改动底层实现的 Raft 的原则,我在结构体CommandReply中设置了AppliedTerm字段,将 reply 先传回到函数Execute中,在Execute中保存的有开始传入 Raft 层的 TermstartTerm,这这里进行比较。
在 Reference Code 中的 Raft 层实现了GetRaftStateSize方法用来获取已经持久化的 RaftState 的大小,我在结构体ShardKV中添加了字段persister *raft.Persister用来保存启动函数StartServer传入的persisiter,直接调用官方在 Raft 层中的Persister.RaftStateSize获取已经持久化的 RaftState 的大小。我还像之前参考【香草美人】实现 KVRaft 那样设置了 0.95 的阈值。
运行提交命令后,出现了这样的错误:
在运行到某个地方的时候,底层 Raft 实现的AppendEntries函数出现了PrevLogIndex < lastIncludedIndex的情况,这样两者相减求相对下标的时候,会出现负数的下标索引。我去查看【香草美人】的代码后发现,他更新了代码,判断了这个情况(不知道之前是漏看了,还是后来他更新的)。
在方法
checkEntryInCurrentTermAction添加空 Shard 的时候,要判断一下 Raft Leader 当前的 Term 是否等于最后一条日志log的 Term,若不相等则添加一个空的 Shard。
在【参考代码】中,是在 Raft 层实现了函数rf.HasLogInCurrentTerm()来判断,我底层 Raft 是没有这函数的,不想动 Raft 层的代码,我想rf.currentTerm == rf.log[len(log)-1].Term直接判断的,但是发现在其他文件中访问 Raft 层的话,只能访问 Raft 层实现的方法,不能访问 Raft 层的变量rf.log[]、rf.currentTerm,我也就只好也在 Raft 层实现了【参考代码】的函数rf.HasLogInCurrentTerm().
结果

倒腾了好久终于通过官方测试了。这种分布式程序调试太难了,每个发生顺序都不确定,在一堆的输出日志找 bug 太难了 QAQ。
相关文章:
6.584-Lab5B
6.584-Lab5B Reference CodeReference BlogHomeworkMyself Code Sharded Key/Value Service 梗概 这个图是我从上面参考blog中拿来的,觉得做的不错,借助这张图来讲解一下需要一个什么样的 Service。 ShardCtrler Client: 接收来自客户发出的命…...
OceanBase 的探索与实践
作者:来自 vivo 互联网数据库团队- Xu Shaohui 本文总结了目前我们遇到的痛点问题并通过 OceanBase 的技术方案解决了这些痛点问题,完整的描述了 OceanBase 的实施落地,通过迁移到 OceanBase 实践案例中遇到的问题与解决方案让大家能更好的了…...
安卓调试环境搭建
前言 前段时间电脑重装了系统,最近准备调试一个apk,没想到装环境的过程并不顺利,很让人火大,于是记录一下。 反编译工具下载 下载apktool.bat和apktool.jar 官网地址:https://ibotpeaches.github.io/Apktool/install…...
动画Lottie
Lottie简介 Lottie是一个Airbnb 开发的用于Android,iOS,Web和Windows的库,用于解析使用Bodymovin导出为json的Adobe After Effects动画,并在移动设备和网络上呈现 — GitHub Lottie主要特性 After Effects 兼容性: …...
C++感受14-Hello Object 封装版 - 上
1. 封装即约束——封装和派生、多态的本质区别 一门计算机语言,要如何帮助程序员写出优秀的代码?两个方法:一是给程序员更多能力,二是给程序员更多约束。之前我们学习的派生和多态,更多的是给我们技能,而封…...
网络安全中大数据和人工智能应用实践
传统的网络安全防护手段主要是通过单点的网络安全设备,随着网络攻击的方式和手段不断的变化,大数据和人工智能技术也在最近十年飞速地发展,网络安全防护也逐渐开始拥抱大数据和人工智能。传统的安全设备和防护手段容易形成数据孤岛࿰…...
RISC-V架构下OP-TEE 安全系统实践
安全之安全(security)博客目录导读 本篇博客,我们聚焦RISC-V 2024中国峰会上的RISC-V和OP-TEE结合的一个安全系统实践,来自芯来科技桂兵老师。 关于RISC-V TEE(可信执行环境)的相关方案,如感兴趣可参考R...
40分钟学 Go 语言高并发:【实战】分布式缓存系统
【实战课程】分布式缓存系统 一、整体架构设计 首先,让我们通过架构图了解分布式缓存系统的整体设计: 核心组件 组件名称功能描述技术选型负载均衡层请求分发、节点选择一致性哈希缓存节点数据存储、过期处理内存存储 持久化同步机制节点间数据同步…...
[创业之路-186]:《华为战略管理法-DSTE实战体系》-1-为什么UTStarcom死了,华为却活了,而且越活越好?
目录 前言 一、市场定位与战略选择 二、技术创新能力 三、企业文化与团队建设 四、应对危机的能力 五、客户为中心的理念 六、市场适应性与战略灵活性 七、技术创新与研发投入 八、企业文化与团队建设 九、应对危机的能力 前言 UT斯达康(UTStarcom&#…...
python如何多行注释
在Python中,多行注释通常有两种方式: 使用三个单引号()或三个双引号(""")来创建多行字符串,这可以被用来作为多行注释。这种方式在Python中实际上是创建了一个多行的字符串对象…...
前端工程化面试题目常见
前端工程化面试常见题目包括: • 谈谈你对WebPack的认识。 • Webpack打包的流程是什么? • 说说你工作中几个常用的loader。 • 说说HtmlWebpackPlugin插件的作用。 • Webpack支持的脚本模块规范有哪些? • Webpack和gulp/grunt相比有什么特…...
定点数的乘除运算
原码一位乘法 乘积的符号由两个数的符号位异或而成。(不参与运算)被乘数和乘数均取绝对值参与运算,看作无符号数。乘数的最低位为Yn: 若Yn1,则部分积加上被乘数|x|,然后逻辑右移一位;若Yn0&…...
页面置换算法模拟 最近最久未使用(LRU)算法
最近最久未使用(LRU)算法是一种基于页面访问历史的页面置换算法。它选择最久未使用的页面进行置换。当需要访问一个不在内存中的页面时,如果内存已满,则选择最久未使用的页面进行置换。LRU算法通过记录页面的访问时间戳来判断页面…...
Ubuntu与Centos系统有何区别?
Ubuntu和CentOS都是基于Linux内核的操作系统,但它们在设计理念、使用场景和技术实现上有显著的区别。以下是详细的对比: 1. 基础和发行版本 Ubuntu: 基于Debian,使用.deb包管理系统。包含两个主要版本: LTSÿ…...
RK3568平台开发系列讲解(pinctrl 子系统篇)pinctrl_debug
🚀返回专栏总目录 文章目录 1. Overview2. debug信息2.1 pinctrl-devices2.2. pinctrl-handles2.3. pinctrl-handles3. debug信息3.1. 查看(pinctrl_register_pins)注册了哪些pins3.2. 查看pin groups;3.3. 查看每种functions所占用的gpio groups信息:3.4. pinconf沉淀、…...
避大坑!Vue3中reactive丢失响应式的问题
在vue3中,我们定义响应式数据无非是ref和reactive。 但是有的小伙伴会踩雷!导致定义的响应式丢失的问题。 reactive丢失响应式的情况1(直接赋值) 场景: 1.你定义了一个数据:let datareactive({name:"",age:"" }) 2.然后你…...
springSecurity权限控制
权限控制:不同的用户可以使用不同的功能。 我们不能在前端判断用户权限来控制显示哪些按钮,因为这样,有人会获取该功能对应的接口,就不需要通过前端,直接发送请求实现功能了。所以需要在后端进行权限判断。࿰…...
Pytorch训练固定随机种子(单卡场景和分布式训练场景)
模型的训练是一个随机过程,固定随机种子可以帮助我们复现实验结果。 接下来介绍一个模型训练过程中固定随机种子的代码,并对每条语句的作用都会进行解释。 def seed_reproducer(seed2333):random.seed(seed)os.environ["PYTHONHASHSEED"] s…...
Conda + JuiceFS :增强 AI 开发环境共享能力
Conda 是当前 AI 应用开发领域中非常流行的环境和包管理系统,因其能够简单便捷地创建与系统资源相隔离的虚拟环境广受欢迎。 Conda 支持在不同的操作系统上重建相同的工作环境,但在环境共享复用方面仍存在一些挑战。比如,在不同机器上复用相…...
人工智能-人机交互的机会
目录 引言HCI领域的发展机会人工智能领域的崛起与机会博雅智信的HCI与AI辅导服务结语 引言 在人类科技不断进步的今天,HCI(人机交互)和人工智能(AI)是两个密切相关且充满潜力的领域。HCI研究如何优化人类与计算机之间…...
微信小程序 - 手机震动
一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注:文档 https://developers.weixin.qq…...
安宝特方案丨船舶智造的“AR+AI+作业标准化管理解决方案”(装配)
船舶制造装配管理现状:装配工作依赖人工经验,装配工人凭借长期实践积累的操作技巧完成零部件组装。企业通常制定了装配作业指导书,但在实际执行中,工人对指导书的理解和遵循程度参差不齐。 船舶装配过程中的挑战与需求 挑战 (1…...
Linux 中如何提取压缩文件 ?
Linux 是一种流行的开源操作系统,它提供了许多工具来管理、压缩和解压缩文件。压缩文件有助于节省存储空间,使数据传输更快。本指南将向您展示如何在 Linux 中提取不同类型的压缩文件。 1. Unpacking ZIP Files ZIP 文件是非常常见的,要在 …...
FFmpeg:Windows系统小白安装及其使用
一、安装 1.访问官网 Download FFmpeg 2.点击版本目录 3.选择版本点击安装 注意这里选择的是【release buids】,注意左上角标题 例如我安装在目录 F:\FFmpeg 4.解压 5.添加环境变量 把你解压后的bin目录(即exe所在文件夹)加入系统变量…...
Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement
Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement 1. LAB环境2. L2公告策略2.1 部署Death Star2.2 访问服务2.3 部署L2公告策略2.4 服务宣告 3. 可视化 ARP 流量3.1 部署新服务3.2 准备可视化3.3 再次请求 4. 自动IPAM4.1 IPAM Pool4.2 …...
ubuntu22.04有线网络无法连接,图标也没了
今天突然无法有线网络无法连接任何设备,并且图标都没了 错误案例 往上一顿搜索,试了很多博客都不行,比如 Ubuntu22.04右上角网络图标消失 最后解决的办法 下载网卡驱动,重新安装 操作步骤 查看自己网卡的型号 lspci | gre…...
0x-3-Oracle 23 ai-sqlcl 25.1 集成安装-配置和优化
是不是受够了安装了oracle database之后sqlplus的简陋,无法删除无法上下翻页的苦恼。 可以安装readline和rlwrap插件的话,配置.bahs_profile后也能解决上下翻页这些,但是很多生产环境无法安装rpm包。 oracle提供了sqlcl免费许可,…...
第八部分:阶段项目 6:构建 React 前端应用
现在,是时候将你学到的 React 基础知识付诸实践,构建一个简单的前端应用来模拟与后端 API 的交互了。在这个阶段,你可以先使用模拟数据,或者如果你的后端 API(阶段项目 5)已经搭建好,可以直接连…...
PH热榜 | 2025-06-08
1. Thiings 标语:一套超过1900个免费AI生成的3D图标集合 介绍:Thiings是一个不断扩展的免费AI生成3D图标库,目前已有超过1900个图标。你可以按照主题浏览,生成自己的图标,或者下载整个图标集。所有图标都可以在个人或…...
STM32标准库-ADC数模转换器
文章目录 一、ADC1.1简介1. 2逐次逼近型ADC1.3ADC框图1.4ADC基本结构1.4.1 信号 “上车点”:输入模块(GPIO、温度、V_REFINT)1.4.2 信号 “调度站”:多路开关1.4.3 信号 “加工厂”:ADC 转换器(规则组 注入…...











