AppDynamics 公司的 智能程序平台 可以帮助客户分析软件程序的性能、用户体验和业务影响等,并可以提供实时的监控、故障解决和分析等服务。智能程序平台的核心是负责记录、跟踪和比较性能指标的指标处理引擎。在软件程序复杂度爆发性增长和许多公司把单一程序拆分成微服务的背景下,指标处理引擎需要采集和分析的指标也变得极度复杂和庞大,因而他们不得不重构了整个系统。 Gautam Borah 在AppDyamics公司负责产品设计和开发基于大数据技术的下一代指标处理系统,他最近在 博客 中记录了这次重构的选型情况。
AppDynamics的程序性能管理(Application Performance Management ,APM)代理在为几千个程序几百万行代码收集性能指标,它们支持包括Jave、.Net、Node.js、PHP和Python等在内的多种语言和框架。可收集浏览器、手机和服务器程序数据,还有扩展程序从各种异构程序和基础设施模块收集数据。收集到的指标被周期性的发送给指标处理引擎,它把各种维度的指标收集起来再以不同角度的视图展示出去。
最初的指标处理引擎是基于MySQL的,但当指标指数级的增长之后,要处理的指标数已经逼近MySQL的物理上限。研发团队总结对智能平台的主要需求是:
研发团队进行了周密的选型。StumbleUpon的OpenTSDB和MetaMarkets的Druid都是不错的时间序列数据库,但由于指标处理引擎的需求太特别,用它们不太合适。在能提供容错和横向扩展的开源键值型存储中,最主流和使用最广的就是HBase和Cassandra了。
最终选择的是HBase,胜出原因也是它的分区策略是按主键有序排列的范围分区,这样就可以自由的按时间范围进行查询,时间跨度大也无所谓,并且方便使用各种集合算法。
HBase的键值对存储在表中,而且每张表都被拆分成多个Region,每个Region中都存储着一段按主键排序的连续数据,即表中从一个Region的初始主键开始到结束主键的范围内的所有数据都存储在这一个Region中。Hortonworks有 文章 详细解释了这个机制。
Cassandra分区策略与此不同,它的节点是按一致性哈希环分布的,所有的主键都转换成Murmur3哈希值然后放在某个节点中。Datastax的 文章 中解释了这种分区策略。
为什么按主键做范围查询如此重要?
如下图所示的AppDynamics程序性能仪表盘提供了整个程序性能指标的拓朴视图。仪表盘展现了业务程序的调用链,还有每分钟调用率、平均响应时间、每分钟错误率和每分钟异常率等性能统计。
拓朴图、调用链、性能统计等都是直接按时间范围从指标库里查出来的。典型的查询语句是:
Select SUM(totals calls) from METRICS where metricID = m1 and time in range (t1, t2), t1-start time, t2 – end time. Select AVG(response time) from METRICS where metricID = m1 and time in range (t1, t2), t1-start time, t2 – end time. Select SUM(total errors) from METRICS where metricID = m1 and time in range (t1, t2), t1-start time, t2 – end time.
解决这个问题的一个最简单设计就是把metricID做为表的主键,把时间点做为表的字段,在某个时间点采取的指标值就保存在对应时间点的字段里。HBase和Cassandra都支持这种设计,而且因为主键是metricID,不管HBase还是Cassandra,这个指标的所有值都会保存在一个分区里。查询一个时间范围内的指标值时,只需要把对应的时间点里的值取出,再加上上面查询语句对应的算法就可以了。
但这个设计在现实中是不可行的,因为不管理论上还是工程上,一张表所能支持的字段数都是有限的。在指标处理系统中,一分钟至少要保存一个值,一天就有几千个值,一星期就会有几百万,而一年则会有几十亿。不可能设计一张表有这么多字段。
一个相对好得多的改进设计是把主键按时间段分区。即主键是metricID加上时间段,对应的时间段里的各个时间点的值,则和上文一样作为表的字段保存起来。比如以一个小时为一个时间段,则从12:00AM到12:00PM总共会有12个主键值。有一篇 文章 讲述了Cassandra如何用这个方法为时间序列问题建模的,具体就是它的组合主键。使用metricID作为分区键,使用时间段的值作为集合键,收到的指标值作为表的字段保存起来。Cassandra的存储引擎底层是使用组合字段来存储集合值的。所有相同分区键对应的逻辑行,实际上是做为一个物理宽行保存的。通过这种方法,Casasandra每个物理行可以支持20亿个字段。
HBase则没有组合主键的概念,它的主键就是一个字符串。数据在HBase里的保存是按照主键的字母顺序排序的,主键值相邻的记录会保存在同一个分区里,即Region。如果主键设计的好的话,几年的指标数据都可以保存在HBase的一个Region中。
这个概念很重要,对这个用例也非常有用。因为一个很长的时间范围内的数据都存储在同一个Region中,那即使做一个半年内甚至两年内的集合运算,它也是在一个Region Server内部计算,算完了只把结果返回给调用程序,因而极大的减少了网络流量。如果不是这样的设计,那数据就可能会分散在多个分区(甚至是多台机器)上,做集合运算就要把数据从各个分区集中到一个客户端程序上,它做完集合运算后,再把最终结果发送到调用程序。这样代价非常大。
除此之外,弃用Cassandra还因为它缺少几个HBase已有的关键功能:
作者在下一篇博客中会讲到他使用HBase过程中碰到的问题及一些改进建议。作者非常欢迎大家 留言 反馈。
感谢杜小芳对本文的审校。
给InfoQ中文站投稿或者参与内容翻译工作,请邮件至editors@cn.infoq.com。也欢迎大家通过新浪微博(@InfoQ,@丁晓昀),微信(微信号: InfoQChina )关注我们。