为什么AppDynamics重构指标服务时选择了HBase而不是别的NOSQL
ekth4092
8年前
<p><a href="/misc/goto?guid=4958986691464986896" rel="nofollow,noindex">AppDynamics</a> 公司的 <a href="/misc/goto?guid=4959675282298127301" rel="nofollow,noindex">智能程序平台</a> 可以帮助客户分析软件程序的性能、用户体验和业务影响等,并可以提供实时的监控、故障解决和分析等服务。智能程序平台的核心是负责记录、跟踪和比较性能指标的指标处理引擎。在软件程序复杂度爆发性增长和许多公司把单一程序拆分成微服务的背景下,指标处理引擎需要采集和分析的指标也变得极度复杂和庞大,因而他们不得不重构了整个系统。 <a href="/misc/goto?guid=4959675282394257733" rel="nofollow,noindex">Gautam Borah</a> 在AppDyamics公司负责产品设计和开发基于大数据技术的下一代指标处理系统,他最近在 <a href="/misc/goto?guid=4959675282474177997" rel="nofollow,noindex">博客</a> 中记录了这次重构的选型情况。</p> <p>AppDynamics的程序性能管理(Application Performance Management ,APM)代理在为几千个程序几百万行代码收集性能指标,它们支持包括Jave、.Net、Node.js、PHP和Python等在内的多种语言和框架。可收集浏览器、手机和服务器程序数据,还有扩展程序从各种异构程序和基础设施模块收集数据。收集到的指标被周期性的发送给指标处理引擎,它把各种维度的指标收集起来再以不同角度的视图展示出去。</p> <p><img src="https://simg.open-open.com/show/762cf7f83aa0892a4796b77cd77d4233.png"></p> <p>最初的指标处理引擎是基于MySQL的,但当指标指数级的增长之后,要处理的指标数已经逼近MySQL的物理上限。研发团队总结对智能平台的主要需求是:</p> <ul> <li>处理的指标总量要比当前翻许多倍</li> <li>各个维度的数据保留期限要延长很多</li> <li>实时收集业务集群指标数据,并要做集合运算</li> <li>要支持批处理</li> <li>系统容错,消除单点故障</li> <li>软件升级不停服</li> </ul> <p>研发团队进行了周密的选型。StumbleUpon的OpenTSDB和MetaMarkets的Druid都是不错的时间序列数据库,但由于指标处理引擎的需求太特别,用它们不太合适。在能提供容错和横向扩展的开源键值型存储中,最主流和使用最广的就是HBase和Cassandra了。</p> <p>最终选择的是HBase,胜出原因也是它的分区策略是按主键有序排列的范围分区,这样就可以自由的按时间范围进行查询,时间跨度大也无所谓,并且方便使用各种集合算法。</p> <p>HBase的键值对存储在表中,而且每张表都被拆分成多个Region,每个Region中都存储着一段按主键排序的连续数据,即表中从一个Region的初始主键开始到结束主键的范围内的所有数据都存储在这一个Region中。Hortonworks有 <a href="/misc/goto?guid=4959675282555131720" rel="nofollow,noindex">文章</a> 详细解释了这个机制。</p> <p>Cassandra分区策略与此不同,它的节点是按一致性哈希环分布的,所有的主键都转换成Murmur3哈希值然后放在某个节点中。Datastax的 <a href="/misc/goto?guid=4959675282630673631" rel="nofollow,noindex">文章</a> 中解释了这种分区策略。</p> <p>为什么按主键做范围查询如此重要?</p> <p>如下图所示的AppDynamics程序性能仪表盘提供了整个程序性能指标的拓朴视图。仪表盘展现了业务程序的调用链,还有每分钟调用率、平均响应时间、每分钟错误率和每分钟异常率等性能统计。</p> <p><img src="https://simg.open-open.com/show/76c0b247c94561f02886bc632e6cbda5.png"></p> <p>拓朴图、调用链、性能统计等都是直接按时间范围从指标库里查出来的。典型的查询语句是:</p> <pre> 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.</pre> <p>解决这个问题的一个最简单设计就是把metricID做为表的主键,把时间点做为表的字段,在某个时间点采取的指标值就保存在对应时间点的字段里。HBase和Cassandra都支持这种设计,而且因为主键是metricID,不管HBase还是Cassandra,这个指标的所有值都会保存在一个分区里。查询一个时间范围内的指标值时,只需要把对应的时间点里的值取出,再加上上面查询语句对应的算法就可以了。</p> <p>但这个设计在现实中是不可行的,因为不管理论上还是工程上,一张表所能支持的字段数都是有限的。在指标处理系统中,一分钟至少要保存一个值,一天就有几千个值,一星期就会有几百万,而一年则会有几十亿。不可能设计一张表有这么多字段。</p> <p>一个相对好得多的改进设计是把主键按时间段分区。即主键是metricID加上时间段,对应的时间段里的各个时间点的值,则和上文一样作为表的字段保存起来。比如以一个小时为一个时间段,则从12:00AM到12:00PM总共会有12个主键值。有一篇 <a href="/misc/goto?guid=4959675282723050512" rel="nofollow,noindex">文章</a> 讲述了Cassandra如何用这个方法为时间序列问题建模的,具体就是它的组合主键。使用metricID作为分区键,使用时间段的值作为集合键,收到的指标值作为表的字段保存起来。Cassandra的存储引擎底层是使用组合字段来存储集合值的。所有相同分区键对应的逻辑行,实际上是做为一个物理宽行保存的。通过这种方法,Casasandra每个物理行可以支持20亿个字段。</p> <p>HBase则没有组合主键的概念,它的主键就是一个字符串。数据在HBase里的保存是按照主键的字母顺序排序的,主键值相邻的记录会保存在同一个分区里,即Region。如果主键设计的好的话,几年的指标数据都可以保存在HBase的一个Region中。</p> <p><img src="https://simg.open-open.com/show/a0451faffed33d9c04f8aaf7f73a9d5a.png"></p> <p>这个概念很重要,对这个用例也非常有用。因为一个很长的时间范围内的数据都存储在同一个Region中,那即使做一个半年内甚至两年内的集合运算,它也是在一个Region Server内部计算,算完了只把结果返回给调用程序,因而极大的减少了网络流量。如果不是这样的设计,那数据就可能会分散在多个分区(甚至是多台机器)上,做集合运算就要把数据从各个分区集中到一个客户端程序上,它做完集合运算后,再把最终结果发送到调用程序。这样代价非常大。</p> <p>除此之外,弃用Cassandra还因为它缺少几个HBase已有的关键功能:</p> <ol> <li>HBase允许把指标分配到不同的列族里,然后以列族为单位设置过期值。Cassandra则以Cell为单位设置过期值,而且对相同类型的Cell要逐一设置,就使得存储非常臃肿。2015年11月发布的Cassandra 3.0解决了这个问题。</li> <li>HBase的设计是在可用性的基础上再提供了一致性,由于指标系统的策略引擎是不断计算的,所以这个功能非常关键。想进一步了解CAP理论可以参考 <a href="/misc/goto?guid=4959675282793725513" rel="nofollow,noindex">这篇文章</a> 。</li> </ol> <p>来自: <a href="/misc/goto?guid=4959675282871602424" rel="nofollow">http://www.infoq.com/cn/news/2016/07/AppDynamics-HBase-NOSQL</a></p> <p> </p>