陈天 · Rust 编程第一课
陈天
Tubi TV 研发副总裁
23195 人已学习
新⼈⾸单¥68
登录后,你可以任选4讲全文学习
课程目录
已完结/共 65 讲
基础篇 (21讲)
陈天 · Rust 编程第一课
15
15
1.0x
00:00/00:00
登录|注册

21|阶段实操(1):构建一个简单的KV server-基本流程

返回值为Result<T, E>的原因
使用trait object
存储的抽象
dispatch方法
处理命令的抽象
使用protobuf定义客户端命令请求和服务器响应
思考题
Storage trait
CommandService trait
客户端和服务器间的协议
架构师的责任
思考问题
代码分析
代码示例
小结
架构和设计
先来一个短平糙的实现
为什么选KV server来实操
阶段实操(1):构建一个简单的KV server-基本流程

该思维导图由 AI 生成,仅供参考

你好,我是陈天。
从第七讲开始,我们一路过关斩将,和所有权、生命周期死磕,跟类型系统和 trait 反复拉锯,为的是啥?就是为了能够读懂别人写的代码,进而让自己也能写出越来越复杂且优雅的代码。
今天就到检验自身实力的时候了,毕竟 talk is cheap,知识点掌握得再多,自己写不出来也白搭,所以我们把之前学的知识都运用起来,一起写个简单的 KV server。
不过这次和 get hands dirty 重感性体验的代码不同,我会带你一步步真实打磨,讲得比较细致,所以内容也会比较多,我分成了上下两篇文章,希望你能耐心看完,认真感受 Rust best practice 在架构设计以及代码实现思路上的体现。
为什么选 KV server 来实操呢?因为它是一个足够简单又足够复杂的服务。参考工作中用到的 Redis / Memcached 等服务,来梳理它的需求。
最核心的功能是根据不同的命令进行诸如数据存贮、读取、监听等操作;
而客户端要能通过网络访问 KV server,发送包含命令的请求,得到结果;
数据要能根据需要,存储在内存中或者持久化到磁盘上。

先来一个短平糙的实现

如果是为了完成任务构建 KV server,其实最初的版本两三百行代码就可以搞定,但是这样的代码以后维护起来就是灾难。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文深入介绍了如何使用Rust语言构建一个简单的KV server,并强调了代码结构的重要性。作者首先指出了简单实现的问题,包括代码结构混乱、难以维护和测试的缺点。随后,通过实际代码示例展示了构建KV server的基本流程,包括使用DashMap创建内存中的kv store、处理客户端请求、使用AsyncProstStream处理TCP Frame等关键部分。文章还介绍了如何定义客户端和服务器间的协议,以及如何处理请求的命令,返回响应。通过这些内容,读者可以快速了解构建KV server的基本思路和关键接口的定义。此外,文章还详细介绍了Storage trait的设计,强调了其对不同存储方案的抽象和扩展性。整体而言,本文对于想要了解Rust语言实现KV server的读者具有很高的参考价值,尤其对于想要深入了解KV server实现细节的读者来说,是一篇值得阅读的文章。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《陈天 · Rust 编程第一课》
新⼈⾸单¥68
立即购买
登录 后留言

全部留言(16)

  • 最新
  • 精选
  • Roy Liang
    对于 Storage trait,为什么返回值都用了 Result?在实现 MemTable 的时候,似乎所有返回都是 Ok(T) 啊? 我觉得Storage作为trait,需要关注IO操作失败的错误情况,而MemTable实现,都是内存操作,几乎不会失败,所以返回Ok(T)就可以了

    作者回复: 对的!

    2021-10-19
    2
    9
  • Marvichov
    这次的选图发生在最近的一个大地艺术: 包裹凯旋门! 想了想为什么需要序列化/反序列化, http, json或者xml已经是structured的data了啊; 后来意识到, 需要把text data转化成某种rust的数据结构(data + algorithm)才能使用与数据绑定的algorithm (OOP) 比如用protobuf生成对应的rust struct (or enum)…然后对那些struct实现CommandService trait 或者 Into, new之类的方法

    作者回复: 序列化反序列化的目的是把内存中数据结构的表述转换成网络中或者文件中可以存储的表述。比如一个 Box<T> 显然无法直接在网络中传输的。json 是最常见的序列化方式,但 json 效率太低(xml 就更低了)。protobuf 效率很高,且其二进制的格式非常精简(比如长度都是 varint),很省带宽。

    2021-10-14
    5
  • zahi
    那个短平糙的实现代码,那个引用kv下面的结构根本找不到吗,github上也找不到这个代码。

    编辑回复: 短平糙的版本是个示意

    2022-07-30归属地:北京
    2
  • 如果就是风硕
    我理解先要做设计,这个设计是针对需求,设计实现需求的整个流程,流程中的每一个步骤都是做什么,而不要考虑怎么做,怎么做是需要延迟决策处理的。这样做出来的设计才能简单清晰。

    作者回复: 先定义接口

    2022-01-16
  • Lionel
    请问老师,怎么独立运行build.rs ? 譬如proto文件修改后,我只想让生成新的abi.rs,该如何操作?

    作者回复: 你可以就运行 `cargo build`

    2021-11-22
    2
  • 罗杰
    Windows User 用户目录下中文名称 proto 编译出错,需要修改 build.rs,千万不要乱修改中文名称,这个很坑。

    作者回复: 哦,还有这样的坑

    2021-10-19
    2
  • 罗杰
    最近事情多,快跟不上了,代码还是要亲自写,切身感受。

    作者回复: 加油!

    2021-10-19
  • D. D
    定义Storage trait就是为了以后可以灵活的使用不同的具体的存储方案。如果之后要求持久化,其中涉及到例如I/O之类的操作,就很有可能要返回Err了。 此外,在并发场景下,也会有例如获取锁失败之类的情况。

    作者回复: 👍

    2021-10-12
  • pedro
    想一想,对于 Storage trait,为什么返回值都用了 Result<T, E>?在实现 MemTable 的时候,似乎所有返回都是 Ok(T) 啊? Result 这个枚举有两个类型T,E,当查询出错时,通过 E 给出出错原因,方便客户端及时做出纠错和调整,而 Ok 只有 1 和 0 的区分。

    作者回复: 嗯,还有一个原因是 trait 以后可能会被用在其它场景,比如文件系统中的 kv store,此时就可能有 IO error,所以,即使现在 in memory store 还用不着,但以后有可能用到。

    2021-10-11
  • 给我点阳光就灿烂
    老师在以后的章节中可不可以讲一下,如何把server实现类似docker 一样的socket 守护进程

    作者回复: 你可以使用可以做 demonize 的库来生成一个 damon。 比如:https://github.com/knsd/daemonize

    2021-10-11
收起评论
显示
设置
留言
16
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部