2017-12-18 许式伟 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语言的这十年[转]的更多相关文章

  1. TOP100summit 2017 七牛云许式伟:不用JAVA和C语言,我为什么坚持Go语言

    本文编辑:Cynthia 2009年,谷歌发布第二款开源编程语言,Go语言.8年过去了,很多初创公司早期使用Go进行开发,包括云计算巨头Docker.而Go语言在中国的普及程度还比不上JAVA和C语言 ...

  2. 七牛CEO许式伟:移动游戏资源存贮的大趋势

    (国内知名Android开发论坛eoe开发者社区推荐:http://www.eoeandroid.com/) 9月14日,eoe移动开发者大会正式在北京国家会议中心召开,七牛云储存CEO许式伟先生做了 ...

  3. 架构师-盛大许式伟VS金山张宴

    许式伟:作为系统架构师,您一般会从哪些方面来保证网站的高可用性(降低故障时间)? 张宴:很多因素都会导致网站发生故障,从而影响网站的高可用性,比如服务器硬件故障.软件系统故障.IDC机房故障.程序上线 ...

  4. 许式伟看 Facebook 发币(上): 区块链, 比特币与 Libra 币

    你好,我是七牛云许式伟. Facebook(脸书)于6月18日发布了其加密数字货币项目白皮书.该数字货币被命名为 Libra(天秤座),象征着平衡与公正.此前,BBC 报道说这个数字货币叫 Globa ...

  5. Go语言学习笔记十二: 范围(Range)

    Go语言学习笔记十二: 范围(Range) rang这个关键字主要用来遍历数组,切片,通道或Map.在数组和切片中返回索引值,在Map中返回key. 这个特别像python的方式.不过写法上比较怪异使 ...

  6. Go语言学习笔记十: 结构体

    Go语言学习笔记十: 结构体 Go语言的结构体语法和C语言类似.而结构体这个概念就类似高级语言Java中的类. 结构体定义 结构体有两个关键字type和struct,中间夹着一个结构体名称.大括号里面 ...

  7. Go语言编程 (许式伟 等 著)

    第1章 初识Go语言 1.1 语言简史 1.2 语言特性 1.2.1 自动垃圾回收 1.2.2 更丰富的内置类型 1.2.3 函数多返回值 1.2.4 错误处理 1.2.5 匿名函数和闭包 1.2.6 ...

  8. 数据结构算法C语言实现(十九)--- 5.5&5.6&5.7广义表

    一.简述 传说Lisp的基本数据结构就是广义表,广义表也是具有典型递归属性的数据结构,此外,由于建表要处理字符串,用C语言处理起来也是一脸懵逼.....最后自己还想写一个将广义表还原成字符串的函数,一 ...

  9. 数据结构算法C语言实现(十二)--- 3.4循环队列&队列的顺序表示和实现

    一.简述 空队列的处理方法:1.另设一个标志位以区别队列是空还是满:2.少用一个元素空间,约定以队列头指针在队尾指针下一位置上作为队列呈满的状态的标志. 二.头文件 //3_4_part1.h /** ...

随机推荐

  1. 并发服务器--02(基于I/O复用——运用Select函数)

    I/O模型 Unix/Linux下有5中可用的I/O模型: 阻塞式I/O 非阻塞式I/O I/O复用(select.poll.epoll和pselect) 信号驱动式I/O(SIGIO) 异步I/O( ...

  2. LeetCode之“树”:Path Sum && Path Sum II

    Path Sum 题目链接 题目要求: Given a binary tree and a sum, determine if the tree has a root-to-leaf path suc ...

  3. TCP的核心系列 — ACK的处理(二)

    本文主要内容:tcp_ack()中的一些细节,如发送窗口的更新.持续定时器等. 内核版本:3.2.12 Author:zhangskd @ csdn 发送窗口的更新 什么时候需要更新发送窗口呢? (1 ...

  4. 高斯混合模型和EM算法

    使用期望最大化算法(Expectation-Maximization)来进行密度估计(density estimation). 与k-means一样,给定的训练样本是,我们将隐含类别标签用表示.与k- ...

  5. Eclipse修改工程名字

    1:修改项目目录下:.project文件 <?xml version="1.0" encoding="UTF-8"?> <projectDes ...

  6. 基于MT6752/32平台 Android L版本驱动移植步骤

    基于MT6752/32平台 Android L版本驱动移植步骤 根据MK官网所述,在Android L 版本上Turnkey ABS 架构将会phase out,而Mediatek Turnkey架构 ...

  7. c程序的编译

    linux系统下采用gcc进行编译,而在aix系统下采用xlc 进行编译. 附上aix安装xlc地址:https://www.ibm.com/developerworks/cn/aix/library ...

  8. 学习一下DOM中的cloneNode()与cloneNode(true)的基础知识

    带你去熟悉HTML dom中当然cloneNode()与cloneNode(true)之间区别 code <!DOCTYPE html> <html> <head> ...

  9. javascript学习笔记(四) Number 数字类型

    数字格式化方法toFixed().toExponential().toPrecision(),三个方法都四舍五入 toFixed() 方法指定小数位个数  toExponential() 方法 用科学 ...

  10. jquery选择器项目实例分析

    首先废话一句,jQuery选择器真心很强大!  在项目中遇到这么一个问题easyui的问题 如图所示,当前页面显示的是"原始报文查询"的页面,当时左侧导航栏却选中的是"重 ...