夜天之书 #98 Rust 程序库生态合作的例子

近期主要时间都在适应产品市场(Product Marketing)的新角色,不少想法还在酝酿和斟酌当中,于是文章输出没有太多时间来推敲和选题,只能保持每月发布相关的进展或一些零碎的思考。或许我可以恢复最早的模式,多做更新但是文章内容可能不会太过完整。

原本这一期想讨论的是 ASF 开源项目代码的所有权,以及开源软件变更协议的具体含义与操作方式。但是这个话题稍显枯燥,而且要把相关细节讲清楚,还需要继续斟酌。所以我改为采取把最近开始全职投入 Rust 开发,并接触相关生态发展和合作的经历做一点梳理,分享个人在其中的所见所闻。

我会从 Rust HTTP 库的生态切入,从最近一个大事件出发,即 Rust 采用范围最广的 HTTP 库 hyper 和 http 前后发布 1.0 版本,讲述其导致的整个 Rust 应用开发上下游牵一发而动全身的变化。

起因是我在整蛊 GreptimeDB HTTP 相关代码的时候,发现项目依赖的 axum 库是 0.6 版本,而上游是 0.7 版本。这天降的升级闲手,不升有点对不起自己了。通过解决升级过程中的问题,也能帮助摸清 GreptimeDB HTTP 模块的逻辑。

不过,我显然是小看了 Rust 生态荼毒甚广的 ZeroVer[1] 文化的威力。

ZeroVer 是一个揶揄的说法,即在采用语义化版本(SemVer[2])的前提下,因为各种原因,项目迟迟不愿发布 1.0 版本。

29a90b7f85a0aa35353b64cf788788c1.png

0ver 的魅力时刻

在语义化版本中,0.x 版本是在项目正式发布或说进入稳定期前,一个相对动荡的快速迭代阶段。语义化版本的核心价值是告诉用户升级版本可能面临什么变化:

  • 升级补丁版本(Patch Version):应当只有缺陷修复和性能提升等,不会破坏用户程序的改动。

  • 升级小版本(Minor Version):可能包含新功能,应当向后兼容,用户应用应当可以顺滑升级。

  • 升级大版本(Major Version):可能包含破坏性变更,用户需要做好应对逻辑甚至数据迁移的准备。

当然,在实践当中,语义化版本并不那么严格执行。尤其对于大型项目的实验性功能,是可能有一个独立的可靠机制的。但是无论如何,进入 1.0 之后就意味着项目对用户做了一个向后兼容的保证,除非升级大版本,否则用户会假设软件升级是可以非常激进的。

ZeroVer 方案的反面极端是 Apache Arrow 和 Apache DataFusion 每次发版都升级大版本的做法,很难评价。

  • build(deps): update datafusion to latest and arrow to 51.0[3]

  • build(deps): bump datafusion 20240528[4]

话说回来,axum 0.6 到 0.7 的版本升级是一个巨大的变更,基本把核心的类型设计做了一个颠覆,即 Body 不再是泛型了。

这其实也是一个槽点。国内开发者油条哥做的 Poem[5] 就不搞这些花里胡哨的泛型,直接用胖指针抹掉底下的差别,提供更好的开发体验。你说我都 HTTP 了,搞应用层接口开发了,我是跟你抠这点性能的人吗?

c928631d08a5809b17244ec7dcf29520.png

一个屏幕都写不完的 breaking changes 列表

34fa8303e1ac6fdc45d986b47d8b512a.png

Rust HTTP 生态泛型的魅力时刻

于是我着手升级 axum 的版本,一上来就是好几个屏幕的编译错误。没事,Rust 开发者的日常而已。

第一个小问题,我们依赖了 axum-test-helper 这个库,它没跟上 axum 0.7 的版本。我先试着给上游提 PR 升级:

  • feat: support axum 0.7[6]

未果。

自己维护比较头疼,其实只有一个文件,最后我在 GreptimeDB 里 vendor 掉了:

  • refactor: bundle the lightweight axum test client[7]

  • chore: respect axum test client's origin[8]

这里我又要吐槽了。axum 是不是哪里有问题,居然不提供测试套件,还要下游自己 embedded 然后去掉 (crate) 修饰词,好玩吗?虽然其实也是可以用 reqwest 套一个 TestClient 解决,按照上游的说法:“这只是很薄的一层”[9],但是这么简单提升使用体验的事情,为何不做呢?

反观 Poem 就提供了 TestClient[10] 工具,开发起来舒服多了。不管是不是我一个文件就能解决,这不是下游应该解决的事情。

紧接着,发现 axum 自己的 TestClient 有落后,以及一个 Rust Nightly toolchain 的兼容问题,提 PR 解决:

  • Upgrade reqwest to 0.12[11]

  • Enable diagnostic attributes for Rust 1.78+[12]

Rust Nightly toolchain 的兼容问题是一个很奇妙的问题。因为 Nightly 顾名思义就是最新的 Rust 开发版本,不提供语义化版本保证,只是在 Rust 1.x 的时间线上大体向后兼容。但是结合上 Rust Stabilize 的流程,以及打开 feature gate 如果找不到 feature flag 就会编译失败等等细碎的问题,经常会导致生态在跟进 Nightly 之前有一个无法编译的窗口。

这不算是绝对的坏事,甚至推着生态跟新版本是合理的。但某种程度上其实是 Rust Stabilize 太慢,导致系统开发比如 GreptimeDB 不得不用 Nightly 版本,而出现的新问题。Rust 开发很多用 Nightly 版本,跟 0ver 可能也有某种互相呼应的巧合。在这种环境下,开发公共库并保持多平台多版本兼容,其实是一件非常困难的事情,怪不得都 0ver 了。

然后我就遇到了本次升级最大的大魔王。Rust 生态的 gRPC 库 tonic[13] 闪亮登场!

这里的依赖关系大概是这样的。

首先,axum 0.7 除了接口变化,还有一个关键的依赖变化是把 hyper 和 http 给升到了 1.0 上。因为 Rust HTTP 生态都依赖 hyper 和 http 这两个库,这就导致如果你的接口开始交互,那么所有的结构都要同步到同一个版本。

这个问题并不那么致命。因为如果你合理的 re-export 了依赖的接口,那么同一个 crate 的多个版本是可以共存的,就像我最近在升级 Apache OpenDAL 的时候连带需要升级 reqwest 到 0.12 版本,它依赖了 hyper 1.0 和 http 1.0 但是跟 axum 的 server 端代码关系较小,所以我可以切割开:

  • build(deps): upgrade to reqwest 0.12[14]

注意以上 PR 里修改 use 语句以选择正确的 re-export 符号的变更。

不过,tonic 的情况就比较幽默了。tonic 依赖了 axum 0.6 版本,而且 tonic 和 axum 都用了 tower 作为中间件的第三方库,而且都没有 re-export 而是标榜自己能无缝接入 tower 丰富的中间件生态。

由于 tonic 尚未完成 axum 0.7 和 hyper 1.0 的升级,这下就连环爆炸了:你找不到一个合适的 tower 版本,或者说你找不到一个合适的 axum 版本,来作为 GreptimeDB 被传递关联起来的版本约束。

于是,直到今天,GreptimeDB 的升级还是未完成的状态:

  • Upgrade Axum to 0.7[15]

不过,在三月底,tonic 上游就出现了一位大英雄开了一个升级的 PR 完成了主要的工作:

  • Upgrade to Hyper 1.0 & Axum 0.7[16]

这个 PR 我看到的时候还需要两个 hyper-util 的改动,我给帮忙推着合并了:

  • Adds max_pending_accept_reset_streams for legacy[17]

  • feat: add {http1,http2}_only for auto conn[18]

这里又岔开一下。虽然 tonic 在 hyperium 组织下,跟 hyper 和 http 一样,但是 hyper 和 http 的作者,Rust 生态真正负责人的英雄 @seanmonstar 并不怎么看 tonic 这个库。tonic 主要是 tokio 的作者 @LucioFranco 和另外两位志愿者 @tottoto 和 @djc 维护的。他们都有自己的本职工作要做,所以并没有太多时间 Review tonic 的变动。实际上,很多项目就用着 tonic 0.11 和 axum 0.6 万年不动也还行的(有没有发现 tonic 也是 ZeroVer 流派)。

不过,经过两个月当中的空闲时间累积,这个 tonic 的升级 PR 终于看着要走进尾声,希望能顺利。开源项目能有这个效率,小几个月跟进一个大型重构,虽然比不上 @seanmonstar 和其他活跃维护项目的响应速度,也绝对算是能及时更新的了。

这个 tonic PR-3610 有很多经典的开源贡献者跟维护者之间的交流和争论,我这里就不展开了。但是我非常建议各位关心开源的人去看看,了解真实的开源世界,未来或许参与进去做出自己的贡献,而不是自己想象或者冷眼旁观。

最后,贴两张图说明 Rust 生态 ZeroVer 的严重程度:

7be065416532ab350da21b6790bfdfa2.jpeg

GreptimeDB 的依赖 ZeroVer 有 782 个

4b91f14197cbaabb13ccabeb4d2cd69d.jpeg

GreptimeDB 的依赖非 ZeroVer 有 278 个

在 GreptimeDB 的依赖里,ZeroVer 的占比约莫七成。

其实,GreptimeDB 很多升级都很有工程上的说法,欢迎各位关注发现。我可能也会在今年的某些 Rust 会议上分享相关的经验。

文末放两个我在 Reddit 上跟这次 HTTP 生态大更新相关的讨论链接,在 Rust channel 上还算有一些有趣的讨论。

  • Spreading http 1.0 and hyper 1.0 among the ecosystem[19]

  • Super heavy generic on HTTP lib makes debugging hard[20]

参考资料

[1]

ZeroVer: https://0ver.org/

[2]

SemVer: https://semver.org/

[3]

build(deps): update datafusion to latest and arrow to 51.0: https://github.com/GreptimeTeam/greptimedb/pull/3661

[4]

build(deps): bump datafusion 20240528: https://github.com/GreptimeTeam/greptimedb/pull/4061

[5]

Poem: https://docs.rs/poem/latest/poem/

[6]

feat: support axum 0.7: https://github.com/cloudwalk/axum-test-helper/pull/29

[7]

refactor: bundle the lightweight axum test client: https://github.com/GreptimeTeam/greptimedb/pull/3669

[8]

chore: respect axum test client's origin: https://github.com/GreptimeTeam/greptimedb/pull/3805

[9]

“这只是很薄的一层”: https://github.com/tokio-rs/axum/issues/1146

[10]

TestClient: https://docs.rs/poem/latest/poem/test/struct.TestClient.html

[11]

Upgrade reqwest to 0.12: https://github.com/tokio-rs/axum/pull/2688

[12]

Enable diagnostic attributes for Rust 1.78+: https://github.com/tokio-rs/axum/pull/2693

[13]

tonic: https://github.com/hyperium/tonic

[14]

build(deps): upgrade to reqwest 0.12: https://github.com/GreptimeTeam/greptimedb/pull/4037/commits/ad0793b48cb0ac19fbd7c52be215140d96ca6eb5

[15]

Upgrade Axum to 0.7: https://github.com/GreptimeTeam/greptimedb/issues/3610

[16]

Upgrade to Hyper 1.0 & Axum 0.7: https://github.com/hyperium/tonic/pull/1670

[17]

Adds max_pending_accept_reset_streams for legacy: https://github.com/hyperium/hyper-util/pull/102

[18]

feat: add {http1,http2}_only for auto conn: https://github.com/hyperium/hyper-util/pull/111

[19]

Spreading http 1.0 and hyper 1.0 among the ecosystem: https://www.reddit.com/r/rust/comments/1bqfjbo/spreading_http_10_and_hyper_10_among_the_ecosystem/

[20]

Super heavy generic on HTTP lib makes debugging hard: https://www.reddit.com/r/rust/comments/1czi4g4/super_heavy_generic_on_http_lib_makes_debugging/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/21249.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

YOLOv8改进(一)-- 轻量化模型ShuffleNetV2

文章目录 1、前言2、ShuffleNetV2代码实现2.1、创建ShuffleNet类2.2、修改tasks.py2.3、创建shufflenetv2.yaml文件2.4、跑通示例 3、碰到的问题4、目标检测系列文章 1、前言 移动端设备也需要既准确又快的小模型。为了满足这些需求,一些轻量级的CNN网络如MobileNe…

十_信号4-SIGCHLD信号

SIGCHLD信号 在学习进程控制的时候,使用wait和waitpid系统调用何以回收僵尸进程,父进程可以阻塞等待,也可以非阻塞等待,采用轮询的方式不停查询子进程是否退出。 采用阻塞式等待,父进程就被阻塞了,什么都干…

力扣83. 删除排序链表中的重复元素

Problem: 83. 删除排序链表中的重复元素 文章目录 题目描述思路复杂度Code 题目描述 思路 1.定义快慢指针fast、slow均指向head; 2.每次fast后移一位,当fast和slow指向的节点值不一样时,将slow.next指向fast同时使slow指向fast; 3…

MyBatis框架-开发方式+参数传递+#{}、${}+返回值处理+查询结果封装为对象+resultType

一、开发方式 MyBatis-Dao层Mapper接口化开发 二、注意事项 1、Mapper接口与Mapper.xml映射文件要满足4个对应 (1)Mapper接口的全类名必须与Mapper映射文件中的namespace相同 (2)Mapper接口中的每一个方法名在Mapper映射文件…

回溯算法之电话号码字母组合

题目: 给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。 给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。 示例 1: 输入:digits "2…

Java web应用性能分析之【jvisualvm远程连接云服务器】

Java web应用性能分析之【java进程问题分析概叙】-CSDN博客 Java web应用性能分析之【java进程问题分析工具】-CSDN博客 前面整理了java进程问题分析和分析工具,现在可以详细看看jvisualvm的使用,一般java进程都是部署云服务器,或者托管IDC机…

每周统计-20240531

用于测试程序的稳定性: 龙虎榜: 成交额: 封成比: 收盘前放量: 开盘抢筹: 封单额:

论文阅读:Correcting Motion Distortion for LIDAR HD-Map Localization

目录 概要 Motivation 整体架构流程 技术细节 小结 论文地址:http://arxiv.org/pdf/2308.13694.pdf 代码地址:https://github.com/mcdermatt/VICET 概要 激光雷达的畸变矫正是一个非常重要的工作。由于扫描式激光雷达传感器需要有限的时间来创建…

linux命令:调试必备工具dmesg

在服务器上进行芯片调试时,我们会遇到各种各样的问题,很多问题与操作系统相关。此时就需要了解操作系统发生了哪些事件。 dmesg 是linux系统中用来打印或控制内核缓冲区内容的命令。这个环形缓冲区记录了系统启动以来发生的各种事件消息,包括…

ChatTTS改良版 - 高度逼真的人类情感文本生成语音工具(TTS)本地一键整合包下

先介绍下ChatTTS 和之前发布的 Fish Speech 类似,都是免费开源的文本生成语音的AI软件,但不同的是,ChatTTS测试下来,对于人类情感语调的模仿,应该是目前开源项目做的最好的,是一款高度接近人类情感、音色、…

WordPress中借助Table of Contents Plus+Widget Options插件,实现仅在文章侧边栏显示文章目录的功能

本文转自博主的个人博客:https://blog.zhumengmeng.work,欢迎大家前往查看。 原文链接:点我访问 序言:今天心血来潮,写了一篇文章,忽然发现自己的文章极少有目录,这对于长文章的阅读来说是十分不利的&#…

【自动驾驶】针对低速无人车的线控底盘技术

目录 术语定义 一般要求 操纵装置 防护等级 识别代号 技术要求 通过性要求 直线行驶稳定性 环境适应性要求 功能安全要求 信息安全要求 故障处理要求 通信接口 在线升级(OTA) 线控驱动 动力性能 驱动控制响应能力 线控制动 行车制动 制动响应能力 线控转向 总体要求 线控…

车联网安全入门——ICSim模拟器使用

文章目录 车联网安全入门——ISCim模拟器使用介绍主要特点:使用场景: 安装使用捕获can流量candumpcansnifferwiresharkSavvyCAN主要特点:使用场景: 重放can报文cansendSavvyCAN 总结 车联网安全入门——ISCim模拟器使用 &#x1…

SQL刷题笔记day8——SQL进阶——表与索引操作

目录 1 创建一张新表 2 修改表 3 删除表 4 创建索引 5 删除索引 1 创建一张新表 我的答案 create table if not exists user_info_vip (id int(11) primary key auto_increment Comment自增ID, # 有了主键就不用写not nul了 uid int(11) unique not null Comment用户ID, …

272 基于matlab的形态滤波和局域值分解(LMD)的齿轮故障诊断

基于matlab的形态滤波和局域值分解(LMD)的齿轮故障诊断,GUI交互界面。通过形态滤波对一维信号进行降噪处理,并通过LMD局部均值分解提取故障信号,最后提取处故障频率。程序已调通,可直接运行。 272 形态滤波…

微信小程序的服务调取

微信小程序的服务调取概述 微信小程序允许开发者通过网络请求与服务器进行交互,从而实现数据的上传和下载。这是通过小程序提供的API,如wx.request、wx.downloadFile、wx.uploadFile等来完成的。这些API使得小程序可以从远程服务器获取数据,…

Java+SVNCloud+Mysql课程设计

文章目录 1、主要内容2、所需准备3、与sql访问的中间类:SqlMessage4、窗口界面5、main方法 1、主要内容 课程设计,主要通过Javas wing创建窗口,jdbc连接云端mysql数据库进行基本操作,支持随机生成数据并用动态展示数据结果。 先…

一种最大重叠离散小波包特征提取和支持向量机的ECG心电信号分类方法(MATLAB 2018)

目前小波分析算法常采用Mallat快速算法。该算法由与滤波器卷积、隔点采样和隔点插零等三个环节组成。由于实际使用的滤波器并不具有理想频域特性,使得在标准二进小波算法中存在着频率混叠和小波系数失真等缺点,在标准二进小波包算法中还存在频带错乱现象…

展现市场布局雄心,ATFX再度亮相非洲峰会,开启区域市场新篇章

自2023年全球市场营销战略部署实施以来,ATFX在全球各区域市场取得了丰硕成果,其品牌实力、知名度、影响力均有大幅提升。在这场全球扩张的征程中,非洲市场日益成为集团关注的焦点。自2023年首次踏上这片充满潜力的市场以来,ATFX持…

列表标签 ul+ol/li

04-07、列表标签 ulol/li 概述 列表标签:无序列表ulli、有序列表olli和定义列表 dl dt dd 三种,在网页制作中应用非常广泛,列表就是信息资源的一种展示形式。 特点: 它们都是块元素,可以受到宽度,高度&…