夜天之书 #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/

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

node.js点餐系统app-计算机毕业设计源码84406

摘 要 21世纪的今天,随着社会的不断发展与进步,人们对于信息科学化的认识,已由低层次向高层次发展,由原来的感性认识向理性认识提高,管理工作的重要性已逐渐被人们所认识,科学化的管理,使信息存…

脚本实现登陆滑块

脚本实现登陆滑块 仅供学习参考,简单操作 你知道吗,滑动验证码居然是为了验证人类比机器人蠢而设计的。 你以为自己快速、准确地滑动拼图、对齐图案,才被允许通过,系统还说你超越了99%的用户,夸你“比闪电还快”&am…

算法-随机快排及荷兰国旗优化

文章目录 算法介绍 :1. 随机快排解析2. 荷兰国旗问题3. 随机快排优化4. 总结随机快排 算法介绍 : 随机快速排序和传统的快速排序的逻辑本质是一致的,都是找到一个值作为划分的中间位置,左边数值均小于该数值,右边数值均大于该数值,但是与传统的快排又不一致的是,我们的这个位置…

Chrome DevTools

Console 面板 此章节请打开 justwe7.github.io/devtools/console/console.html 一起食用 一方面用来记录页面在执行过程中的信息(一般通过各种 console 语句来实现),另一方面用来当做 shell 窗口来执行脚本以及与页面文档、DevTools 等进行交…

动态SQL IF语句

IF语句学习 第一种写法(标准) 我们先来看以下标准写法: select * from .. <where> <if test""> and ....... <if test""> and ....... <where> 我们用了一个where标签 , 内嵌if语句 第二种写法: 这是第二种写法:不用where标…

综合交易模型--雪球跟单参数说明支持qmt,同花顺

经过测试&#xff0c;目前完成了这个策略。支持多策略&#xff0c;支持全市场&#xff0c;包括股票&#xff0c;etf,可转债 全部的参数 { "雪球跟单":"跟单原理", "原理":"比重变大默认买入&#xff0c;变小默认卖出&#xff0c;持股…

【SpringBoot】SpringBoot项目关于默认port以及context path的配置 application.yml

application.yml server port [端口号] 配置/修改默认端口号 # server configurationserver:port: 8080context path [虚拟目录] 配置/修改默认虚拟目录 # server configurationserver:servlet:context-path: /spring configuration # spring configuration spring:applica…

mysql DDL——增删改

简略版&#xff1a; 详细版&#xff1a; DDL&#xff1a;对库中表的的记录进行增删改操作&#xff1b; 分别对应&#xff1a;添加&#xff08;insert&#xff09;&#xff0c;修改(update)&#xff0c;删除(delete); 一&#xff1a;添加数据 1. 对全部字段添加数据&#x…

【一刷《剑指Offer》】面试题 28:字符串的排列

牛客对应题目链接&#xff1a;字符串的排列_牛客题霸_牛客网 (nowcoder.com) 力扣对应题目链接&#xff1a;LCR 157. 套餐内商品的排列顺序 - 力扣&#xff08;LeetCode&#xff09; 核心考点 &#xff1a;全排列问题&#xff0c; DFS。 一、《剑指Offer》对应内容 二、分析题…

关于留痕的使用常见的问题

1. 登录微信 登录要导出数据的微信&#xff08;不支持微信多开&#xff0c;不支持部分老版本微信&#xff09; 相关信息 想把手机端的微信聊天记录转移到电脑上可以使用微信自带的聊天记录迁移功能 操作步骤&#xff1a; 安卓&#xff1a; 手机微信->我->设置->聊…

AI解密:语言模型生成下一个词的概率从何而来

在这个信息爆炸的时代&#xff0c;你是否曾好奇过&#xff0c;当你与聊天机器人流畅对话时&#xff0c;那些机智回复的背后&#xff0c;究竟隐藏着怎样的秘密&#xff1f;今天&#xff0c;就让我们一起乘坐时光机&#xff0c;深入语言模型的神秘腹地&#xff0c;揭开它预测下一…

【spring】第二篇 bean实例化

对象已经能交给Spring的IOC容器来创建了&#xff0c;但是容器是如何来创建对象的呢? 就需要研究下bean的实例化过程&#xff0c;在这块内容中主要解决两部分内容&#xff0c;分别是 bean是如何创建的 实例化bean的三种方式&#xff0c;构造方法,静态工厂和实例工厂 在讲解这…

iOS——类与对象底层探索

类和对象的本质 当我们使用OC创建一个testClass类并在main函数创建它的实例对象的时候&#xff0c;OC的底层到底是什么样的呢&#xff1f; 首先&#xff0c;我们要了解OC对象的底层结构&#xff0c;那么我们就得知道&#xff1a;OC本质底层实现转化其实都是C/C代码。 使用下面…

详解 Spark SQL 核心编程知识

一、SparkSQL 概述 1. 概念 Spark SQL 是 Spark 用于结构化数据 (structured data) 处理的 Spark 模块&#xff0c;使用 SQL 的方式简化 RDD 的开发 2. Hive VS SparkSQL Hive 是早期唯一运行在 Hadoop 上的 SQL-on-Hadoop 工具&#xff0c;但是 MapReduce 计算过程中大量的中…

java高并发实战<2>

##>>> 我们解决我们重复下单的问题 我们可以使用mysql 的唯一索引 &#xff0c;在我们的数据库层面保证不能重复下单 我可以控制是唯一的 同一个用户 针对于同一个商品只可以买一个 重复下单 优化 我们 >1.使用数据库唯一索引 一旦是 2个请求 因为mysql 有行级…

万物皆有定数

前段时间&#xff0c;测算一个女孩的婚姻&#xff0c;她年底或明年必有婚姻&#xff0c;因为蛇冲猪日&#xff0c;冲动夫宫&#xff0c;就有婚姻出现。不过&#xff0c;按照她总体八字分析&#xff0c;是要晚婚的&#xff0c;但这个运已到&#xff0c;所以&#xff0c;就要允许…

【文献阅读】汽车上的信息安全工程

文章目录 前言 基本概念 信息安全评估 信息安全措施 测试验证 参考文献 前言 见《汽车电子——产品标准规范汇总和梳理&#xff08;信息安全&#xff09;》 基本概念 道路车辆信息安全 cybersecurity 使资产受到充分保护&#xff0c;免受道路车辆相关项、其功能及其电气或…

运放的自激振荡问题

运放的自激振荡指的是当运算放大器加电后&#xff0c;在没有外部信号输入的情况下&#xff0c;输出端会出现高频类似于正弦波的波形。 运算放大器产生自激的原因以及解决办法-CSDN博客 a)当振荡由分布电容、电感等引起时&#xff0c;可通过反馈端并联电容&#xff0c;抵消影响…

Java web应用性能分析之【java进程问题分析工具】

Java web应用性能分析之【java进程问题分析概叙】-CSDN博客 前面大概讲了java进程问题分析流程&#xff0c;这里再小结一下分析工具&#xff0c;后面也会小结一下java进程问题分析定位。 1.分析工具 1.1.linux命令工具 参考&#xff1a;Java web应用性能分析之【Linux服务器性…

汪小菲直播翻车亲儿子直言麻六记有异味网友热议引爆话题

汪小菲直播翻车&#xff01;亲儿子直言“麻六记”有“异味”&#xff0c;网友热议引爆话题在星光璀璨的娱乐圈&#xff0c;汪小菲一直以家庭幸福、事业有成的形象示人。然而&#xff0c;近日的一场直播让他遭遇了前所未有的尴尬。在直播中&#xff0c;汪小菲兴致勃勃地向观众跨…