前言

Gopher China 是中国 Go 语言爱好者知名度最大的盛会,目前已经举办过非常多届(B 站上有不少往届的大会视频)。蚂蚁集团是这次大会的钻石级赞助者,所以有幸蹭了一张免费票去现场听一听。

这是本次大会的所有主题,本文就挑几个我觉得有意思的主题重点讲一讲。有些技术细节不一定准确,只是凭记忆描述。

这是本次大会的会场(图片来自 GoCN 公众号):

Go 发展的趋势

Go 的微服务框架百花齐放

Go 最近几年在国内的发展越来越迅猛,之前大家都广泛认为 Go 因 Docker 和 Kubernetes 这些杀手级项目的兴起而成为云原生第一语言,而现在,越来越多的公司直接采用 Go 来做日常的业务开发,而这一领域,之前普遍认为是 Java (或者 PHP ?)的天下。

要想用一门编程语言写复杂的业务逻辑,个人认为要满足以下几个条件:

  1. 语言抽象度要足够高,上手成本要尽可能低

  2. 要有足够好用的框架,将日常的 CRUD 等操作尽可能框架化

  3. 语言生态要足够好,不仅常见的库都有,还要能吸引更多的人来学习,更重要的是要好招人

经过十余年的发展,Go 渐渐具备了上述几个条件,因此最近几年能看到各式各样的微服务框架(比如国内较为出名的 beego / go-zero 等等)百花齐放。

如果是拿金融场景来看的话,长桥证券(阿里系投资公司)有不少交易和行情系统是用 Go 写的(从招聘广告上看的)。

Go Runtime 的研究逐渐深入

用 Go 来写偏基础层的应用(特别是强 IO 服务,比如网络代理或者存储),都会不可避免地会遇到性能、延迟抖动等问题。随着越来越多的人用 Go 来写一些基础组件,且这些基础组件都极有可能会被大规模部署在生产环境上,因此对 Go Runtime 的研究和调优就在所难免。

这次大会上有好几个问题最后都会涉及到 Go Runtime,比如我们公司自己的 MOSN On Envoy 方案:如果想达到更好的性能,就需要对 cgo 有一定的修改;PingCAP 团队对数据库执行流的 trace 之前的方案也是通过修改 Go Runtime 实现。

Go 虽然提供了极其易用的语言和强大的 goroutine 机制,但是与之带来就是无法对 CPU 和 Memory 有极其精确的控制,几个常见的问题:

  • Go Runtime 目前无法精确做 CPU Affinity(就是没法绑核运行 )
  • 开发者没法控制精确控制 Memory(这是一个悖论,因为使用 Go 就等于把内存管理的重任交给 gc)

之前备受诟病的 GC STW 问题(早期版本),其实现在被提及得不算多,更多的人表示由于 Go GC 算法在最近几个大版本的优化下,以处于可被接受的程序。

Go 的生态扩张迅猛

正如前文所说,Go 已经从当初的云原生第一语言逐渐出圈,渐渐进入更多的领域,比如:

  • 嵌入式开发

    可以关注 TinyGo 项目。tinygo 重写了 Go 的编译器,并可以支持 LLVM 后端,更深度支持 WASM,主要是面向嵌入式场景。这次大会 JetBrain 的工程师用 tinygo 和树莓派打造了一个全屋监控系统。

  • 大数据开发

    可以关注 Go+。一直以来大家都会认为 Python 是大数据领域常用的编程语言,但是 Go+ 出现渐渐改变这一趋势。这部分内容我也只是通过浏览对应的 PPT 才有了一些粗浅的认识。

  • 网关开发

    一直以来,大家都觉得网关的开发是 C/C++ 的天下,因为追求是高性能,但是 Go 生态的也出现不少网关,比如典型的有 MOSNBFE 等。虽然性能非常重要,但是在贴近用户层一面的网关其实用 Go 来写也并非不可,Go 的性能也并非想象中的那么差。如果能通过加机器解决问题其实也很划算,毕竟也不是每一家公司都有像头部几家互联网公司那样有如此巨大的流量。更重要的是,使用 Go 对开发效率的提升成倍于 C 系语言。

  • 复杂业务系统开发

    正如之前所说的,Go 其实具备了写一个复杂业务系统的全部基础,而且越来越多的公司愿意尝试去用 Go 写生产业务。

从程序员收益比来看的话,Go 的学习是极具性价比:相对较低的学习门槛和广泛的应用场景。从这次大会的赞助商来看,使用 Go 的公司已经覆盖了大中小公司。这说明 Go 早已不是大厂才敢尝试的技术,反而越是新公司越倾向于首先使用 Go。

几个有意思的主题

MOSN on Envoy 方案

MOSN 是一个 Go 版本的 ServiceMesh 数据面 Proxy,而 Envoy 则是 Istio 社区根正苗红的数据面 Proxy,采用 C++ 编写。可想而知,从内存消耗和性能上,MOSN 应该是无法和 Envoy 一较高下。面对 Enovy,MOSN 最核心的竞争力应该是:

  • 数倍于 C++ 的研发效能
  • 活跃的 Go 生态

因此,MOSN on Envoy(下称 MoE)方案的核心点就是:既能有 Enovy 的高性能,又能有 MOSN 极高的研发效能。但是天下没有免费的午餐,想完美地结合 MOSN 和 Enovy 还是需要付出不少代价。

MoE 的整体架构如下所示:

其中几个关键的技术点是:

  • MOSN 将编译成一个 SO,由 Envoy 拉起来运行
  • 数据的 IO 层由 Envoy 处理,并通过一套统一的 API(proxy_golang API)经过 CGO 传给 MOSN
  • MOSN 拿到这些数据之后做进一步处理,此时就可以利用 Go 的能力对这些数据包进行处理

通过上述的数据流可以看到,MoE 更多的是将利用 CGO 机制将 MOSN 作为后续数据包的处理单元,此时怎么高效利用 CGO 就一个很关键的问题:如何安全高效地将数据从 Enovy 籍由 CGO 传递给 MOSN ?如何做到 zero copy ?这写问题都需要 MoE 方案的开发者对 CGO 有较深入的理解。这块因为平时接触不多,感受不深,毅松同学提到的几个优化点其实理解地不算深入,待后续有了更多了解再补充(大家可参考这篇文字稿博客)。

总的来说,个人感觉 MoE 是一个相对比较复杂的方案,而且稳定性和性能其实还有待进一步验证。用户使用 MoE 必须接受:使用 Go 开发是一件非常重要的事情,如果这一点能接受,我感觉 MoE 整体方案还是有不少有意思的亮点。

百度的 BFE 七层负载均衡

BFE 是一个百度用 Go 写的 7 层负载均衡,已经被 CNCF 列为孵化项目。这个项目其实和 MoE 都有一个核心认知:Go 的研发效能和生态优于高性能,但其实还有一个很重要的好处:Go 是 Memory Safe 的语言。虽然用 Go 写这种强 IO 的项目,性能一定比不过用 C/C++ 开发的项目,但是其他收益还是非常明显。会上章老师举了几个很有明显的例子:

  • 性能如果不够可以加机器,几台高性能的 x86 服务器一年的开销(大约 20w 一年)比招一个资深的 C/C++ 工程师要便宜得多,况且 Go 的性能其实并没有那么差,跟其他语言对比,还是非常不错的;
  • 大多数中小公司根本无需要那么高性能的 LB,性能差不多也就可以了,更重要的是功能丰富和二次开发容易;

BFE 其实更贴近用户侧,当流量经由 4 层负载均衡下来(比如 LVS),就流到 BFE,由 BFE 进行处理。

BFE 其实对标的是传统的 nginx,nginx 虽然有着极致的性能(最近几年被 F5 收购后也开始推出商业版本),但是功能上还是有很多不足,而且整体社区也不算活跃,而这些 BFE 都做出了极大的改进。相比 nginx,BFE 增加了很多更抽象的功能,典型的有:

  • 原生支持多租户(引起租户、集群和子集群的概念);
  • 支持细粒度的动态配置加载;
  • 支持基于表达式的转发规则,减少正则表达式的使用(因为正则表达式不仅可读性差,还容易引起性能故障);
  • 极其丰富的可观测性(用 Go 写的服务很容易通过加一些 Metric 都得到很好的观测性);

很多高级功能其实用 Go 来写都非常容易,开发效率要远大于直接在 nginx 加扩展。同样地,BFE 也对外暴露不少 hook 来让用户增加扩展。个人感觉,除了性能比不上 nginx,BFE 在功能上比 nginx 丰富很多,而且未来想增加新的功能都相对比较容易做到。虽然 nginx 的 C 代码写得极其优雅干净漂亮,但是想在上面增加稳定的功能做二次开发,还是有不少难度和挑战的(业界比较知名的是利用 Lua 来做扩展,比如 OpenRestry 项目)。

TiDB 的全链路监控

PingCAP CTO 的分享相对比较轻松,更多是在分享一个设计的思路,而且将方案的演进思路都一步步描述出来,感觉还是相当有意思。

TiDB 的全链路监控其实就是想解决一个问题:可观测 SQL 执行的完整过程。比如 SQL 执行哪里执行时间比较长,为什么会执行怎么长时间等。

整个方案核心思路并不复杂,简而言之可以是:

  1. 将 Trace ID 和 Span Context 信息通过某种机制带到 TiDB 内部,这个可以通过给 SQL 扩展新的语法来实现

  2. 利用 pprof 来采样 trace go runtime(你要知道到底是 SQL 执行有问题,还是 goroutine 调度有问题)

整个演进更有趣是思路的分享,比如最开始他们是 hack Go Runtime 来实现 tracing runtime 的功能,但需要单独维护 Go 分支这件事情对他们来说是无法接受的事情,所以就转变思路利用其 pprof 最新的 Label 特性。

阿里巴巴新一代基于 Go 的云原生应用引擎实践

OAM 是阿里云和微软联合推出的一个应用交付的标准,目的是为了给 PaaS 提供应用交付的标准。为什么需要 OAM 呢,我对演讲中这张图非常有感兴趣:

随着 K8s 成为一个事实标准,目前有无数基于 K8s 构建的 PaaS 平台,各种各样 PaaS 已经成为无数异构的平台。对于用户来说,理解这些 PaaS 暴露的概念对用户并不是一件很好的事情,而且很容易 Lock-in 到某个平台上。这时候,我们能否再提供一层抽象层,让这些不同的 PaaS 都提供统一的核心概念 ?并且这层抽象层由很好的扩展能力,可以将多种不同的云原生能力扩展到这层抽象来。因此便诞生了 OAM。

OAM 是以 Application 为核心,对外暴露了这些概念:

  • Application
  • Component
  • Trait

基于 OAM,阿里云又提供了 KubeVela 来实现 OAM 语义到 K8s 的映射,KubeVela 就是 OAM 的一个标准实现。基于 OAM,平台管理员可以很容易将一些最佳实践编写成最佳实践模版,然后终端用户将这些模版进行自由组合,组成一个 Application。典型的工作流可如下所示:

KubeVela 还可以和 IaC 结合(比如 cuelang),面向用户提供更高级的抽象。

其他

其他的主题的零散听了一些,比较认真地听了 Terminus 公司的 PaaS 平台的设计。个人感觉,目前这些基于 K8s 构建的 PaaS,其实最大的难点是怎么讲各种能力(发布部署、可观测性、数据分析等等)整合成易用性极强的平台让用户使用,这其实是一件工作极其巨大而且极其考验产品能力的事情。

Go 的泛型机制备受广大 Gopher 关注,这次大会还远程连线了 Go 泛型的设计者 Ian Lance Taylor 。但是由于网络质量是在太差了,导致整个访谈变成了大型听力现场,模模糊糊并没有听到太多东西。我觉得 Go 就算没有泛型也没有太大影响,无非就是多写一些冗余的代码,而引入泛型也就引入了更多复杂性。

go-zero 的作者这次大会讲了怎么将单体服务拆分成微服务,讲得非常好,是非常 pragmatic 的一个演讲。比如:

  • 单体是不是就是不好 ?对于小公司,业务快速发展才是关键,单体服务无论是开发和调试都是极其容易的,这个阶段就不需要盲目微服务;
  • 业务发展到一定阶段,微服务化在所难免,怎么将单体服务拆分成粒度合适的微服务是一个很考验业务设计能力的过程;
  • 怎么做到讲流量和数据无损地迁移到到微服务上 ?可以从线上拷贝流量导入到不对外服务的微服务上,并通过与旧服务比较处理后的返回值来实现流量的真实验证;
  • 尽可能用工具来代替人工,各种开发和流程要进行工具化;

等等。可看出,演讲者对用 Go 来写微服务这件事情轻车熟路。

类似的,Grab(东南亚打车公司) 的工程师也带来了用 Go 写后端业务的实践经验,说实话,经验都挺不错,就是讲得比较枯燥,不过可以看出 Grab 是一家开发流程非常规范的公司,难怪不卷不加班。

这次大会还有曹春晖同学的 Go 抢占性调度的底层分析。说实话,细节太多,很多东西都只是听了个大概,待后续研究下 scheduler 之后再回过头再看。

总结

个人还是挺满意这次 Gopher China,不仅开拓了眼界,也顺便也拿了不少免费的礼物(衣服、贴纸…),主题也做到 “干湿分离”,适合各个层次的 Gopher。希望明年有机会继续参加 !