我在2011年由InfoQ组织的QCon大会上分享的《持续交付》相关话题中介绍过该公司的情况。那时该公司只有不到40名工程师,每天部署50次。在部署前需要运行一个很大的单元测试集合,总运行时间为15~20分钟(当然是分布式执行,而不是在一台机器上啦)。一旦通过,即可部署到生产环境中。当然,这么做有一个前提是有一个强大的监控系统,他们把它叫做“免疫系统”。下面是这个免疫系统的升级过程介绍,以及他们开源出来的监控工具istatd。

  每天向生产环境部署代码达到50次之多(而工程师人数还不到50)。每当工程师完成一个任务后,都会运行一个巨大的单元测试集合,一旦成功通 过,会马上部署到服务器上。这形成了一个即时反馈环:一旦出错,会立即被发现,而工程师对他的修改还记忆犹新,所以修复速度通常也很快。 

   这个流程中的一个重要组成部分是“免疫系统”。这个免疫系统监控整个系统的状态,并侦测突发事件。如果这些突发事件引起足够大的问题或风险,并 且它与近某次代码部署相关的话,这些代码部署会被回滚,并将监控图表与错误日志的链接发送给相关的工程师,以便其找到问题所在。

  在过去很长一段时间里,使用RRDtool加脚本从memcache中获取计数值来捕获数据,并用cacti将这些数据变成图形。当公司还比较小的时候,这是一种非常容易上手的方式,,而现在公司已经变得相当大了。两年前,这个系统开始显出老态。一年前,我决定找个新方案,而想要解决的问题是:

  现有系统只能每5分钟收集一次数据。这种频率无法快速地侦测到因坏代码引起的问题。虽然坏代码的情况很少,但希望对客户的影响尽可能地小。

  现有系统会根据时间的长短将数据均化后保存,以便长期保存粗粒度的数据。但这也意味着丢失了一些准确性数据。比如,在每个度量维度上的数据波动幅度是多少?小值是多少?大值是多少?

  数据的保留时间太短。为了确定是当前系统是否表现失常,还是由于是的原因才高出一点儿,需要一周之前的准确数据做基准进行判断。

  这个系统所依赖的度量数据首先被写入到 memcache中,再通过cacti抓回来放到rrd files里,因此常常会不堪重负,很多计数器会丢失数据。

  为 了解决这个问题,他们开始寻找新的计数器解决方案。他们试了很多,后决定用“Graphite”, 好象Etsy也在用它。然而,Graphite好象还是不行 — 当在做度量数据聚合保留时,它只允许用一个聚合函数,而且内建的后台存储有一些性能问题,很大程度上可以追溯到它用NFS的分布式模型。

  所以,他们开始写自己的后台,但前端的图形生成仍旧使用Graphite。后端程序完全符合Graphite 的要求,并且使用子计数器的概念,通过单一度量项暴露出不同的数据。对于一个图片中的每个数据点,都可以得到平均值,样本数,标准差,大值和小值。想 做到这一点,需要做大量的工作,而且有很多不太优雅的歪招儿 — 因为Graphite的内部结构简直不是为了他们这种情况设计的。而且Graphite使用服务器端渲染的方式,这也意味着只要几个工程师在他们的机 器上开着有一打度量项的指示器,并且每10秒刷新一次的话,服务器会过载,影响度量项的收集工作。

  他们无法忍受了,于是不但用自己写的后端程序,而且还写了自己的前端程序。这个前端程序是一个HTML5应用,利用客户端的JavaScript做渲染,分担服务器端的压力。同时,利用HTTP做数据传输,因此可以使用不同的客户端——如果必要,还可以用web caching!

  后,为了解决间歇性数据问题,他们利用代理来转发数据。在每个服务器上运行一个代理,由它接收本地数据,然后再转发给主服务器。如果这个代理与主服务器的连接中断,它会将数据保存到缓存里,同时尝试重新建立连接。

  现在,他们决定把这个系统(包括前端和后端)放到了GitHub上开源。如果你有这样的需求:跟踪大量的计数器,并且希望丰富的数据,而不只是每个数据点上的一个简单聚合功能,你可以看看这个工具,它的Wiki在这里:

  https://github.com/imvu-open/istatd/wiki

  后端程序是C++ 的,线程和网络部分用的是boost::asio,目前可以保留50万计数器文件,在RAID5 SSD硬盘的中端戴尔服务器上,每10秒可以更新一次。当前只有Ubuntu 10.04LTS上的构建与打包支持,但任何GCC的reasonable UNIX机器应该都没有什么问题。