NanoProfiler - 适合生产环境的性能监控类库 之 大数据篇

上期回顾

上一期:NanoProfiler - 适合生产环境的性能监控类库 之 基本功能篇

上次介绍了NanoProfiler的基本功能,提到,NanoProfiler实现了MiniProfiler欠缺的多线程和异步代码的支持,并且,由于采用不同的内部数据结构,NanoProfiler拥有更高的执行效率,而且占用极少的系统资源,因此,是适合在生产环境下使用的性能监控类库。并且,我们也提到了,NanoProfiler设计理念的另一大不同,即面向大数据分析。

这一期,我重点介绍一下NanoProfiler之大数据分析理念。

面向大数据分析的数据结构

上一期,我们曾经简单介绍了,NanoProfiler和MiniProfiler相比的,由于采用了不同的数据存储结构,因而具有更高的执行效率。这一节,首先,详细介绍一下NanoProfiler的数据存储结构。

首先,我们先来举一个简单的例子。假设我们有个对APP1的Web页面请求R,请求R的执行过程中,我们有以下几个Step:R-step-1, R-step-2,R-step-2的执行过程中,调用了APP2的一个WCF服务方法W.而W的执行过程中,又有以下几个Step:W-step-1, W-step-2。

如果使用MiniProfiler进行性能监控,R这个请求,可以得到类似下面的一整个树形结构的数据:

R (start, duration)
|
- R-step-1 (start, duration)
|
- R-step-2 (start, duration)
  |
  - W (start, duration)
    |
    - W-step-1 (start, duration)
    |
    - W-step-2 (start, duration)

start和duration表示,每个步骤相对整个请求开始的开始时间和执行时间。

MiniProfiler运行时,在内存中对一个逻辑请求,维护这样一个树形结构的数据,即使执行过程中有WCF调用,它也会通过WCF的EndpointBehavior和MessageInspector,将在APP2中执行的WCF调用内部的性能监控数据,返回并且合并到APP1的R请求这棵树结构数据。如果,当前请求包含一些前端的性能监控步骤,所有前端性能监控数据,也会实时保存到同一个内存中的数据结构中。如果要持久化,也会将整棵树,保存为一个JSON。这样做,虽然方便查看整个请求整体的性能数据,但是,不可避免的有以下一些问题:

  • 因为要在内存中维护这棵树,如果有并行的步骤,运行时,不得不加锁,因而,执行效率较差;
  • 跨应用(比如例子中APP1的请求调用了APP2的WCF)的调用,需要被调用方,将监控数据返回到调用方,增加了不必要的数据传输,因而,影响执行效率,也占用了不必要的内存(更何况,如果这个WCF服务是One-Way的呢?);
  • 如果同一个逻辑请求包含相关的多个子请求(比如,包含多个前端的AJAX请求和后端的WCF调用),R请求至少要等待所有这些子请求的性能监控数据全都返回并且合并之后,才能通知R请求的调用方R请求执行完毕,但是,这些子请求如果不是为了性能监控,R请求本身的执行逻辑,其实本来未必有依赖,因此,这样的机制,既导致了额外的内存开销,还导致了对R请求本身的执行时间的影响;
  • 将整个逻辑请求的性能监控数据整体保存为一个JSON,虽然方便后期查看这个请求本身的数据,但是,由于这个整体的树结构嵌套层次数量不可控,因此,不利于后期的数据分析,比如:如果我想分析某一天,上例中W这个WCF服务总的执行次数,平均执行时间等,将不得不需要解析和索引每一个嵌套层次的JSON,很难保证执行效率;

那么,NanoProfiler是怎么存储性能监控数据的呢?

假设还是上面的例子,如果使用NanoProfiler代替MiniProfiler,在在APP1的内存中,请求R的性能监控数据结构大概是下面这样的:

R (type=web, start, duration, tags=request_token_of_R) :{
  Steps: [
    R-step-1 (type=step, parent=R, start, duration),
    R-step-2 (type=step, parent=R, start, duration)
  ],
  Customs: [
    W-client (type=wcf_call, parent=R-step-2, start, duration)
  ]
}

同时,在APP2的内存中,有另一个WCF服务调用W的性能监控的数据结构:

W-server (type=wcf_server, start, duration, tags=request_token_of_R) : {
  Steps: [
    W-step-1 (type=step, parent=W-server, start, duration),
    W-step-2 (type=step, parent=W-server, start, duration)
  ],
  Customs: [
  ]
}

看出区别了吗?

  • 首先,NanoProfiler的数据结构不是一棵树,而是一些平面的数组,因而,即使要维护一棵树的父子关系(即使在有并行步骤的情况下),也无需关心树结构的层次嵌套,只需要将每个步骤的监控结果,添加到平面数组,执行效率显然更高;
  • R和W虽然属于同一个逻辑请求,但是,他们分别在自己的APP里维护自己的性能监控数据,仅通过tags的方式进行关联,好处是什么?很明显,R执行结束,无论子请求是不是One-Way的,都不需要等待相关的其他子请求完成,并且返回性能监控数据就能通知调用端执行完毕,存放监控数据的内存也能立即释放,所以,即使开启了性能监控,也基本不会影响R请求的执行时间和整体的内存消耗;
  • NanoProfiler,并不将每个请求的监控数据整体保存为一个对象,而是会将每一个步骤,保存为一个对象,例如,对上面的例子,我们一共会得到下面这些事件数据:

  • R (type=web, start, duration, tags=request_token_of_R)
  • R-step-1 (type=step, parent=R, start, duration)
  • R-step-2 (type=step, parent=R, start, duration)
  • W-client (type=wcf_client, parent=R-step-2, start, duration)
  • W-server (type=wcf_server, start, duration, tags=request_token_of_R)
  • W-step-1 (type=step, parent=W-server, start, duration)
  • W-step-2 (type=step, parent=W-server, start, duration)

上面这样的存储结构有什么好处呢?

  • 首先,没有嵌套层次,非常容易被解析和存储;
  • 即使,对同一个逻辑请求的性能监控,被拆分成多个事件,但是,他们之间可以方便的通过每个事件的tags和parent属性的值进行关联和追踪;
  • 方便只对某一种type的监控数据进行宏观的大数据分析,比如,我要分析一天之内W这个WCF服务的调用次数和执行的平均时间非常容易;
  • 由于避免了不同子请求的性能监控数据之间的直接耦合,而通过tags进行关联,方便和其他异构log系统的数据,进行大数据整合,例如,对这个请求的微观和宏观性能分析,可以包含跨应用,跨服务器甚至集群的异构的异常日志,前端日志,服务器日志等等(只要,这些相关日志之间能够通过相同的request_token进行关联),而不用像MiniProfiler那样,只局限于单个请求的数据,只局限于MiniProfiler能支持的类库产生的监控数据的整合,这就大大提高了大数据分析的灵活性;
  • 事实上,在NanoProfiler中,对需要监控性能的每一个步骤,无论是代码步骤,还是DB请求,WCF请求,都可以指定0到多个tag,请求的token作为tag只是一种应用方式,我们完全可以对某个步骤,指定其他各种目的(无论是业务的还是非业务)的tags,实现各种维度的微观和宏观的大数据分析;

面向大数据分析的数据存储

数据结构Ready了,下面是怎么存储的问题。NanoProfiler的性能监控数据,由上面举例的相同结构,但类型可能不同的平面事件数据组成。我们假设,平均每一个逻辑页面请求会产生20个event,如果,某个APP一天有500万页面请求(包含各种服务调用,AJAX请求等等),就会有1亿个event。这个数据夸张吗?对一个稍大一点互联网应用来说,一点也不夸张。所以,这里的数据,必然有那么点“大”的。这还是只一个APP,如果,有10个100个APP呢?

对于超大量的类日志数据,传统的文件系统,或者关系型数据库,很可能已经不能很好的胜任了。不仅仅读写性能未必能达到要求,数据的维护也会成为大问题。

所以,我们需要特别适合类日志数据存储的数据存储方案。很幸运的,很多走在前面的大数据公司,已经铺了不少路,我们现在有Cassandra,有HBase这些本身就是类日志存储的NOSQL数据库,非常适合类日志的超大量密集写操作的数据存储。

以Cassandra为例,早在3年前,就已经可以达到每秒超过百万次的写操作,这里也有一个中文的翻译。Netflix当时使用了288个节点达到的每秒百万写,而最近Datastax公司的测试,已经能达到1000个Cassandra节点的线型性能扩展了,可以简单计算,即使三年后,Cassandra单个节点的写并发能力没有增加,支持每秒几百万的写操作也是很轻松的事情。

大数据分析工具

说起大数据分析,大家一定首先想到Hadoop。但是,如果各位做大数据分析,却还没尝试过elasticsearch和kibana,那真的有点out了。

园子里关于kibana的介绍文章也早就有不少了,我就不说太多安装使用细节了。

//本文完

posted @ 2014-06-13 01:00 Teddy's Knowledge Base Views(...) Comments(...) Edit 收藏