Twitter研发人员John Oskasson分析Twitter后台软件栈

John Oskarsson是Twitter的一名研发人员。最近,他撰写的一篇博客中提到了Twitter后台的软件栈,其中包括:服务支持、服务监控、服务协调、跟踪系统、负载测试、服务发现、Hadoop作业等诸多方面。这篇博客也被Twitter工程团队的官方博客引用。

文中提到:

出于性能和成本等多种原因,Twitter在工程方面付出了巨大努力,将网站后台拆散为更小的基于JVM的服务。其额外作用是,我们可以以开源方式开放由此产生的多个应用库和其他工具。

尽管已经有很多信息介绍这些项目,但是对于他们口中这非官方的的“Twitter Stack”,到目前并没有全面介绍。这是John的初衷。

要指出的是:这里所有的相关信息,都是关于开源项目的。

……

不过,下面这些项目,虽然不全是Twitter自己构想出来的,而且其他公司也有类似方案。我还是认为这些软件十分强大,基于它们构成的平台,足以开发新服务。

我将会从Scala语言的角度讲解这些项目,但是其中很多用Java也是没有问题的。

支持服务——Finagle

John首先提到了Finagle。这是服务核心之一。Finagle抽象出了RPC系统的底层核心功能,大大降低了服务开发人员需要处理的复杂性。让开发人员可以专心编写业务逻辑,而不是处理分布式系统的底层细节。网站本身使用这些服务完成运维操作,或是获取产生HTML的数据。在Twitter里面,内部服务都使用Thrift协议,但是Fingale支持其他协议,包括Protocol buffers和HTTP。

使用Finagle设置一个服务需要四个步骤:

  1. 编写一个Thrift文件,定义API。其中应该包含结构体、异常和方法,用来描述服务的功能。可以查看Thrift的接口描述语言文档(Interface Description Language,简称IDL),特别是结尾处的例子。
  2. 使用Thrift文件作为代码生成器的输入,生成你需要的语言代码。对于基于Scala和Finagle的项目,John推荐Scrooge。
  3. 实现Thrift IDL中的Scala特性。这就是服务真正要实行的功能。
  4. 为Finagle服务构建器提供上述实现的实例,还有用来绑定的端口,还有其他启动服务需要的任何设定。

似乎这与平常使用Thrift没有区别,但是Finagle中有很多改进,比如出色的监控支持、跟踪,Finagle还能让开发人员以异步方式编写服务。同时,Finagle也可用来作为客户端,处理超时、重试和负载均衡。

服务监控——Ostrich

当一个重要的Finagle Thrift服务运行起来之后,需要保持它一直正常运行,对这个服务的监控就很重要。Ostrich可以很容易地暴露服务的多种指标。John在文中列出了具体的代码示例。

Ostrich运行一个http管理接口,可以暴露指标以及其他功能。只需要访问一个特定的json文件,就能得到当前的指标快照。在Twitter,每个服务的状态都会从Ostrich读取出来,然后经过内部的观察和分析栈,提供漂亮的图表、警告和其他机制。

Ostrich还可以处理服务的配置,能够以平滑的方式关闭所有组件。具体截图可以参考该演示幻灯。

跟踪系统——Zipkin

Ostrich和Finagle组合起来,可以提供很好的服务水平指标。然而,面向服务的架构存在一个问题:很难得到一个请求通过整个软件栈的全面性能概览。比如,你需要改善某个特定外部api访问点的性能,这时候,使用Zipkin,你就能以可视化的表现方式,知道满足该请求的时间都用在了哪里。可以将其看做后台的Firebug或者Chrome开发人员工具。Zipkin是基于Google Dapper论文实现的跟踪系统。

集群管理——Mesos

Mesos是一个“集群管理器,在分布式应用和框架之间提供高效的资源隔离和共享”。

Mesos的核心是一个开源的Apache孵化项目。在其上,你可以运行调度器,处理特定技术,比如Storm和Hadoop。其背后理念是:同样的硬件应该可以用作多种用途,降低资源浪费。

除在Mesos上使用Storm之外,Twitter还部署了一些基于JVM的服务到内部的Mesos集群上。配置之后,它可以处理多样化的机架,如果一台服务器宕机,它可以重新调度。

Mesos带来的限制有其正面效益:强制满足多种良好的分布式系统实践。比如:

  • 服务所有者不应该对作业的寿命有任何假定,Mesos调度器可以随时将作业移动到新的主机上。
  • 作业不应该写入本地磁盘,因为不能保证持久性。
  • 部署工具和配置不应使用静态服务器列表,因为Mesos会假定部署到动态环境。

负载测试——lago

在将新服务部署到生产环境之前,应该要检查它在负载下的表现。这就是lago(之前的Parrot)的作用——负载测试框架,易于使用。

协调分步式系统——ZooKeeper

Apache项目,完成各种分布式系统之间的协调。Twitter用它来发现服务。Finagle服务会在ZooKeeper中使用ServeSet库注册,可以参考finagle-serversets。客户端只要说它们希望与“A数据中心中供B服务使用的生产集群”通信,ServerSet实现就会确保提供最新的主机列表。当新的计算资源加入后,客户端会自动收到通知,并开始在所有服务器之间进行负载均衡。

开发Hadoop作业——Scalding

Scalding是一个Scala库,方便开发Hadoop中的作业。开发人员不需要编写底层的map和reduce功能,用Scalding可以像写自然的Scala语言一样开发。

虽然已经有很多可以编写Hadoop作业的工具,但如果项目使用Scala开发,用Scalding编写Hadoop作业还是很方便的。其语法接近Scala集合开发库中使用的语法,而且使用Scalding,开发人员以同样代码可以处理上T的数据。

JVM调优——javmgcprof

使用JVM处理对时间敏感的请求,垃圾回收机制带来的暂停会有很不好的影响。如果运气不好,GC暂定可能会在错误的时间出现,导致某些请求性能骤降,甚至超时。最坏的情况甚至会导致宕机。

要应对GC问题,首先要做的是调整JVM启动参数,以配合要执行的服务。John建议读者阅读Attila Szegedi的这些幻灯片。此前Attila也曾在2011年的QCon杭州上做过相关分享。

使用jvmgcprof,可以减少服务产生的垃圾,将GC带来的问题最小化。在启动服务时使用jvmgcprof,就能达到这个目的。用Ostrich跟踪服务的指标,并以之告诉jvmgcprof哪个指标表明工作结束。John在文中列出了一个具体的例子,并建议大家阅读jvmgcprof的Readme文件。

在总结中,John指出:

虽然无甚奇特之处,但我们还是发现:有一个公关栈令我们受益匪浅。一个团队完成的改进和bug修复能够让其他人受益。当然也有不好的一面,有些时候,引入的bug会导致其他服务出问题。不过,举个例子,当开发Zipkin时,知道其他人都在使用Finagle,这非常有帮助。因为当我们开发完成后,他们马上就能得到免费的跟踪功能。

你可能感兴趣的:(Twitter研发人员John Oskasson分析Twitter后台软件栈)