转载

Mike:Rust是近15年最佳工程实践的集大成者

日前,CSDN 采访了 Rust 方面资深使用者庄晓立和Elton,很多人对于Rust在应用方面有着极大的兴趣,为此我们建立了 CSDN Rust 学习交流群(见文末的二维码),邀请 Rust 中文社区 站长、妈咪问问 CEO 唐刚为我们分享妈咪问问的Rust实践。

Mike:Rust是近15年最佳工程实践的集大成者

唐刚 ( GitHub ),Rust 中文社区站长、妈咪问问 CEO,前美洽网络联合创始人兼 CTO,曾在龙芯梦兰担任近 3 年的研发工程师。

毕业于电子科技大学,前期偏重于嵌入式开发、Linux 驱动开发、Linux 发行版定制等技术领域,目前对 Rust 非常感兴趣。从2010年开始投入到Web开发和互联网创业中,主导开发了 MVC Web框架 Bamboo(lua语言)并应用在了一些项目中。

以下为分享实录:

妈咪问问是一个集成化的本地母婴在线实时咨询平台,提供就近服务机构的医疗、健康、心理等免费咨询。相对于其它母婴类产品,它的特点是简单直接地解决问题(IM形式),后端是大量本地的服务机构专家的服务。

目前妈咪问问刚上线,各方资源都还在陆续入驻中。其中,妈咪问问有一个自助机器人,叫智能保姆大白,如果觉得无聊,可以随便调戏它,在微信里面访问 这个链接 进入这个智能咨询室。

Mike:Rust是近15年最佳工程实践的集大成者

妈咪问问产品组件

「妈咪问问」现在提供 iOS App、 Android App 、微信聊天室、微信公众账号接口4个前端,对于服务机构,还有一个专门的PC工作台客户端。所以说她是一个咨询集成化平台,当然,要做到这一步,还有很长的路要走,但是,我还是相信 Rust ,因为他做的后台是非常稳定的。

妈咪问问目前只有部分使用了Rust,主要用来写业务逻辑,主要包括用户的注册登录、页面的渲染、url请求处理、微信接口与IM接口的打通、各服务数据同步服务等等。像数据处理组件和IM组件都是用的成熟的第三方的服务(感谢亲加语音云通讯的大力支持,SVIP级别的用户了)。

我和Rust的故事

我第一次听见Rust大概是在13年年初,因为我一直都是火狐粉,比较认同Mozilla的精神(分享知识 共建开放网络),所以当时发现他们在做这个项目就瞟了一点,发现这个语言很难看懂,完全不知所云,之后就不再关注了。而且在那个时间段,我正沉醉在动态语言的便捷性里面,认为动态语言已然很强大了(fall in love with Luajit),没有必要掌握一门静态语言了。

第二次开始关注是在14年9月底,这之前踩了很多动态语言的坑,一直在思考有没有从很底层解决工程质量的工具或语言?于是考察了各种非主流(这里的意思是相对于C、C++、Java来说非主流)语言 Erlang、Go、Haskell等,不过感觉都不是太合胃口。然后就想起来Rust,于是回头仔细阅读了官网上的文档,当时是 0.11 stable。发现这个语言跟13年的时候,感觉是两个语言了,没有任何熟悉的感觉,就开始试着学习。当看到ownership, move, copy, borrow, borrow mut 这些概念的时候,一下子就震惊、震惊、震惊了。这是我之前所谓学习过的数十种语言中完全不曾分辨的概念! 所以我有种预感,Rust有戏!

大家都能感受到的吧,编程语言的设计都透露出一种哲学,在哲学上,如果把一个概念辨析得越清楚,那么它分析问题就越犀利。这就是我的初步感受。后来就开始认真学习,参与各种社区的讨论,先是在Google Group上发现了liigo建的群,当时群里只有2,30人。后来,我们早期几个人又一起建了个论坛 http://rust.cc ,好让rust在中国有个根据地。说起来这个Rust的服务器是由SpeedyCloud免费提供的,放在香港,感谢他们对开源社区的支持。

被动态语言宠坏的人,其实都比较懒,对很多细节的概念也比较模糊。所以,我学起来也还是比较吃力的,跟大部分人一样。

其中有一些比较蛋疼的事情,Rust在1.0发布之前,特性变化得很快,一般来说,上一周的代码拿这周的Rust编译器是编译不过的。然后,例子也不多,网络上绝大部分其它的文档都过时了的,不能看。这种情况一直持续到15年的4、5月份。5月15日,Rust 1.0 发布了,官方会保证兼容性。然后我们就开始用了,于是,我准备先把之前我写的bamboo web开发框架翻译成 Rust,取名叫bamboors,但是翻得基本能跑起来后,突然发现,nickel.rs 已经实现了我想要的绝大部分功能了,而且很多方面,比bamboo想得还周到。那何不就基于nickel.rs来做呢,以及为nickel.rs社区做贡献呢,于是就开始了使用nickel.rs写妈咪问问后台的征程,下面是我在这个工程中用到的一些依赖库:

[dependencies]

hyper = "~0.5"

postgres = "*"

rustc-serialize = "*"

mime = "=0.0.11"

redis = "*"

chrono = "*"

log = "*"

fern = "*"

nanomsg = "*"

rand = "*"

rust-crypto = "*"

#image = "*"

toml = "*"

lazy_static = "*"

jsonway = "*"

json_macros = "*"

为什么要用Rust,以及其他语言的对比 

要详细说起来,我觉得可能有几点:

  1. 我被Rust震惊了,认为它将来必火,而我在技术上的直觉自认为还蛮准的;
  2. Rust运行速度快;
  3. Rust代码写起来真的是很严谨,很清晰;
  4. Rust工程开发效率不低(出乎很多人的意料)!

在使用体验方面,一般来讲,使用Rust设计一个模块前,要前前后后把模块的前端后端、数据库怎么设计、交互这些都想清楚,一步一步写下来。然后,就开始用Rust实现,一般我用Rust写完代码后,编译会出现很多问题。这时Rust编译器的提醒很清晰,一眼就知道哪里遗漏了,哪里写法不对,哪里类型不匹配。然后,修改等编译通过后,跑起来,就可以测试业务正确性了。

Rust号称,只要你能编译通过程序就不会崩溃的,我没有精确统计过,不过我感觉我的一次正确率在95%,这个指业务逻辑的正确率,我觉得这就是Rust的威力!而我之前用动态语言的时候,一次成功率不超过 7~80%,因为动态语言允许你放肆……人嘛,有时都喜欢偷懒,有时求快,问题没有完全想清楚就开始动手了,结果开发效率反而低了。

总体而言,我感觉 Rust 写业务代码的效率和Node.js写业务代码和效率差不多。Rust写的代码多一点,写得慢一点,会花费编译时间,但是相对于Node.js,如果加上调试时间的话,就差不多了。如果再加上问题没想清楚就动工的话,Rust可以胜出。因为如果你问题没想清楚,你写的Rust代码一般来说都是编译不下去的,会强迫你想清楚!然后,用Rust写的代码,测试用例不用很多,这个相对于动态语言也可以省大把开发时间和大把维护时间。

而作为创业项目,一般都是要求尽快撸出业务,尽快上线,上线后再迭代,因此一般都会选择动态语言来开发。但是我觉得,这并不是说不要把问题想清楚,就可以因为追求快上线就可以放弃稳定性。

我用Rust开发的过程中,也碰到很大的进度压力,这时怎么办?我代码里面现在还存在大量的unwrap(),这个其实是有风险的,也就是说我没有做详尽的错误处理。这个时候,比如一个参数或一个状态不正确,就可能导致服务器(线程)崩溃——对的,是线程崩溃,不是整个服务器崩溃。我也犯了先撸业务的毛病,但是Rust能帮助我明确问题,减轻痛苦:

在测试过程中,我发现一旦出了问题,我们可以很快地定位问题代码——因为这些代码都在unwrap()或其它未处理的异常语句那儿,这是一个很重要的特性!等进度缓和一点,或人手充裕了后,就可以来着手补全这些unwrap()的处理了。因为Rust基本能保证,除了这些地方,其它地方的代码,一旦编译通过,是不会出问题的。这就给人一种很踏实的感觉——可预测性,这个对于工程和科学来讲,很重要。

如果一个东西行为不可预测,那我们心里一天都是提心吊胆的,程序员容易猝死,我想是不是也有这方面原因。

使用 Rust 遇到的问题及解决之道

这3个月,大概遇到这么几个问题

  1. nickel.rs(底层是hyper),作为一个Web Server竟然不能暴露出端口来直接访问,这里的不能不是不可以,是不好。比如一个4核的机器跑hyper线程池,默认是开启10个,但如果有10个keep-alive连接连上来,那么第11个连的就卡住了,当时查这个问题查了一天,后来,把它架在nignx代理后面就好了,估计这也是hyper在ab上测试不过的原因;
  2. nickel.rs 目前是基于hyper 0.5的,而现在hyper 0.6的接口已经变化了,nickel没有跟进。最近他们的开发有点不太积极了,所以,我计划我们可以组织起来来维护这个东西;
  3. 图片处理库的问题。rust有一个库(crates.io上)叫image,用作图片处理。开始我以为他很强大,至少应该跟gd库不差,可它很多格式的图片都不支持,就连JPG都支持不全,后来还是用了 imagemagick 的 convert 来处理。所以,这些都是生态不完善的结果。

对打算学习和使用 Rust 人的建议

首先,要有心理准备, 接受一些新的概念 。这些核心的概念是有其价值所在的,我见过很多新同学,一上来就说Rust这样写也不行,那样写也不行,太不方便了。这样特性也没有,那样特性也没有,功能太弱了。这实际也是在反应他之前的编程的严谨性可能是有一定问题的,就我自己来说,用了rust一段时间后才发现自己以前写多线程程序有太多没有注意的地方。

与此同时,因为现在Rust文档比较缺乏,上手难度相对较高,所以比较容易卡在编译阶段,这时,可以 多看官方文档

借力社区。 论坛、QQ群、微信群等都有很多的大牛,不懂的就问,是解决问题的最佳之道。社区最近也在讨论、翻译技术文档、出书和录制视频教程等事情,让Rust的学习更加的容易些。

参与项目。 我们也会组织一些开源的Rust项目,大家一起来参与,可能学习进步会更快一些,可参见:github.com/rustcc 和  http://play.rust-lang.org /(交流Rust代码的好地方)。

QA环节

John:Mike有没有关于使用Rust和Node过程中开发效率和运行性能对比?

Mike: 对比开发效率,差不多。运行性能的话,我测试的nickel.rs和node echo 对比,在我机器上,nickel.rs 是48000,node是 23000。目前我们系统处理当前的业务已经够用了,不行就扩展服务器。

Andy:Mike你提到过“Rust开发测试用例不用很多”,能解释下为什么吗?和Ruby/Java分别对比的话,Rust的测试有什么优势?

Mike: 因为首先,参数类型不用测试了,这个就省很多代码。Rust的cargo管理工具内建测试机制三个层次的,很方便。Java、Ruby也类似吧,但是感觉没Rust这么方便。另外,Rust和cargo还能对文档注释中的代码进行测试,所以说,Rust是实用主义派——近15年最佳工程实践的集大成者。

cuterxy:Rust 支持增量编译吗?大工程如何管理?

Mike: 支持支持增量编译。cargo是一个项目管理工具,如pip,cargo管理工具大量吸收了Ruby社区的优秀经验,Rust的module机制,也很适合大工程管理(作者做了bundle,然后rust组把他邀请过来给rust做)。

Mike:Rust是近15年最佳工程实践的集大成者

toml格式的配置

正文到此结束
Loading...