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研究如何优化人类与计算机之间…...
Android Wi-Fi 连接失败日志分析
1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分: 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析: CTR…...
【力扣数据库知识手册笔记】索引
索引 索引的优缺点 优点1. 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度(创建索引的主要原因)。3. 可以加速表和表之间的连接,实现数据的参考完整性。4. 可以在查询过程中,…...
【机器视觉】单目测距——运动结构恢复
ps:图是随便找的,为了凑个封面 前言 在前面对光流法进行进一步改进,希望将2D光流推广至3D场景流时,发现2D转3D过程中存在尺度歧义问题,需要补全摄像头拍摄图像中缺失的深度信息,否则解空间不收敛…...
抖音增长新引擎:品融电商,一站式全案代运营领跑者
抖音增长新引擎:品融电商,一站式全案代运营领跑者 在抖音这个日活超7亿的流量汪洋中,品牌如何破浪前行?自建团队成本高、效果难控;碎片化运营又难成合力——这正是许多企业面临的增长困局。品融电商以「抖音全案代运营…...
【配置 YOLOX 用于按目录分类的图片数据集】
现在的图标点选越来越多,如何一步解决,采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集(每个目录代表一个类别,目录下是该类别的所有图片),你需要进行以下配置步骤&#x…...
12.找到字符串中所有字母异位词
🧠 题目解析 题目描述: 给定两个字符串 s 和 p,找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义: 若两个字符串包含的字符种类和出现次数完全相同,顺序无所谓,则互为…...
JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作
一、上下文切换 即使单核CPU也可以进行多线程执行代码,CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短,所以CPU会不断地切换线程执行,从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...
C++八股 —— 单例模式
文章目录 1. 基本概念2. 设计要点3. 实现方式4. 详解懒汉模式 1. 基本概念 线程安全(Thread Safety) 线程安全是指在多线程环境下,某个函数、类或代码片段能够被多个线程同时调用时,仍能保证数据的一致性和逻辑的正确性…...
在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?
uni-app 中 Web-view 与 Vue 页面的通讯机制详解 一、Web-view 简介 Web-view 是 uni-app 提供的一个重要组件,用于在原生应用中加载 HTML 页面: 支持加载本地 HTML 文件支持加载远程 HTML 页面实现 Web 与原生的双向通讯可用于嵌入第三方网页或 H5 应…...
Reasoning over Uncertain Text by Generative Large Language Models
https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829 1. 概述 文本中的不确定性在许多语境中传达,从日常对话到特定领域的文档(例如医学文档)(Heritage 2013;Landmark、Gulbrandsen 和 Svenevei…...











