我与Go的缘分:成长的十年
Posted 许式伟
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了我与Go的缘分:成长的十年相关的知识,希望对你有一定的参考价值。
Go语言刚刚度过了它的十周年纪念日。而要说我与Go的缘分,也同样始于十年前(2007年)。这十年,是Go成长的十年,同样也是我成长的十年。
2007年2月,我建立了金山实验室,主攻分布式存储方向。这是我职业生涯至关重要的一个转折点。此前我已经做了7年的WPS Office办公套件的研发。这对我有两个重要的挑战:一个是角色转换上的,从做软件研发的架构师到做业务的产品经理;一个是技术领域变化上的,从单机的桌面软件开发到分布式的后端服务器开发。
我第一个面临的问题是技术选型。几乎没有作任何纠结,我们选择了Java作为主体的开发语言。作为初入后端开发领域的团队来说,这只是一个从务实角度出发的选择。但TrustNo1在程序员杂志发表的《一场茶杯里的风暴》一文让我认识了Erlang语言,并深深被Erlang的编程思想所打动。我意识到这种编程思想将会极大释放服务端编程的生产力。为了推动服务端最佳实践的探索,也为了进一步推动更多人了解和研究Erlang,我发起了ECUG社区。ECUG到现在已经十年。这十年我们风雨无阻,每年年底都会举行一场ECUG Con大会,和来自各行各业的技术大拿们齐聚一堂,大家一起分享这一年来服务端开发的实践心得。
尽管我们选择了Java,但是随后我们也做了小范围使用Erlang进行开发的尝试。在2008年我们启动了一个用Erlang来编写存储系统(极简版)的业余项目。这次的尝试让我对Erlang有了进一步的判断:尽管Erlang的编程思想很好,但是Erlang语言本身并不适合大型的工程项目。
到了2009年3月,也就是我加入盛大创新院重启分布式存储项目时,我面临了第二次技术选型。这一次我选了最难的一条路:用C++来开发。这是一条艰苦的路。促使我做出这一选择的最大原因是,我很希望能够制造一个新轮子,它应该既有Erlang编程思想的优势,又可以克服Erlang语言的劣势。如果这事能够干成,它将是一件伟大的创举,所有的服务端开发人员都将受益于此。于是,在心怀满腔热血之下,一个名为CERL的项目诞生了。在我们存储的第一个版本期间,实际上我们花费在CERL库的时间远超过了做存储本身,无论从代码量还是花费的精力来说都是如此。
CERL项目经历了2个大的版本。CERL1.0完全遵循Erlang的编程思想,主要编程范式如下:
可以启动任意多的进程(这里进程是抽象的概念,实现上是纤程/协程),进程数上限只受限于内存大小。
每个进程有进程邮箱,相互发消息通过进程邮箱。
消息分同步消息和异步消息,同步消息会阻塞等待对方返回消息。
网络服务器是单进程模型(就是大家理解的单线程模型),一次只处理一个消息。
没有锁。
…
基于CERL 1.0的编程模型,我们实践中发现了这样一些问题:
在网络服务器A、B相互给对方发送同步消息时会发生“死锁”。因为双方可能都正在处理消息中而无法及时响应,这种“死锁”最终表现为超时(但是实际上超时更可怕,是服务器性能的杀手)。
解决“死锁”的方法是把同步消息改为异步,但是这对编程复杂性带来很大的影响,程序语义变得晦涩。本质上,这是回到了传统的异步编程模型,放弃了Erlang编程模型最大的优势。
“没有锁”的假设代价过高:在网络服务器的单个处理响应时间较长(存储服务必然如此)时,必然希望启动独立的进程来响应单个请求。但是各个处理请求的进程之间需要共享网络服务器的状态,这就意味着需要有锁(除非网络服务器是无状态的,但是很不幸存储服务器必然是带状态的)。要么放弃性能串行化地处理请求,要么有锁—“没有锁”,想说爱你不容易。
…
在发现“死锁”问题后,我们立刻对我们整个编程模型进行了反思,决定重构整个编程模型,修改后的CERL2.0要点如下:
可以启动任意多的进程(这里进程是抽象的概念,实现上是纤程/协程),进程数上限只受限于内存大小。
没有进程邮箱。
进程之间只有同步消息(要发送异步消息,用启动一个新的进程并发送同步消息来达到同样的效果)。
网络服务器是多进程模型,每个请求都由一个独立的进程来处理。
有锁。
两个版本的编程模型的关键差异在于拒绝锁还是拒绝异步消息。CERL 1.0(也就是Erlang编程模型)中拒绝锁,而CERL 2.0拒绝异步消息。基于CERL 2.0我们实现了分布式存储的第二版、第三版。事实证明,完全杜绝了异步消息这个概念后,这个版本的服务器编程模型心智负担小了很多。
然后,如大家所知,后来Go语言就发布了。我们团队一看,在服务器编程模型这一点上,CERL 2.0和Go语言居然一模一样(包括所有细节上的决策)。有一次团队聚餐谈起这事时,道哥(李道兵)说了一句:我们赶紧把CERL开源吧,不然等Go流行起来它就没机会了。我还真和创新院院长陈大年谈了CERL开源的事情,大年说:没问题,你发个邮件申请吧,留个凭证。然而我最终没有发出这封邮件。在尝试用Go写了一周的代码后,我心里已经有了结论:我并不打算让CERL面世。因为有人已经把它的目标完成了,而且远超预期。
于是,2011年6月,我们离开盛大创新院创办七牛云的时候,我面临了第三次技术选型。这一次,我很坚决地选择了Go语言。为此我还专门给团队发了一封邮件,邮件中有一段是这么说的:
在创业过程中我们会面临很多选择,也会有很多选择后来会被证明是错的,但是今天我可以确定的是,选择Go将会成为我们最正确的选择。
在选择了Go语言后,考虑到Go仍然是一门十分小众的语言,我们开始有意识地培养Go中国社区。为了让更多人能够知道Go,加入Go的行列,我们做了很多工作。我们启动了《Go语言编程》一书的编写工作,并最终和Go 1.0版本同步发布。2012年2月,我首次在公开场合说:Go会超过C、Java,成为最流行的语言。这一年我到处宣讲,做了不下十场的Go语言讲座,平均每个月有一场。讲得最多的一个PPT是《Go,Next C》这篇,它基本上算我对Go的革命性到底在哪里的一个总结。对于一个初创公司来说,为一个并不属于自己业务的技术这么花时间去宣传,有些人可能会觉得比较不可理解。但是实际上有三个理由支撑我们这么做:
Go真的是一门革命性的语言,它的流行将对产业发展具重大意义。
Go仍然是一门小众语言,而我们不止要招Go程序员,更重要的是要说服他们相信Go语言是有远大前景的专业技能方向。
七牛的用户是程序员,我们需要建立在用户心目中的专家形象。
七牛云的起步第一个业务是云存储,我们选择了完全用Go来实现我们的存储系统。这是全球第一个用Go写的云存储,也是第一个用Go写的云服务。而到了2014年,在我们决定进入大数据领域时,我们再一次面临技术选型问题。坦白说,我们还是纠结了一段时间的。从生态来说,选择Java,或者某种JVM平台的语言(比如Scala)有非常显著的优势。尤其对于我们大数据业务的负责人陈超这个Scala的狂热粉丝(八卦一下:陈超的网络id是CrazyJVM),选择JVM平台似乎更加是毋庸置疑的选择。那么我们纠结什么呢?我们认为未来Go会占领整个基础设施领域,而大数据无疑是其中极具关键意义的一个领域。所以面向现在做选型,还是面向未来做选型,这是一个问题。说到这里我提一个有意思的细节。在陈超刚加入七牛的时候,我对他说:“不管未来你会用什么语言,但是进入七牛必须要会写Go。”于是他被我逼着写了一个月的Go代码。一个月后我问他感觉如何,他说:“能够理解为什么你推荐Go了,写了Go代码后不想回去写Scala代码。”不久之后,在他启动Pandora大数据平台项目时,就碰到了我什么说的选型问题。在做了非常细致的思考之后,他决定用Go做Pandora。这对我来说是一个意料之外的决策。因为我自己在这个事情上并没有倾向性,而陈超我觉得他很可能还是会优先选Scala。就在最近(国庆节前)某次聊天中,陈超回顾起这件事,总结了一下他为什么选择了Go:极低的学习成本,极低的心智负担。如果用Scala,新人入职要培训,还要担心写出糟糕的Scala代码。但是用Go新人不培训直接上岗,几次Code Review完后基本就能够知道怎么写出质量不错的Go代码了。
十年过去,Go已经不再是一门小众语言。越来越多人在用Go,喜欢上Go。不记得是什么时候了,但是某一天通过Google Trends搜索golang发现全世界Go最火的地区是在中国时,那一刻真的很开心。
下一个十年会怎样?我知道有一些人很期望Go语言特性的迭代。但是如果你抱有这种想法可能会失望,因为下一个十年Go不会发生太大的变化。对远期需求变化的预测和把控能力,是Go的最大魅力之一。这一点上能够和Go相比的是C语言(C语言不同版本的规范差异极少),但因为Go要解决的问题更多,做到这一点实际上也更难。下一个十年Go仍然会继续深耕服务端开发的生态,同时积极探索其他潜在的应用市场。
以上是关于我与Go的缘分:成长的十年的主要内容,如果未能解决你的问题,请参考以下文章