唐睿

A full stack engineer, an architecture, a project coordinator and an entrepreneur, who is always learning.

Zipkin 和 Pinpoint 选型对比

24 May 2016 » 技术
架构 Zipkin Pinpoint Dapper APM 微服务 服务监控

一、背景

Pinpoint 是一款开源的应用程序性能管理(Application Performance Management)工具,开发团队来自韩国的搜索引擎门户 Naver(截止到 2016 年 5月,Alexa 全球排名第 58 位,韩国本土排名第一位)。该项目于 2012 年 7 月开始,2015 年 1 月开源,至今的稳定版本是 1.5.2。与 Zipkin 类似,其理论基础也是基于 Google Dapper 的那篇论文。

二、Pinpoint 与 Zipkin 的差异性

Pinpoint 与 Zipkin 有明显的差异,主要体现在如下几个方面:

  1. Pinpoint 是一个完整的性能监控解决方案:有从探针、收集器、存储到 Web 界面等全套体系;而 Zipkin 只侧重收集器和存储服务,虽然也有用户界面,但其功能与 Pinpoint 不可同日而语。反而 Zipkin 提供有 Query 接口,更强大的用户界面和系统集成能力,可以基于该接口二次开发实现。
  2. Zipkin 官方提供有基于 Finagle 框架(Scala 语言)的接口,而其他框架的接口由社区贡献,目前可以支持 Java、Scala、Node、Go、Python、Ruby 和 C# 等主流开发语言和框架;但是 Pinpoint 目前只有官方提供的 Java Agent 探针,其他的都在请求社区支援中(请参见 #1759#1760)。
  3. Pinpoint 提供有 Java Agent 探针,通过字节码注入的方式实现调用拦截和数据收集,可以做到真正的代码无侵入,只需要在启动服务器的时候添加一些参数,就可以完成探针的部署;而 Zipkin 的 Java 接口实现 Brave,只提供了基本的操作 API,如果需要与框架或者项目集成的话,就需要手动添加配置文件或增加代码。
  4. Pinpoint 的后端存储基于 HBase,而 Zipkin 基于 Cassandra。

三、Pinpoint 与 Zipkin 的相似性

Pinpoint 与 Zipkin 都是基于 Google Dapper 的那篇论文,因此理论基础大致相同。两者都是将服务调用拆分成若干有级联关系的 Span,通过 SpanId 和 ParentSpanId 来进行调用关系的级联;最后再将整个调用链流经的所有的 Span 汇聚成一个 Trace,报告给服务端的 collector 进行收集和存储。

即便在这一点上,Pinpoint 所采用的概念也不完全与那篇论文一致。比如他采用 TransactionId 来取代 TraceId,而真正的 TraceId 是一个结构,里面包含了 TransactionId, SpanId 和 ParentSpanId。而且 Pinpoint 在 Span 下面又增加了一个 SpanEvent 结构,用来记录一个 Span 内部的调用细节(比如具体的方法调用等等),因此 Pinpoint 默认会比 Zipkin 记录更多的跟踪数据。但是理论上并没有限定 Span 的粒度大小,所以一个服务调用可以是一个 Span,那么每个服务中的方法调用也可以是个 Span,这样的话,其实 Brave 也可以跟踪到方法调用级别,只是具体实现并没有这样做而已。

四、比较

下文主要通过对比,列出两者的优缺点,以提供选型参考。

4.1、字节码注入 vs API 调用

根据上文所述,这一点是两者最大的差异。Pinpoint 实现了基于字节码注入的 Java Agent 探针,而 Zipkin 的 Brave 框架仅仅提供了应用层面的 API,但是细想问题远不那么简单。字节码注入是一种简单粗暴的解决方案,理论上来说无论任何方法调用,都可以通过注入代码的方式实现拦截,也就是说没有实现不了的,只有不会实现的。但 Brave 则不同,其提供的应用层面的 API 还需要框架底层驱动的支持,才能实现拦截。比如,MySQL 的 JDBC 驱动,就提供有注入 interceptor 的方法,因此只需要实现 StatementInterceptor 接口,并在 Connection String 中进行配置,就可以很简单的实现相关拦截;而与此相对的,低版本的 MongoDB 的驱动或者是 Spring Data MongoDB 的实现就没有如此接口,想要实现拦截查询语句的功能,就比较困难。

因此在这一点上,Brave 是硬伤,无论使用字节码注入多么困难,但至少也是可以实现的,但是 Brave 却有无从下手的可能,而且是否可以注入,能够多大程度上注入,更多的取决于框架的 API 而不是自身的能力。(此问题在下一节继续讨论另外一种可能性)

4.2、难度及成本

经过简单阅读 Pinpoint 和 Brave 插件的代码,可以发现两者的实现难度有天壤之别。在都没有任何开发文档支撑的前提下,Brave 比 Pinpoint 更容易上手。Brave 的代码量很少,核心功能都集中在 brave-core 这个模块下,一个中等水平的开发人员,可以在一天之内读懂其内容,并且能对 API 的结构有非常清晰的认识。

Pinpoint 的代码封装也是非常好的,尤其是针对字节码注入的上层 API 的封装非常出色,但是这依然要求阅读人员对字节码注入多少有一些了解,虽然其用于注入代码的核心 API 并不多,但要想了解透彻,恐怕还得深入 Agent 的相关代码,比如很难一目了然的理解 addInterceptor 和 addScopedInterceptor 的区别,而这两个方法就是位于 Agent 的有关类型中。

因为 Brave 的注入需要依赖底层框架提供相关接口,因此并不需要对框架有一个全面的了解,只需要知道能在什么地方注入,能够在注入的时候取得什么数据就可以了。就像上面的例子,我们根本不需要知道 MySQL 的 JDBC Driver 是如何实现的也可以做到拦截 SQL 的能力。但是 Pinpoint 就不然,因为 Pinpoint 几乎可以在任何地方注入任何代码,这需要开发人员对所需注入的库的代码实现有非常深入的了解,通过查看其 MySQL 和 Http Client 插件的实现就可以洞察这一点,当然这也从另外一个层面说明 Pinpoint 的能力确实可以非常强大,而且其默认实现的很多插件已经做到了非常细粒度的拦截。

针对底层框架没有公开 API 的时候,其实 Brave 也并不完全无计可施,我们可以采取 AOP 的方式,一样能够将相关拦截注入到指定的代码中,而且显然 AOP 的应用要比字节码注入简单很多。

以上这些直接关系到实现一个监控的成本,在 Pinpoint 的官方技术文档中,给出了一个参考数据。如果对一个系统集成的话,那么用于开发 Pinpoint 插件的成本是 100,将此插件集成入系统的成本是 0;但对于 Brave,插件开发的成本只有 20,而集成成本是 10。从这一点上可以看出官方给出的成本参考数据是 5:1。但是官方又强调了,如果有 10 个系统需要集成的话,那么总成本就是 10 * 10 + 20 = 120,就超出了 Pinpoint 的开发成本 100,而且需要集成的服务越多,这个差距就越大。

4.3、通用性和扩展性

很显然,这一点上 Pinpoint 完全处于劣势,从社区所开发出来的集成接口就可见一斑。

Pinpoint 的数据接口缺乏文档,而且也不太标准(参考论坛讨论帖),需要阅读很多代码才可能实现一个自己的探针(比如 Node 的或者 PHP 的)。而且团队为了性能考虑使用了 Thrift 作为数据传输协议标准,比起 HTTP 和 JSON 而言难度增加了不少。

4.4、社区支持

这一点也不必多说,Zipkin 由 Twitter 开发,可以算得上是明星团队,而 Naver 的团队只是一个默默无闻的小团队(从 #1759 的讨论中可以看出)。虽然说这个项目在短期内不太可能消失或停止更新,但毕竟不如前者用起来更加放心。而且没有更多社区开发出来的插件,让 Pinpoint 只依靠团队自身的力量完成诸多框架的集成实属困难,而且他们目前的工作重点依然是在提升性能和稳定性上。

4.5、其他

Pinpoint 在实现之初就考虑到了性能问题,www.naver.com 网站的后端某些服务每天要处理超过 200 亿次的请求,因此他们会选择 Thrift 的二进制变长编码格式、而且使用 UDP 作为传输链路,同时在传递常量的时候也尽量使用数据参考字典,传递一个数字而不是直接传递字符串等等。这些优化也增加了系统的复杂度:包括使用 Thrift 接口的难度、UDP 数据传输的问题、以及数据常量字典的注册问题等等。

相比之下,Zipkin 使用熟悉的 Restful 接口加 JSON,几乎没有任何学习成本和集成难度,只要知道数据传输结构,就可以轻易的为一个新的框架开发出相应的接口。

另外 Pinpoint 缺乏针对请求的采样能力,显然在大流量的生产环境下,不太可能将所有的请求全部记录,这就要求对请求进行采样,以决定什么样的请求是我需要记录的。Pinpoint 和 Brave 都支持采样百分比,也就是百分之多少的请求会被记录下来。但是,除此之外 Brave 还提供了 Sampler 接口,可以自定义采样策略,尤其是当进行 A/B 测试的时候,这样的功能就非常有意义了。

五、总结

从短期目标来看,Pinpoint 确实具有压倒性的优势:无需对项目代码进行任何改动就可以部署探针、追踪数据细粒化到方法调用级别、功能强大的用户界面以及几乎比较全面的 Java 框架支持。但是长远来看,学习 Pinpoint 的开发接口,以及未来为不同的框架实现接口的成本都还是个未知数。相反,掌握 Brave 就相对容易,而且 Zipkin 的社区更加强大,更有可能在未来开发出更多的接口。在最坏的情况下,我们也可以自己通过 AOP 的方式添加适合于我们自己的监控代码,而并不需要引入太多的新技术和新概念。而且在未来业务发生变化的时候,Pinpoint 官方提供的报表是否能满足要求也不好说,增加新的报表也会带来不可以预测的工作难度和工作量。