作者简介:
Minghua Ye
Google SRE 主管
2007加入 Google 公司,2009年开始,主要负责 Google 的云计算平台,特别是 Google App Engine。
前言
如果大家对 App Engine 还不熟悉的话,简单来说 App Engine 就是 Google 提供的 paas,一个开发、托管网络应用程序的平台,使用户的程序能在 Google 的数据中心运行。
作者在本文中分析他在 Google 的一些经验,鉴于作者的 App Engine 背景。本文很多话题里都涉及跟 App Engine 相关的应用。
1、云平台至关重要的可扩展性
当7年前,我刚刚开始在 App Engine 的 SRE 生涯的时候,App Engine 还是在 Google 内部一个很渺小的服务,活跃用户,流量都远远不能和 Google Search 这样的巨无霸相提并论。
而在短短的7年时间 App Engine 实现的指数型的增长,现如今已经成为了 Google 云平台的重要组成部分。
应用程序开发者在 App Engine 上部署了上千万的应用。在其中不乏一些很重要的客户和很有趣的用例。
上图里我提及到的这些应用开发者们都在它们的网站公开描述了它们在 AE 上的实现。大家如果有兴趣做深入的案例研究可以直接搜索相关的关键字。
值得一提的是威廉王子和凯瑟琳王妃在2011的大婚,皇室选择了 Google 的云计算平台作为婚礼网站和婚礼实时直播平台的提供者。而作为运维小组的 SRE 也得到了皇室的感谢。
在短短的几天之内,网站接受了 15m 的访问和超过 42000QPS 的峰值流量。他们之所以选择 AE,最重要的原因是看中了 AE 系统的自动可扩展性。
网站开发者仅仅部署了网站的源代码,而后台容量的自动扩展和流量的自动均衡都由 AE 系统自动完成,而不需要开发者或者 SRE 的任何干预。
另外一个很重要的客户是 Workivia,Workivia 向全球500强公司提供财务报表的提交服务。众所周知,财务报表的提交时限性很强,而且不容许有失败和错误出现。
这对云平台的稳定性和容错性就有更高的要求,它们选择AE原因也恰恰在于由 Google 提供的高可靠 SLA。
同时 AE 的自动扩展功能使他们能够在繁忙的税季有足够的后端冗余去处理用户请求,而在淡季又能够通过自动减少后端容量已到达节约开支的目的。
最后要提到的是 Spotiy,作为互联网音乐流媒体的主要提供者,它们主要看中的是 Google 云平台的一致性和宽容度,不论你是处理每秒7个事件还是70万个,服务都能保证一至的用户体验。
所以说可扩展性对于一个云平台来说是至关重要的。
2、可扩展系统的基石
Google App Engine 采用了和大多数其他 Google 内部服务一样的微服务架构。而不得不提到的是这些微服务的共同点和它们所依赖的通用内部平台。
首先不得提到的则是 Google 内部自己实现的分布式锁和存储服务 chubby。
在 Google 内部基本上所有的服务都依赖于 chubby 所提供的一系列功能。chubby 本身并没有开源,但是 Google 将 chubby 的实现细节和 API 通过一篇研究论文发表了。
这篇研究论文也恰恰催生了一批开源的实现,而其中最有名的就是大家都知道的 Apache zookeeper。
而大家也能看到 chubby 所提供的功能在单机环境就类似于大家熟知的锁和寄存器,而 chubby 或者 zookeeper 恰恰是把这种基础的服务拓展到了分布式的环境,是的软件开发者能在分布式的环境中轻松的应用单机开发中常用的方法和理论。
当你有很多松耦合的微服务组建在运行的时候,如何能够自动发现并寻址到这些服务,就变的非常重要。服务的自动发现在 Google 也是通过 chubby 来实现的。
BNS 是在chubby上实现的地址协议,chubby 提供小文件读写的一致性,这样就能通过写入 BNS 地址和真实 IP:port 绑定,来实现服务发现。
当服务需要解析一个 BNS 地址的时候,他只要通过一致性的读取相应文件即可。etcd 和基于 etcd 的 skydns 则是服务发现在开源环境中的实现。
当你有很多松耦合的微服务组建在运行的时候,你同样面临的问题是如何能够实现流量负载均衡。
在 Google 内部负载均衡是通过 Google generic service loadbalancer 服务来实现的。你如果使用 Google 的云平台的话,Google 可以提供给你网络即3层,或者 HTTPS 即七层的自动负载均衡。
在 AWS 也有类似的 Elastic loadbalancer 实现。在很多情况下,用户还可以通过 HApxoy 或者 engineX 来实现一些简单的负载均衡。
最后值得一提的是 Google 的 RPC 子系统和 Protobuf。Google 在近期开源了 gRPC 也就是 Google 内部使用的 RPC 子系统的开源实现。
gRPC 使用 http2 作为传输层,同时使用 Protobuf 作为接口描述语言和消息格式。
2.1 分布式锁和存储
让我们来看一下 chubby 会提供哪些在分布式环境下至关重要的服务:
第一、不同微服务间的同步,通过独占锁的实现,只有一个服务是能获得独占锁并更新共享的信息。
第二、有一些服务需要实现主从分配,多个服务用例能通过masterelection库,竞选出真正的主实例。而且从实例能自动转换成主实例,如果主实例不可用。
第三、是序列号这个在存储和网络中都会经常要用到。
第四、则是我前面提到的 BNS 服务。
第五、chubby 本身是一个文件系统,所以可以用于分布式的文件存储。事实上,在 Google 很多服务用 chubby 存储一些不大的配置文件,这样能实现在线的和同步的,不需要重启服务的配置更新。
2.2 自动注册的服务发现
自动服务发现使服务能够实现自动扩展,你可以随时增加服务的容量,增加或更改服务运行的数据中心,而作为 devops 则不需要上游系统做任何更改。
当一个服务用例失败的时候,RPC 传输和负载均衡中间件能自动发现并将不健康的用例自动从负载均衡的备选用例中剔除,从而实现真正的无人值守。
2.3 谷歌云平台上的负载均衡
刚才提到了在 Google 的云平台上有现成的负载均衡可供用户使用。而且用户也能通过使用第三方的软硬件来自行实现负载均衡。
2.4 Protobuf
不得不提到的是 Google 开源的 Protobuf 库提供给不同的语言开发者一个统一的通讯协议,服务定义和存储格式。
Protobuf 重要特性是向后兼容性,比如说应用在08书写的 Protobuf 格式的日志,在2017年能够继续被使用和分析,即使是 Protocol buffers 已经被更新很多次。
在接口描述语言和消息格式里面,你可以任意添加新的阈值而不影响服务的向后兼容性。这一点在大规模微服务实现中非常重要。
当你的服务用例数足够大,你则不可能在不影响服务质量的前提下,同时更新所有的服务用例。所以前端和后端必须保证向后兼容的特性,否则在升级过程中会造成数据的丢失或损坏。
在大型的开发团队里,更要求前端和后端能独立开发,独立部署,独立测试,而 Protobuf 的向后兼容的特性,恰恰是这样的开发部署模式成为了可能。
Protobuf 还提供跨平台和语言的兼容性,所以 node.js 的前端能很自然的使用 Protobuf 与 C++ 的后端通信。
更值得一提的是,恰恰是 Protobuf 的这种特性像 Google 这样使用一个单一代码库的公司能在内部部署成千上万的相互依赖的松耦合的微服务。
3、使用Google service(C++)的核心类库
接下来我想谈谈我在作为一个软件开发者的一些体会,SRE 是 Dev+Ops 的合体,所以参与开发也是 SRE 日常工作的一个重要组成部分。
众所周知 Google 广泛的使用各种开源软件打造它的平台,而作为开发者 Google 也向开源社区回馈了很多内部使用的工具的类库。
我将举例几个跟 SRE 相关比较紧密的库逐一讲解,我选择了 C++ 的版本因为我主要从事 C++ 的开发所以比较熟悉。
这些类库大多也都有其他语言的实现,值得一提的这些库基本上被所有的 Google 内部服务调用。
3.1 命令行库—gflags
首先提到的是 Google 的命令行库叫 gflags。在 Google 几乎所有的服务参数和特性都可以通过命令行参数来调教和更改。在很多时候新的服务特性往往是通过命令行参数来启用或者禁用。
举个例子,如果在某次的部署当中新的服务实现了 A,B,C 三种新功能,但是通过部署测试发现 B 功能不能正常工作,这是SRE往往采用命令行参数来禁用b功能,从而使 A,C 功能能及时的发布。
在第二个例子当中,SRE 经常会通过命令行参数来更改服务的特性而不需要重新编译和打包。很多时候程序的配置被写在命令行里,这样只要更改命令行就能服务实现不同的功能。例如你能配置一个服务使用英文而另一个服务使用中文而不需要重新打包。
gflag 定义 flag 为全局变量,你可以用 DEFINE flag 去在任何文件里定义命令行标志,在其他文件中通过 DELCLARE_flag 来实现调用。使用 gflag 你将摆脱手动分析 args,能使程序更加简洁易读。
3.2 日志服务—glog库
第二个提到的是 Google 的 glog 库,实现了程序中标准的日志服务。
glog 定义了不同的日志类型,而开发者可以通过 LOG 类型来简单的实现将不同的日志存储在不同文件中的目的。
glog 提供了 CHECK 宏,能帮助程序检测一些不可恢复的错误并终止程序。在这个例子中如果写失败将终止程序并将 stacktrace 输出到日志中方便 SRE 和 DEV 来 debug。
glog还提供详细日志服务,详细日志通过命令行参数来控制。通过 vmodule 和 v 两个参数可以控制不同的模块产生不同的日志。
glog 还提供系统信号处理,在程序被系统信号终止的时候,他能自动生成出错点的 stacktrace 方便 SRE 和 dev 来 debug。
glog可以和其他的日志管理程序一起实现日志的重定向等服务。
3.3 单元测试库—Google test
最后要提到的是 Google 开源的单元测试库 Googletest,提供两个方面的功能:
一个是单元测试;
一个是虚拟测试;
单元测试被广泛应用于 Google 的代码库,基本上每个实现都有单元测试,而且测试的覆盖率会自动报告。
虚拟测试则广泛应用在复杂服务的测试中,在写单元测试的过程中,被测部分的复杂依赖则通过 mock 来实现,是开发者能专注于单元测试中。
近期好文:
《别让黑客毁掉运维》
《链家网的第三种运维》
《千亿级eBay平台的Kafka深度实践》
《就是干!移动的运维实践之路》
《通过漏洞组合利用实现企业内网入侵》
GOPS · 深圳站,这里的运维很酷
带你走进GOPS
是为了帮你走出运维瓶颈
会议地点:南山区圣淘沙酒店(翡翠店)
会议时间:2017年4月21日-22日
您可点击“阅读原文”,享受特惠折扣购票