[转] 【开源访谈】Muduo 作者陈硕访谈实录
关于开源访谈
开源访谈是开源中国推出的一系列针对国内优秀开源软件作者的访谈,以文字的方式记录并传播。我们希望开源访谈能全面的展现国内开源软件、开源软件作者的现状,着实推动国内开源软件的应用与发展。
【嘉宾简介】
陈硕 北京师范大学硕士,擅长 C++ 多线程网络编程和实时分布式系统架构。现任职于香港某跨国金融公司 IT 部门,从事实时外汇交易系统开发。编写了开源 C++ 网络库 muduo; 参与翻译了《代码大全(第二版)》和《C++ 编程规范(繁体版)》,整理了《C++ Primer 第4版评注版》;曾多次在各地技术大会演讲。
【软件简介】
muduo 是一个基于 Reactor 模式的现代 C++ 网络库,它采用非阻塞 IO 模型,基于事件驱动和回调,原生支持多核多线程,适合编写 Linux 服务端多线程网络应用程序。视频连接:http://v.youku.com/v_show/id_XNDIyNDc5MDMy.html
【访谈实录】
1. 你先介绍一下你自己吧,包括学习经历和工作经历
我2000年上大学,本科和硕士都是在北京师范大学,学的是电子信息专业(原来的无线电系)。2007年硕士毕业到上海工作,在摩根士坦利信息技术有限公
司。到了2010年6月份,公司调我到香港工作,摩根士丹利亚洲有限公司。我第一份工作到现在已经做了五年,没有换过。我工作的内容一直是用C++开发实
时外汇交易系统。
2. 你学的是无线电,跟编程还是有点差异
我们学院的课程设置中,计算机系和电子系重合的部分很大。电子系也讲授C语言、数据结构、汇编语言、计算机组成原理、计算机网络、计算机图形学等等偏CS的课。另外我自学了操作系统课,编译原理也学了一点皮毛。因此我算是半个科班出身。
3. 那你们电子方面是不是用 C 用的比较多?
如果从电子系传统来讲的话,是硬件描述语言(Verilog)和 C 用的比较多。但现在国外嵌入式中 C++
应用也很多,从厂家提供的工具链和各大嵌入式会议的议题就能看出来。国内的话守旧观念势力比较大,大家觉得其他语言不可靠,摸不透,不愿意换其他生产力更
高的工具。单片机上用 C 比较多,我写过8-bit单片机上的C程序。但是稍微大一点的32-bit单板机上就可以用
C++,只要能跑操作系统的就能跑 C++,有C++编译器就能跑。
4. 是什么促使你开发Muduo这个网络库的呢?
我的兴趣是分布式系统,但是搞分布式系统的前提是要有一个足够好的网络库。我有很多想法要写,比如说实现consensus
的Paxos算法,还有其他一些分布式的协议的实现。在写这个网络库之前,我看了一些别的C/C++网络库,觉得还是自己写一个比较靠谱。另外一个原因是
2010年3月份,我写了一篇博客,关于 ACE 的,它是一个古老的 C++
网络库,博客文章叫《学之者生,用之者死——ACE历史与简评》。我在文中描述了我对网络库功能需求的理解。因为2010年我已经工作三年,写了很多网络
相关的程序。所以我决定按照我对网络库功能需求的认识,实现一个符合我价值观的网络库。另外,muduo不只是一个网络库,它还包括基本的线程库、日志
库、日期时间库等部分,可以算作一个基础库。总之我认为编写C++多线程服务端网络应用程序所需要的功能在muduo里都有,muduo体现了我对这个领
域的理解。
5. 为什么要叫Muduo这个名字,怎么念呢?
一般可以念成拼音,木铎(念:夺)。“木铎”是木舌金铃的意思,引申义是教育传播,摇铃铛以吸引行人注意。我选这个名字还有其他几点考虑。首先这个名字要
用作 namespace(命名空间),就跟 boost 一样,所以不能太长,敲键盘要比较方便。Boost 是五个字母,C++
标准库std是三个字母,我觉得还是不要超过五个字母为好。然后名字不能是英语单词,因为五六个字母的英语单词一定已经被用掉了,你搜这个单词就搜不到
我。也不能都用首字母缩写,这样就只能按字母来念(就像HTTPS)。库的名字要能顺口念出来,一两个音节最好。中国人能读,老外也能读得八九不离十,所
以不能用xue之类的拼音。综合一下这些条件,选择也就不多了。选这个名字我还是花了一点心思,最后想到了北师大的校徽,干脆就用muduo了。
6. Muduo这个域名拿下了吗?
我拿了一个 muduo.info 的域名。muduo.net 是北师大的校园网,muduo.com 也是别人在用,muduo.org
是一个人博客。我2010年的时候没有想着去拿域名,当时这三个主流的域名就已经被注册了,最近想拿就只能拿一个 muduo.info 的。
7. Muduo相对于别的网络库来讲,它的优势和特点是什么呢?
先说特点。Muduo有一个很明显的特点是不可移植的。一般的网络库会把跨平台可移植当做一个卖点。而我特意选择只在 Linux
上实现并优化,这个算是特点。因为大规模分布式系统通常都会在Linux上开发部署,支持其他平台没有多大意义,我个人精力与知识面也不够。还有一个特点
是只支持 TCP。有的网络库会以支持TCP、UDP、ICMP、串口等各种协议为卖点,muduo则不然。Muduo的特点是只支持 TCP
,而且只支持 IPv4。因为我不认为开发公司内部使用的分布式系统会用到其他传输协议,更不会在内网用IPv6。muduo只支持one event
loop per
thread这一种并发模型,只使用非阻塞IO,因为这是Linux下使用native语言编写高性能网络程序最成熟的模式,Muduo适合编写有较多并
发TCP长连接的网络服务。甚至连 DNS 解析都只支持异步的解析,没有直接的一个函数调用就能从域名拿到
IP,因为这样会阻塞。总之,我认为在开发公司内部系统中用不到的东西我都没有支持,muduo是有明确的适用范围的,它不是那种大而全的网络库。减少选
择,让你节省时间,少走弯路。
再说优势。优势之一是API设计。Muduo是一个现代的 C++
网络库。现代和古代的API区别在于两方面。一个是事件回调,另外一个是资源管理。一般的网络库设计API的方式是定义一个接口(抽象基类),包含几种网
络事件对应的处理函数。你的代码去继承这个接口,这个接口会定义收到消息是回调哪个虚函数,然后你覆盖一下这个虚函数。然后把你的对象注册到网络库中,发
生事件的时候就回调你的虚函数。一般的 Framework 都这么搞,这就是传统的或者说古代的 C++
网络库的做法,也是Java网络库的做法。这种做法在C++中面临的一个直接问题是对象的生命期管理,因为C++的动态绑定只能通过指针和引用来实现,你
必须把基类指针传给framework,才能获得事件回调。那么这个派生类对象何时销毁就成了难点,它的所有权到底归谁?有的网络库甚至在事件处理函数中
出现了delete this;这种代码,让人捏一把汗。
我现在的回调方式是用boost::function,它在TR1时已经进入
C++
标准库。Boost::function不对类型和函数名做限制,只对参数和返回类型做部分限制。如果你通过传统的继承来回调的话,你这个类型必须是
framework里某个基类的派生类,函数的名字必须一样,参数列表必须一样,返回类型也基本肯定是一样。但是boost::function没有这些
限制。Muduo网络库不是一个面向对象(object-oriented)的库,它是一个基于对象(object-based)的库。它在接口上没有表
现出继承的特性,它用的是boost function的注册/回调机制,网络事件的表示就用 boost
function。所以对Muduo来讲,它不需要知道你写什么类,也不强迫继承,更不需要知道你的函数叫什么名字,你给它的就是一个 boost
function对象,限制就很少。而且你没有把对象指针传给网络库,那么就可以按原有的方式管理对象的生命期。
还有一个优势就是资源管理,Muduo在一处最关键的地方用了引用计数(Reference
Counting)型智能指针,当然我没有自己写,用的是标准库的shared_ptr。我只在表示 TCP
连接的class上使用了引用计数,是因为TCP连接是短命对象(short-lived)。但是当连接被动断开的时候,网络库不能立刻销毁对象,因为用
户可能还持有它的引用,准备用来发消息。如果直接delete,有可能造成空悬指针。因此既然TCP对象是网络库和用户代码共同拥有,那就用引用计数好
了。Muduo用引用计数是经过仔细考虑的,也没有用在其他长命的对象上,这些长命对象的生命期可以由用户代码直接管理。用Muduo你就不用担心指针失
效的问题,可以避免一些古老的 C++ 程序中的一些内存错误。
这种用对象来封装文件描述符等系统资源的做法是C++独有的资源管理方式,称为RAII。通过把文件描述符的生命期与对象等同起来,我们还能有效地避免串
话(cross
talk)。比如说,操作系统给你一个新的TCP连接,文件描述符就是一个小整数,这个整数可能等于刚刚关闭的某个TCP连接的文件描述符。比如你现在有
一个连接号是3,你把连接关了再打开有可能还是3,所以就带来连接管理方面的一些麻烦。如果你是用 C
写,不小心的话就会造成你这里关了3这个连接,但是程序其他地方还在往3这个连接发消息(考虑多线程的话更头疼),但其实3这个连接已经指向其他地方了,
就跟使用野指针一样。用RAII就没有这个困扰,因为3这个连接的生命期和对象绑定,对象活着,连接就不会关闭,也就不会有其他对象同时使用了3这个文件
描述符。
最后,Muduo的性能也是让人满意的。我在编写Muduo的时候没有以“高性能”为首要目标。在完成并开源之后,受网友启发,拿它和其他一些网络库做了
性能对比,发现相比通用的跨平台网络库(libevent2、Boost.Asio),muduo有明显的性能优势。相比专用的网络程序
(Nginx,ZeroMQ),muduo的性能也不落下风。
8. 也就是说在资源管理方面是比较可靠的,不会混淆和不会泄露
是的,首先是资源在不用的时候一定会释放,其次是通过对象来管理文件描述符可以有效地防止串话。
9. Muduo目前的推广是怎么进行的?
我主要在博客上写一些文章,没有特别的推广。有些线下活动会参加,讲讲这个项目。
10. 那这个项目目前在实际产品中的应用如何?
我们公司不用muduo,公司有自己的网络库,在我加入之前就成熟了。从个人邮件来往看的话,有人在学,有人编译了试用。具体有没有哪个公司在用我也不清
楚。Muduo的特点之一是它代码只有5000行,如果你认真读一遍,花一个星期理解透,然后自己写一个更好的也可以。不一定非要用我这个原装版的。关于
C++
网络编程的技巧啊,陷阱啊都在代码里,而且写的很清楚。Muduo的代码是写出来给人看的。Muduo的目的之一也是放在那里让人学的,所以为什么叫木
铎,这个名字也有相应的含义,刚才也说过了。
11. 根据你刚才的描述,那开发和维护Muduo的人员应该也只有你一个吧
是的,只有我一个,在工作之外的业余时间开发。
12. 有没有人提交过 bug fix 或者 pull request 之类的?
这个项目在 Google Code,源代码是在 Github 上管理的。有一个 Pull
Request,但不是针对代码的,而是针对编译选项的。是关于 boost 库的一个警告,但是我查了一下,应该是 boost 的问题,我向
boost 提交了这个 bug,看他们修不修吧。
13. 那平均一周你花费多少精力在开发和维护Muduo这个项目上面呢?
要看我有没有新的想法。比如上周我就花了很多时间把多线程非阻塞日志库写好了,花了一整个周末。平时的话可能一周看都不看。去年花了挺多时间是要写博客,
写各种例子。Muduo这个库的例子很丰富,编译出来大概有近百个可执行文件,各种网络编程常用的功能都有,例如聊天,文件下载,广播等等。而不像有些网
络库只有一个 echo 的例子。
14. 你是2010年开始做的吗?
我是2010年三月份开始做,到八月份的时候就开源了。实际上我写了一两个月写完了但是没有立刻开源,因为那会儿正好从上海搬家到香港,杂事很多。在开源
之后主要工作就放在写例子上。写到11年底,我那个博客系列写完了,没有更多简短的例子可以写了。然后我就开始做另外一个项目,是用Muduo和
Google Protocol Buffer RPC 做一个分布式系统中的多机服务管理软件,还没做完。
15. 我们一天按8小时算,你觉得到目前为止花费在Muduo上的时间有没有一个月?
一个月以上
16. 那差不多两个月的时间?
算两个月吧。其实学习思考的时间很多,我有时候看到一篇博客,影响了我的想法,就会把这个思路实现一下。
17. 目前看来你应该是没有从Muduo获得任何收入?
没有收入
18. 那你觉得你做这个事情和你的全职工作有冲突吗?
我觉得没有冲突,实际上能帮我更好地理解 TCP
网络编程。我们在公司用肯定是用写的很好的(现成的)网络库。正常情况下,网络库就是收发数据而已。那如果网络出问题,应用程序有哪些异常的表现的话要写
过网络库才清楚,不然的话就只能看别的网络库的文档,查不出来问题的根在哪儿。对公司来讲,这是有正面意义的,如果公司的服务发现网络方面有问题,特别是
在跨洲的网络环境里面,例如伦敦发到纽约这种,你就会有一些思路,可能是某某问题,应该如何确认,确认之后可以怎么调一下。
19. 你的老板知道你做了Muduo这样的一件事情,就是你业余也会做些开发,写写博客之类的?
我老板估计不知道,其他组有几个同事知道。我最近一年来没有写长篇博客,因为CSDN博客不再支持Live Writer发布,而我一般喜欢同时发到cnblogs和cppblog这几个地方。
20. 呵呵,那应该他知道了也不会在乎这个事情吧
应该是吧,我们公司对开源有比较明确的政策,不能涉及公司的信息。Muduo的编写也没有使用任何公司资源,我甚至从来没有在公司的机器上下载编译过源代码。
21. 上次我跟你聊的时候,我记得你对于通过Muduo获得收入是很谨慎的,因为你是全职在摩根士丹利工作,是吗?这是在你的劳动合同上注明的吗?
我们员工行为准则有一个叫做利益冲突条款,其中一条是不能通过摩根士丹利雇员的名头来牟利。因此我在私人活动中不能宣称自己是摩根的雇员,以免引起联想。敝公司对员工在工作之外的行为要求比一般的公司要严格。
22. Muduo将来的发展方向你有过考虑吗?
我是2010年8月份推出0.1.0版,到2012年5月份是0.3.5,它是每0.0.1增加所以一共有25个版本。0.3.5及其以前的版本都是
alpha 版,我上个星期(2012年6月初)推出的0.5 beta 版。这个 beta 版的区别在于它有一个实际可用的日志库。以前的
alpha 版日志只能写到屏幕,现在加了文件日志那它就可以实际拿来用了,所以是 beta 版。
23. 那你对 1.0 有没有想法呢?
有,1.0的时候应该把网络库的单元测试做好。因为muduo网络库涉及到 IO和多线程,IO
的单元测试会比较麻烦。特别是各种出错的情况,你怎么让操作系统返回你想要的错误。这个我有一些想法,也已经写了博客,但还没有时间去真正的把它做出来。
现在的测试是手工完成的,不是很好。到2.0的时候会用 C++
11,或许会利用右值引用和移动语义提高一些内存复制方面的性能。但是目前主流的Linux发行版自带的GCC编译器版本都还没有支持 C++
11,要等 GCC 4.6普及了以后才行。
24. 你觉得网络游戏服务器是不是你这个库比较好的应用场景?
如果你从处理并发长连接这个方面来讲是没有问题的。但是Muduo不支持 UDP,如果你的游戏需要用 UDP
通信的话,那你需要做一些改动。另外就是网络游戏可能会在安全性方面有所考虑,比如说抵御一些网络攻击,但是Muduo并没有在安全方面做特别的支持,因
为它考虑的是公司内网的网络环境。
25. 也就是说Muduo是为公司内网的分布式系统设计的?
可以是公司内网的全球规模的分布式系统,但并不是为公网使用而设计的。但是你可以用一个比较抗暴的连接服务器放到公网上,然后用Muduo来完成连接服务
器之后的那些业务处理工作。我个人在安全性方面并没有很多的研究,我只知道网络攻击的方式五花八门防不胜防,所以如果我说可以用(在公网用)的话那是在坑
你。
26. 国外有很多成功的开源项目,但是国内似乎没有,你怎么看这个现象?
很多公司用了开源项目,并且修改了,多半是不愿意把修改回馈给上游的。比如说优化了一下性能,或者增加了一些功能我公司内部用就很好了。我觉得公司尚且如此的话,那么个人就只能凭借兴趣爱好参与了。
27. 也就是你认为国内开源做的不好是因为没有公司的推动?
也不能这么说。如果公司要用外面贡献的代码是要签协议的。比如我上次给 Google glog提一个 bug,我给他一个 diff
文件,他想用这个 diff 文件,他要我跟他签授权协议,要明确我愿意贡献出这段代码的知识产权。因为如果没有这个协议的话,我以后可以告
Google
说你用了我一行代码。所以如果开源项目的维护是公司的话,是会有这些法律方面的问题。所以法律方面也要跟上,让公司觉得做这个事情是安全的,否则他宁愿不
接受外界的贡献。
28. 所以你觉得是因为国内法律方面的缺失,导致了公司感觉没有保障性?
应该说是没有这个先例吧,我不晓得有哪些律师在这方面很在行。我不知道是不是可以由知识产权方面的律师来拟定一个关于代码贡献的合同。只有这些都有了才能
做双向的开源。否则就是单向的,我(公司)把代码放出来你们可以看,但是改只能我改。你可以提bug,但是只能我来改,我不会把你的 patch
拿进来,估计也没人提交
patch。而且在公司具有话语权的人,他不一定是搞技术的,他一定会考虑这个事情会不会影响公司形象,或者惹上官司等等,往往这种项目都不会通过。
29. 你有没有一些建议给刚入门的程序员,帮助他们成长?
程序员成长该看什么书之类的应该有很多人讲过,我就不多费口舌了。我认为在国内这个环境下新手不要上国内论坛问问题或参与讨论,你可以去看国外论坛别人问
的问题与回复。但是国内论坛充满了口水战、抬杠、灌水,就算有人回答你的问题,你怎么知道回答的人是真懂,还是半瓶水晃荡,又或者是道听途说人云亦云呢?
如果新手提问的话,要么就是问题很简单别人不乐意反复回答,或者糊弄你几句让你看书去;要么就是问题太复杂,没有人愿意花时间写几百字详尽解答。而且新手
通常也问不出什么有新意的问题,基本上都是别人问过回答过的,多用搜索就能解决。所以我觉得少上论坛,浪费时间。
30. 你这个观点很独特,我第一次听到。你对开源中国有什么意见或者建议吗?
现在功能相近的开源库很多,开源中国是不是能做一些实测评比,用不同的库实现相同的功能,然后在相同的运行环境中比一比性能和使用的难易度。对于网络库而
言,有一个不错的测试用例:http://blog.yufeng.info/archives/116中提到的hotwheel。
31. 我们的访谈已经严重超时了,感谢你对开源中国的支持,下次有机会继续探讨。
好的,非常感谢,再见!