千亿级服务器监控数据存储实践

导语

公司目前有几十万台左右服务器,TMP(腾讯监控平台)平均每天采集1200亿+监控数据,本文将从当前存储架构存在的问题出发,介绍使用大数据平台组件Hbase存储TMP监控数据的实践历程。

背景

近几年开源的大数据处理系统已经逐步发展到一个比较成熟的阶段了,各类大数据处理的场景都有了相应的解决方案,如同 mysql 在当今互联网公司中的关系数据存储广泛应用地位一样。

公司目前有几十万台量级的服务器,TMP 系统按 1 分钟粒度采集监控数据,平均每天采集 1200 多亿的数据点。本文将从当前存储架构存在的问题出发,介绍从尝试使用Opentsdb到自行设计Hbase存储方案来存储 TMP 服务器海量监控数据的实践历程。

TMP 当前存储架构分析

我们首先看下当前的 TMP 的 1 分钟粒度数据存储架构。Agent 上报的数据,通过 collector 从 mysql 数据表中查询索引和路由规则 a,分发到不同的数据存储结点上。数据节点 Datacache 收到数据后先缓冲到内存中,内存的数据定期 DUMP 到文件系统中。

这套架构优点很明显,设计简洁、有最新数据缓存、数据分布式存储、可横向扩展,同时完全自研,各自实现细节可控。但同样存在一些问题:

a.数据节点 Cache 程序异常,会导致内存缓存数据丢失,进而丢失监控数据,需要从 agent 端或者对等集群恢复;

b.数据节点磁盘故障或机器故障,持久化的 FILE 也会丢失,数据同样需要从对等集群中恢复,数据访问入口需要人工介入切换集群;

c.数据格式和占用空间固定,不具备监控粒度扩展性,空的数据点也要占据存储空间,数据不支持压缩;

d.索引和路由规则这类依赖外部 DB 系统,这些 metadata 的可用性影响整个系统。

Hbase 存储引擎优势

Hbase 是 Hadoop 生态栈中的分布式列存储数据库,基于 Bigtable 模型和 LSM-Tree 存储引擎,用于海量数据的随机读写,在业界的大规模监控系统的时序数据存储中已有成熟应用案例,如某度和某宝 。

图 1. Hbase 的存储原理

我们看下使用 Hbase 存储有何优势:

a.数据高可靠,高可用。数据在写内存的同时,会写一份 HLog 到 HDFS 中,如果某台 RegionServer 异常,内存中的数据会从 Hlog 中自动恢复。持久化数据保存在 HDFS 中,默认持有 3 个副本,无单点丢失数据风险。

b.高性能。LSM-Tree 存储引擎保证了 Hbase 超高的写性能,实际上前面介绍的 TMP 自研存储系统也是一种简化版的 LSM-Tree 存储引擎,因而同样有如此高的性能。

c.天然的水平伸缩,高可扩展性。存储层 DataNode,数据服务层 RegionServer 均支持自由伸缩扩容。

d.数据表支持压缩,空列不占存储空间。

Opentsdb 尝试及瓶颈分析

在准备使用 Hbase 存储 TMP 监控数据之初,我们曾尝试使用基于 Hbase 的开源时序数据库 Opentsdb 来直接存储服务器监控数据。但 Opentsdb 到 70w/s 的时候整个 Hbase 集群就已超负荷运转、响应缓慢了,完全无法满足如此大规模的存储需求。

我们仔细分析了 Opentsdb 在超大规模时序数据存储上存在的主要瓶颈:

a.所有 metric 跟 tag 都要经过 tsdb-uid 表的转换,此设计本意是为了压缩 rowkey 大小,但引入较大的计算资源开销;

b.数据写入的 Append 机制及原始 compaction 设计存在较大的性能问题,这在后面部分会详细分析;

c.所有的数据都放在同一张表里,不利于基于时间对数据进行维护操作,比如对一个月前非热点数据进行抽样存储,且无法控制 Region 数,也就无法控制 split,对性能影响较大;

基于这些原因,我们最终决定直接使用 Hbase 进行 TMP 服务器监控数据存储。

TMP 监控存储设计实践

Hbase 的使用在整个 hadoop 生态栈中属于较为复杂的一个类别。TMP 监控存储设计结合了业界使用 Hbase 的一些成熟的实践经验,同时参考和改进了 OpenTSDB 在使用 HBase 时的比较好的设计思想,以支撑 TMP 监控数据的大规模读写。

2.1  Region 预切分

Hbase 中的数据会按 rowkey 所处范围分布在各个 Region 中,新建表的时候只有一个 Region,并随着 Region 变大开始分裂。这在过程中会消耗大量在网络、磁盘 IO 等资源,对集群会有较大性能影响。同时由于开始期间只有少量 Region,数据的读写很容易全落在单台 RegionServer 上,造成 HotSpot 现象,严重影响读写性能。因此对存储表进行 Region 预切分处理是 Hbase 使用中十分重要的一步。

这里我们将每天的数据表预切分为 100 个 Region, 以{0x01, 0x01 … 0x63},即二进制的 1~99 为 splitKeys,第一个 Region Rowkey 范围为 0x00…~0x01,第二个 Region Rowkey 范围为 0x01…~0x02,以此内推。结合接下来这节中的 Rowkey salt 设计就可以均匀地将数据分散在各 Region 中。

2.2  Rowkey 和列设计

Rowkey 设计由 salt(1 byte) 服务器 ID(4 byte) timestamp(4 byte) 监控特性 ID(4 byte) 的方式组成。

a.Salt 是使用服务器 id 进行 hash 后对单表初始 Region 数进行求余所得的一位字节,用来将不同服务器的监控数据均匀分布在表的各个 Region 中

b.Rowkey 第二部分为服务器 ID,服务器监控数据查询通常是查询指定服务器的某些特征,因而将服务器 ID 放在第二部分可以大幅提高查询效率;

c.timestamp 实际上是一个 time-base,用于将一段时间内的数据存放在同一行;

d.attr_id 为特性 id,区分具体监控指标。

这里使用一个字节 t 作为列族,列族名称本身并没什么含义,主要强调只使用一个列族存储数据,尽量小的名称作为名字。使用多列族每个 Region 会对应有多个 Memstore,会加重内存消耗,在此场景下不适用。

列名(在 Hbase 中称 Qualifier)为时间偏移,与 Rowkey 中的 time-base 一起组成 timestamp 标识数据点的精确时间。

2.3  基于列的 Compaction

在介绍列 Compaction 之前,我们先看下 Hbase 数据的具体存储结构:

表结构与存储结构

如图所示为表结构以及对应的存储结构示例,在 Hbase 或表格存储这类底层采用 LSM-tree 的数据库中,表数据会按列存储。每行中的每一列在存储文件中都会以 Key-value 的形式存在于文件中。其中 Key 的结构为:行主键 列族 列名,Value 为列的值。该种存储结构的特点是:

a、每行主键会重复存储,取决于列的个数;

b、列名会重复存储,每一列的存储都会携带列名;

c、存储数据按 row-key排序,相邻的 row-key会存储在相邻的块中。

可以注意到,在 Hbase 的物理存储中,每一列都会存储该列的 rowkey 和列族信息,在列很多的情况下这些重复的信息将占用大量的存储空间。因此这里参考 Opentsdb 的做法,将同一 time-base 内的所有列合并压缩为一列(注意这里说的列 Compaction 与 HBase 本身的 Compation 是完全不同的,Hbase 的 Compation 是指将多个小的 HFile 合并为一个大的 HFile)。

Opentsdb 的列 Compaction 由数据量大小和时间间隔共同触发,在并发写操作巨大的时候会对 Hbase 产生很大的读写压力,并且会阻塞写操作,性能表现较差。2.2 版本加入的 append 机制更是每一次写操作产生一次读操作,对 Hbase 利用很不经济,写入量大时会对整个集群的读压力造成巨大影响。

基于这些原因,TMP 监控数据在每天凌晨对前一天的数据表进行全表扫描,并对每行数据的列名(Qualifier)和 Value 进行合并,压缩为一列。在现网实际环境中可以看到,列压缩后的数据表比压缩前占用存储空间减少接近90%,如下图

2.4  Hbase 性能调优

Hbase 性能调优是个比较复杂的事情,网上可以看到很多专门讲 Hbase 调优的文章。这里仅挑出几个比较立竿见影的点来分享。

a.Heap 和 Memstore 大小。尽量调大 RegionServer 的 heap 大小,如写入量远大于查询量,可以增大 Memstore 与 BlockCache 的比例,如 0.5 : 0.3 。原因是 HBase 基于 LSM Tree 的存储引擎,数据会先缓存至 Memstore 再刷入磁盘

b.Snappy 压缩。对数据表启用 Snappy 压缩,可以减少磁盘 IO,增大写入性能

c.Hbase 自身的 Compation 线程数。Hbase 在 flush 和 compaction 的时候会对 rowkey 进行排序操作,适当增大 compaction 线程,可更加充分利用 CPU,增加性能。具体可将 hbase.regionserver.thread.compaction.small/large 调节为 5。

d.GC 调优。GC 参数设置不当会触发 Stop the world 这类严重影响性能的问题,具体可参考这篇文章《HBase最佳实践-CMS GC调优》

 总结

基于上述设计和优化后, TMP 监控数据存储方案比直接使用 Opentsdb 存储性能提高了 3~5 倍,8 台 RegionServer 峰值写入速率可达 400w/s ,Opentsdb 则到 70w/s 的时候整个 Hbase 集群就已经无法正常工作了。

目前此套基于 Hbase 的监控数据存储系统已经上线提供服务,后续计划在入库 Hbase 之前加入缓冲层进行列的预 Compaction,可进一步成倍提升整体性能。HBase 发展至今已是个比较成熟的开源分布式数据库,其高性能,高可用性及高可扩展的特性,可为海量数据的存取提供强大动力。

原创声明,本文系作者授权云+社区-专栏发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏码代码的陈同学

Java应用性能优化之道

第一篇 理解 Java GC 中我们学习了不同GC算法的处理过程,GC是如何工作的,什么是年轻代和老年代,JDK7中的5种GC类型,以及每种GC类型对性能的影响...

1723
来自专栏后端技术探索

如何解决秒杀的性能问题和超卖的讨论

最近业务试水电商,接了一个秒杀的活。之前经常看到淘宝的同行们讨论秒杀,讨论电商,这次终于轮到我们自己理论结合实际一次了。

681
来自专栏跨界架构师

过去这几十年,分布式系统的「数据一致性」精华都在这了!

        本文是本系列的第三篇。与前两篇《分布式系统关注点——数据一致性(上篇)》、《分布式系统关注点——通过“共识”达成数据一致性》形成完整的「数据一致...

991
来自专栏Golang语言社区

Golang语言社区--游戏服务器端开发的一些建议(转载)

大家好,我是Golang语言社区(www.golang.ltd)主编彬哥,本篇给大家转载一篇关于游戏服务器开发的文章。

4407
来自专栏韩伟的专栏

帧同步游戏开发基础指南

最近一个月休了个假,体验了一下类似欧洲的田园生活。所以更新几乎荒废了,但是总结和积累是一直持续着的。根据前一阶段对于实时对战游戏的开发思考,写了这一篇入门级的文...

4346
来自专栏北京马哥教育

Redis集群技术

1. Redis常见集群技术 长期以来,Redis本身仅支持单实例,内存一般最多10~20GB。这无法支撑大型线上业务系统的需求。而且也造成资源的利用率过低——...

2887
来自专栏鹅厂网事

走进腾讯公网传输系统

"鹅厂网事"由深圳市腾讯计算机系统有限公司技术工程事业群网络平台部运营,我们希望与业界各位志同道合的伙伴交流切磋最新的网络、服务器行业动态信息,同时分享腾讯在网...

2385
来自专栏Java职业技术分享

又出现异常数据?架构师深度剖析分布式系统「事务」

如果说「共识」解决的是「水平」问题,那么「事务」解决的是「垂直」问题。是如何让一条绳上的蚂蚱共同起舞?

773
来自专栏CSDN技术头条

勿谈大,且看Bloomberg的中数据处理平台

中数据意味着数据体积已经超越单服务器处理的上限,但也无需使用数千台节点组成的集群——通常是TB级,而不是PB级的。这里,我们不妨走进Bloomberg的用例,着...

2016
来自专栏Java架构师学习

多研究些架构,少谈些框架——一名阿里架构师的笔记

微服务架构和SOA区别 微服务现在辣么火,业界流行的对比的却都是所谓的Monolithic单体应用,而大量的系统在十几年前都是已经是分布式系统了,那么微服务作为...

3358

扫码关注云+社区