我与Go语言的这十年
2007 年 9 月 20 日,关于设计一门全新语言的讨论正式开始,这门全新的语言,就是后来的 Go。时至今日,Go 语言已经发布到 1.9 版本,走过了整整十年的历程。在这十年间,Go 语言两夺 TIOBE 年度语言大奖(2009/2016),许多初创公司在早期使用 Go 进行开发,包括现在的云计算巨头 Docker,也由此催生出了 Kubernetes 这样的项目。在大洋彼岸的中国,Google Trends 显示 Go 的异常火爆更让 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 个大的版本。CERL 1.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语言有个“好爹”反而被程序员讨厌?
- 【外评】为什么人们对 Go 1.23 的迭代器设计感到愤怒?
- 【译文】Go语言性能从 1.0 版到 1.22 版
- Go 语言程序员的进化
- 【译文】面试时,有人问我喜欢Go语言什么?
- 4 秒处理 10 亿行数据! Go 语言的 9 大代码方案,一个比一个快
- 【译文】Go语言设计:我们做对了什么,做错了什么
- 最好的 Go 框架就是不用框架?
- 吵翻了!到底该选 Rust 还是 Go,成 2023 年最大技术分歧
- “Go 语言的优点、缺点和平淡无奇之处”的十年
你对本文的反应是: