Home > study > [译]Why do you like Erlang?

[译]Why do you like Erlang?

November 20th, 2007 :: jackyz

作者:Tony Arcieri (Dive into Erlang)
原文:http://www.clickcaster.com/items/why-do-you-like-erlang
译者:朱照远(Joshua Zhu)

Not invented here

mryufeng 同学对于这一篇有过一个评价

感觉写的非常好(激动中) 和我的经历几乎一样 得出的结论就是: erlang就是我要的 网络应用erlang足够强大了

共鸣很强烈啊。

这篇文章也可以认为是一位长期战斗在“高性能服务器开发”第一线的兄弟“从 C 到 Erlang 的心路历程”。文中涉及了 n 多的技术框架和背景知识,从中我们可以看到一个完整的“服务器开发技术路线进化图谱”,非常精彩。现在好了,朱照远(Joshua Zhu)同学为我们扫清了语言障碍,带来了这篇文章精彩而生动的中文翻译版。

让我们对 朱照远(Joshua Zhu)向 erlang 中文社区作出的贡献表示感谢!

在线版请继续阅读,为方便收藏阅读,同时也提供 PDF 版,点此下载

自从大约两个月前我变成了一个Erlang铁杆以来,人们经常问我这个问题。我认为最好的解释方式就是把它作为Greenspun第十定律的一个推论:任何足够复杂的并发的C程序都内含了一个临时拼凑起来、没有正式规范、充满错误并且低效的半吊子Erlang实现

我一直着迷于那些要处理大量并发连接的网络服务器的开发。多年以来,我尝试着用C来写,考察了事件监测的很多不同方法,也研究了诸如《Unix网络编程》这些书中所描述的不同的实现网络服务器的方式。遗憾的是,我发现这些模型和方法中的不少都已经过时了。自从glibc支持了Linux,线程模型就变成了事实上的标准。

几年后,我决心用每个请求一个线程的模型来实现一个大规模并发的网络服务器。此前,我已经建立起一个属于我个人的服务器框架,伴随着该框架有很多操作系统的基础设施的抽象接口,并且我已经写了一个有超过2万行代码的网络服务器。

正是在这个时候,我开始在线程方面碰壁。本来,我已经对Win32和pthreads之间进行了跨平台的线程模型抽象,正在很多平台上测试。我开始注意到,在某些平台上我会遇到死锁,但是其余的则不会。随着数据结构高级程度的增加,我开始发现更多的死锁。当那些重要的共享数据需要在所有线程之间进行同步的时候,锁变得更复杂,更难调试,程序性能也开始下降。

我开始更加了解互斥量的开销,这种开销对于一个关心性能的C程序员来说是非常令人抓狂的。例如,在Win32平台上锁住一个互斥量,需要使用超过600条的CPU指令!我很快意识到最好的的方法确实是一个CPU核上只跑一或两个线程,并且,能避免线程同步问题的更轻量级的并发机制是处理大量并发连接的更好方法。

首先映入我眼帘的是《计算机程序设计艺术》中描述的Knuth协程,它们提供了一种轻量级的协作调度方法,不需要系统调用即可在它们之间进行切换。GNU Pth库的实现和其非常类似。我找到了很多相似的用户空间线程的方法,其中包括像被Win32纤程和*IX的ucontexts实现的“微线程”思想。

所有这些方法的最终目标都是从把行为和功能分离开。每个原生线程(假如你有超过1个)都把它的行为隔离进一个内嵌的事件循环,功能则可以被实现为一个微线程。

假设已经到了这一步,当你发现你需要一种在微线程之间传递消息的途径的时候(该途径要在某种意义上抽离出网络I/O事件的处理,并且如果你使用了线程,那么也允许你在它们之间发送消息),问题便接踵而至。我就这个问题实验了很久,弄得在多事件源和线程模型之间的抽象相当的复杂。

结果是,为了建立一个并发网络编程框架,我付出了多年的努力,却从来没有达到一个让我满意的程度。我从来就没有感觉到我已经真正把我要去解决的那些问题抽离出来了。

终于,我认识到不共享任何东西才是可行之道。我开始对Dan Bernstein的qmail迷恋起来。Qmail使用了很多不共享任何东西的操作系统进程,它们通过管道进行交互以处理网络通信。厌倦了线程,厌倦了微线程,也厌倦了企图去同步共享的信息,这就是我得到的最终结果。Unix哲学的智慧“做一件事情并且把它做好”最终在我的眼里彰显了它自己。

最后,我发现了Erlang。随着我对它了解的越多,我越认识到它正是那个我期待了很久的模型的一个绝对卓越的实现(我自己曾经企图去实现过)。此外,它还把每CPU内核上多个原生线程轮流运行多个“微线程”的模型与一个消息通信系统整合在了一起,远比我自己当初的整合要优雅得多。

对于那些还不了解的读者,这是从最近出版的《Programming Erlang》一书中摘录出来的关于于Erlang消息处理的一个描述:
1.当进入一条receive语句的时候,我们启动一个计时器(但是仅当表达式中存在一个after段的时候)
2.取出收件箱里面的第一条消息并尝试和模式1,模式2等等进行匹配。如果匹配成功,则把该消息从收件箱中删除,这一模式之后的表达式将被求值。
3.如果receive语句中没有任何消息匹配,那么第一条消息被从收件箱中删除并放于一个“保存队列”中。然后,尝试收件箱中第二条消息。这一步骤被重复直到找到一个匹配的消息或者收件箱中的所有消息都被检查完毕为止。
4.如果收件箱中没有消息被匹配,那么进程被挂起并且会在下次一条新的消息放置于收件箱中后被重新调度执行。注意,当一条新的消息到达的时候,保存队列中的消息不会被重新匹配,只有新的消息才会被匹配。
5.一旦一条消息已经被匹配,那么所有已经被放进保存队列的消息将按照他们抵达进程的顺序重新进入收件箱中。如果设置了计时器,那么该计时器会被清掉。
6.如果在我们等待消息的时候计时器已经耗完,则计算ExpressionsTimeout的那些表达式,并且把保存的信息按照它们抵达进程的顺序重新放回收件箱。
读完这个以后,我认识到这就是我一直在尝试发明的东西。我把它给Zed Shaw看了(他可能以Mongrel web服务器的创建者被你所知)。他表示这和他在Myriad框架中实现的消息处理方式非常类似。我不打算为Zed就Myriad是一个Erlang的重新实现这一点去辩护什么,我只是要指出当人们处理此类问题足够久之后,人们得出解决这类问题的结论是相同的。

总之,我对Erlang处理事情的方式感到自然的舒服。一直以来,我就是这样写程序的。终于找到了一门抽离了所有处理并发网络复杂行为的语言,这种感觉非常爽。更进一步,就一旦所有底层问题都被抽离,你能构建出什么这方面而言,分布式Erlang和OTP框架更是超过了我最疯狂的梦想。

现在我终于可以不用试图构建一个临时拼凑起来、没有正式规范、充满错误的框架了,我开始集中精力于我实际上一直所关心的:功能。

study

  1. November 20th, 2007 at 18:52 | #1

    精彩

  2. Joshua Zhu
    November 20th, 2007 at 19:30 | #2

    呵呵,举手之劳而已,jackyz兄太客气了 :)

    P.S. 译者名字应该为朱照远(不是“元”) :P

  3. jackyz
    November 21st, 2007 at 22:20 | #3

    汗,赶紧改过来了。

  4. Tank
    November 21st, 2007 at 22:40 | #4

    跑个题:)
    Windows下的完成端口(IOCP)不好么?IIS就用IOCP,ms网站的访问量不大么?

  5. November 22nd, 2007 at 07:25 | #5

    to tank:
    面包车不是挺好吗?面包车拉的人不是很多吗?那干嘛要出奔驰!

  6. xushiwei
    November 22nd, 2007 at 08:15 | #6

    to tank: 也跑个题,不觉得ms网站巨慢吗? :)

  7. Tank
    November 22nd, 2007 at 09:20 | #7

    呵呵,那说正经的
    书上(Jeffery Richter的《Programming Server-Side Applications for Microsoft Windows 2000》第二章,网上有ebook)说,IOCP是Windows下实现高并发服务程序的最佳方式,但我没实做过IOCP的server app。 我虽是ms的粉丝,但更是事实的铁粉,所以想请老大们用实例比较下,IOCP实现的套接字服务程序到底比Erlang实现的套接字服务程序的并发性到底低多少?(套接字服务程序从客户端读入xxK数据,计算pai值到n位,然后将pai值及接受到的数据echo回客户端)

  8. November 22nd, 2007 at 09:30 | #8

    to tank: 你的思路还是停留在比拼tcp连接的接收能力上 实际上这部分只占服务器开发很小的一部分 我不想比较这方面的能力 因为没有意义 但是我想告诉你一个数字echo服务器 4G内存 epoll erlang已经可以处理300K个客户端了。

  9. Tank
    November 22nd, 2007 at 10:16 | #9

    hi mryufeng,您说得太对了,确实,服务器开发中还有更多要考虑的东西,单纯比某一样没太大意义。说高层的应用,那就是事务,安全,WS-*什么的了,记得以前有过Java petshop vs. .Net petshop大战,现在何不搞个Erlang petphop vs. WCF petshop大战呢?(或口水战)

  10. Tank
    November 23rd, 2007 at 19:05 | #10

    初来贵地,冒犯之处,请牛人们海涵。相信这里不是新语丝,各位也不会像方舟子老师那样钻进小楼成一统。
    传统的并发处理方式存在,并占绝对主流,一定有它的优点。我虽不做底层,但还是有些兴趣。哪位牛人能从实验数据出发,深入浅出、图文并茂的分析Erlang、IOCP的本质、各自的优劣,那真是太好了,相信这对弘扬Erlang也大有裨益。
    Regards

  11. jackyz
    November 24th, 2007 at 11:21 | #11

    Tank,你不必介意 yufeng 的大糙话,erlang 的社区小,大家熟,一向浑来浑去惯了,吓到你了吧。不过,你大可以放心,这里既没有什么“小红楼”,也不会有人对“一统江湖”什么的感兴趣。

    不过这里倒还真是有一小撮“人老珠黄的老程序员”(比如说,我),这些家伙成天懒洋洋的,只喜欢插科打诨互相掐架,没几句正经,一到晚上就精神抖擞目光炯炯,拼命敲键盘。再加上大家都有挣钱养家的活要赶,对于 csdn 式动辄洋洋洒洒数万言的“xx vs yy”精彩大战没有时间关注也是可以理解的吧。

    虽说我年纪也老大不小了,但和你一样,对于 erlang 接触的时间也没多久,对于其本质,真不敢妄论。至于实验数据,一向都是很欢迎的。如果你有兴趣做个实验,搞搞分析,真的也很不错啊。如果能够旁征博引、图文并茂、深入浅出,那就更好了,简直求之不得。怎么样,你来搞一篇吧,我帮你推荐给《程序员》的编辑(这句完全可以当真)。

  12. pi1ot
    November 27th, 2007 at 15:58 | #12

    “我开始集中精力于我实际上一直所关心的:功能”
    真正能决定一个server到底能抗多大并发的也得看每个请求具体执行了什么功能,把处理每个请求消耗的服务端资源降下来远比硬撑更多的访问数量来得重要。

  13. January 8th, 2008 at 18:50 | #13

    心路历程啊,有收获!

  14. simon
    January 18th, 2008 at 15:49 | #14

    好文!erlang值得一学。

  15. May 27th, 2010 at 11:47 | #15

    Hello, blogger, your article very good, looking forward to sharing your latest

  1. No trackbacks yet.