藏川线前段

--- 摄于 2017 年 9 月 藏川线前段

从内嵌 web api 需求开始说起

最近由于工作上需要将 tentacle 的用户接口进行大幅度改动,支持 async trait,为用户提供 async/await 生态的支持,这是一个影响巨大的决定,需要在改动之前做一些评估,并自己实验一番,看看易用性与改动难度之间的对比度,从而能够说服别人这个改动是势在必行的,是用户体验的巨大提升。与此同时,手上一个项目需要内嵌 web api 作为内部状态报告和监听的手段,于是,盯上了 Rust 的 web framework 生态,这是时隔三年之后的第二次考察。

一番调查之后发现:

然后突然从 crates.io 的垃圾堆里面找到了 salvo,基于 hyper 底层,这玩意内嵌进应用肯定没问题了,于是随手看了两眼代码,开始撸内嵌 api,上线完美。这时候的我压根没想到后续还会有交集。

重写之心蠢蠢欲动

就在上上周,我突然想起了,似乎两年没碰过的博客项目,这是具有纪念意义的项目,标志着我能独立写一个相对复杂的应用。它现在还在服役中,只是从日志中可以看出,有部分不安全的 panic 问题,只是因为线程池不断的拉起线程,让它能继续工作而已。在 async/await 语法稳定的那段时间,我就一度想重写,但一直找不到符合我想法的 web framework,现在这东西不就已经有了么,而且重写还能进一步探索 async trait 在复杂项目中的应用问题,于是我决定重写了。

于是,花了上上周两天周末将 db 操作从 diesel 切换到 sqlx,以及上周几乎所有的业余时间,将所有 web 相关都切换到了 salvo 上,同时新增了博客的上传文件和 Rss 订阅功能,修复了一些历史遗留的问题,当然也碰到不少 js 问题,通过暂时的手段解决掉就好了,毕竟时间有限,前端的东西不是特别熟悉,凑合用用罢了。

这种项目的全方位大范围重写,压根不是开个 branch 可以搞定的,我的方法是重新开了一个项目,打开两个编辑器,对着同步逻辑实现异步版本,同时改善几年前比较青涩(拉跨)的实现,实现功能的兼容和性能的飞跃,当完成之后,直接覆盖原项目,保留 git 记录,然后加一个 commit 就是重构结束了。

上周末部署上线之后的对比是,原先两个进程加起来需要 10m 的常驻内存需求,现在重写版本只需要 20k 左右,拉起来的时候只需要 12k,后续因为内存使用稳定在 20k。这是一个很棒的数据,同时吞吐量也上升了,相当完美。

在重写的过程中,我还顺手向 salvo 项目提交了一些修复和改善的代码,因为本人习惯性地看源码,习惯性地看不惯导致性能下降的写法等等。基本上来讲,当我重写完成之后,salvo 项目的源码也看完大半了,值得一说的是 salvo 的树形路由功能,这个我觉得是最棒的地方。

树形路由与全局中间件

下面我来简单说一下树形路由与全局中间件的区别和各自的好处。

全局中间件

优点是简单,知道所有请求必然会经过这个中间件处理,并且中间件与 url 的设置可以完全拆开处理,不需要考虑路由与中间件的耦合问题。

缺点也是这样简单粗暴的处理,因为并不是每个 url 都需要中间件处理的,凭白多了一些函数调用是很不划算的问题。

树形路由

树形的优点在于灵活配置的中间件,包括任意位置的 before 和 after handle,还可以有虚拟上级树,url 解析的时候就类似 /bar//foo 这样,中间空白无所谓,只是为了插入一个 before 或者 after handle 用来统一处理这个父节点下的所有子节点的请求。

缺点同样很明显,因为树形的灵活导致这些中间件必须与 url 的设置挂钩,导致路由的设定会相对来说复杂一点,体现为代码会多一点点,但我觉得问题不大。

最后

由于我提交 PR 过于频繁,导致现在我已经成为 salvo 的股东(管理者),大家如果想简单尝试一下内嵌 web 之类的需求,不妨考虑一下这个库呗,顺便也反馈一些问题,我自己的 blog 是上线了,但因为我大量阅读了代码,所以个人觉得这种情况不属于一般情况,现在需要一些不具体看代码的使用样例来推进文档和 api 的改善工作,就酱~

评论区

加载更多

登录后评论