關於開源訪談
開源訪談是開源中國推出的一系列針對國內優秀開源軟件作者的訪談,以文字的方式記錄並傳播。我們希望開源訪談能全面的展現國內開源軟件、開源軟件作者的現狀,着實推動國內開源軟件的應用與發展。
【嘉賓簡介】
陳碩 北京師范大學碩士,擅長 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. 我們的訪談已經嚴重超時了,感謝你對開源中國的支持,下次有機會繼續探討。
好的,非常感謝,再見!