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

42|阶段实操(7):构建一个简单的KV server-如何做大的重构?

支持 PSUBSCRIBE 的设计
内存泄漏的 bug
让客户端能更好地使用新的接口
继续重构:弥补设计上的小问题
在处理流程中引入 Pub/Sub
Pub/Sub 的实现
支持 pub/sub
使用 yamux 做多路复用
现有架构分析
Redis 的 Pub/Sub 支持
代码抽象和友好性
重构对测试的影响
流程和架构分析
大的重构
架构设计
思考题
Pub/Sub 支持
系统重构
总结

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

你好,我是陈天。
在软件开发的过程中,一开始设计得再精良,也扛不住无缘无故的需求变更。所以我们要妥善做架构设计,让它能满足潜在的需求;但也不能过度设计,让它去适应一些虚无缥缈的需求。好的开发者,要能够把握这个度。
到目前为止,我们的 KV server 已经羽翼丰满,作为一个基本的 KV 存储够用了。
这时候,产品经理突然抽风,想让你在这个 Server 上加上类似 Redis 的 Pub/Sub 支持。你说:别闹,这根本就是两个产品。产品经理回应: Redis 也支持 Pub/Sub。你怼回去:那干脆用 Redis 的 Pub/Sub 得了。产品经理听了哈哈一笑:行,用 Redis 挺好,我们还能把你的工钱省下来呢。天都聊到这份上了,你只好妥协:那啥,姐,我做,我做还不行么?
这虽是个虚构的故事,但类似的大需求变更在我们开发者的日常工作中相当常见。我们就以这个具备不小难度的挑战,来看看,如何对一个已经成形的系统进行大的重构。

现有架构分析

先简单回顾一下 Redis 对 Pub/Sub 的支持:客户端可以随时发起 SUBSCRIBE、PUBLISH 和 UNSUBSCRIBE。如果客户端 A 和 B SUBSCRIBE 了一个叫 lobby 的主题,客户端 C 往 lobby 里发了 “hello”,A 和 B 都将立即收到这个信息。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文介绍了如何对一个已经成形的KV server进行大的重构,以支持类似Redis的Pub/Sub功能。作者首先分析了现有架构存在的问题,指出需要返回一个异步的Stream以支持Pub/Sub,并且需要在TCP/TLS之上建立流的概念以避免应用层的队头阻塞问题。接着,作者介绍了使用yamux进行多路复用的方案,并提供了相应的Rust代码示例。通过对yamux的封装,成功地将其融入到现有架构中,同时保持网络层的逻辑不变。最后,作者修改了abi.proto文件,加入了新的命令请求,以支持Pub/Sub功能的实现。整体而言,本文通过具体的技术分析和代码示例,展示了如何在现有系统上进行大的重构以满足新的需求,为读者提供了有益的技术指导和实践经验。文章内容涉及了Pub/Sub功能的设计和实现,以及相关的Rust代码示例,对于需要进行类似重构的读者具有一定的参考价值。文章还提出了思考题,引发读者对系统设计的深入思考。

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

全部留言(8)

  • 最新
  • 精选
  • yyxxccc
    很多时候,实际工作修改老系统,老系统啥单元测试啥的都没有😂,果真是动一行,就是牵一发而动全身,这方面老师有什么指导性原则么。

    作者回复: 在做新功能时,同时涉及到的老系统的模块一个个构建单元测试,然后再在其上开发新功能(以及适当的重构),新功能必须要有更严格的单元测试。这样运作一两年,老系统的单元测试就逐渐补齐了。不要试图一下子把老系统所有缺失的单元测试都补齐,往往这样的工作会被冠以优先级不高而虎头蛇尾。

    2021-12-06
    6
  • 罗同学
    我有个疑问, tokio 本身不就是 支持了多路复用吗 用 yamux来整合多路复用的意义是什么?

    作者回复: yamux 是一个具体的网络协议,它在 TCP 之上可以运行多个互不干扰的 stream(就像 HTTP/2);tokio 是一个异步运行时,可以在 N 个线程上跑 M 个 tokio task。我们利用 tokio 的异步能力来承载 Yamux 协议。

    2021-12-09
    3
  • 罗同学
    我现在有个困惑 这几天一直没想到答案 比如老师说的yamux 来做连接的多路复用 如果客户端不能用rust 有办法对接吗? 我试了一下 如果服务器yamux 过的服务 对方如果不是yamux包装的 请求 会报错 就是不能当成常规的tcp连接来处理

    作者回复: yamux 是个协议,比如你可以用 nodejs client, python client 访问。你当然需要使用支持 yamux 协议的库,比如 https://www.npmjs.com/package/yamux-js。这就跟你要访问 http server,需要符合协议规范的 http client 一样。

    2021-12-17
  • 罗杰
    写测试代码的确有助于我们思考,从而把代码写的更好。

    作者回复: 嗯

    2021-12-06
  • Freedom
    tokio家出了,tokio-yamux,哈哈哈,这下不用util转了
    2023-12-19归属地:河北
    1
  • 进击的Lancelot
    思考题1: 主要考虑如何检测 receiver 被 drop 的情况以及何时触发 gc 操作;对于如何检测 channel 被关闭有两种方式: 1. 每个 sender 发一次消息便可知道,这种方法低效,而且一方面需要考虑用于检测的消息不能和用户可能发送的消息出现重合,另一方面发送出去的消息还可能会被用户看到,不考虑这种方式 2. tokio::mpsc::sender 提供了 is_closed 方法来判断 channel 是否关闭,简单高效。如果使用的 channel 没有提供这个方法,可以考虑仿照第 35 讲中的 channel 的实现,对 channel 进行包装并增加一个原子计数来判断 receiver 的数量 有了检测方式,接下来就是考虑触发时机,考虑到并发情况下,访问 subscriptions 会有锁的问题,而且这种情况不会太频繁,因此可以放在 unsubscribe 的时候进行检查和清理。 思考题2:如果要提供 PSUBSCRIBE 功能,考虑增加一张 patter 表,按照 glob::Pattern 来匹配,则表的形式为 patterns: DashMap<Pattern, DashSet<u32>>,其中 DashSet 用于保存 subscription id。在 publish 时候,遍历 patterns 并于 channel 进行匹配,匹配成功则取出 subscription id 并发送一条消息。 思考题的完整实现可以参考:https://github.com/Phoenix500526/simple_kv/blob/main/src/service/topic.rs
    2022-10-23归属地:广东
    1
  • 阳阳
    二刷,终于跟着把代码写下来了
    2022-08-10归属地:北京
    1
  • Geek_aa1610
    有一个问题, 假设一个client sub了很多topic (同时有其他client在这些topic上做publish) sub的client端如何区分一次response是上一次sub的CommnadResponse::ok还是之前某次sub的topic上push来的新内容?
    2022-08-28归属地:浙江
收起评论
显示
设置
留言
8
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部