分享

OPPO云可观测服务基础组件TSDB技术实践

 新用户0175WbuX 2022-02-17

  随着服务规模的扩大和复杂性的提高,对于系统需要更为深入、细致的观察。可观测能力成为云原生的关键能力。OPPO云相应的推出了自研高性能的可观测产品,时序数据库TSHouse和日志数据库LogHouse。

  本文将通过对开源TSDB的对比分析介绍自研TSHouse的设计初衷,并对TSHouse的架构和存储引擎设计进行解析,为大家全面介绍TSHouse的技术实践。

  在互联网行业,观测系统和线上状况的监控杆一直都是“刚需”,而监控指标存储和聚合查询服务是每个公司都必须构建的基础服务。无论是实时监控、问题定位还是性能分析,秒级的指标变化能够提供更为丰富的信息。同时,秒级粒度指标还为智能告警服务及时性、云资源调度准确性、大数据分析和AI训练数据丰富性提供巨大帮助。全网秒级监控系统已经逐渐成为业界的监控能力的标志。

  秒级监控需求带来了对时序数据存储的挑战,主要包括:

  亿级/s的指标数据点实时读写;PB级的指标存储,为了节约存储成本,需要支持高效率压缩和自动降精度;需要支持聚合查询,丰富的聚合和计算函数。

  针对时序数据存储的特性,业界开辟了一个专有的数据库领域——时序数据库(TSDB)来支撑数据存储。而对于全网秒级的监控系统存储需求,需要分布式高性能的时序数据库进行支持。

  TSDB在开源领域一直是一个热门的话题,各个公司和组织也陆续开源出众多的TSDB项目。如下是DB-Engines上时序数据库排名趋势图:

  OPPO云可观测服务基础组件TSDB技术实践

  可以看到排名靠前的TSDB包括:InfluxDB、kdb+(非开源)、Prometheus、Graphite、RRDtool、OpenTSDB、TimescaleDB和Druid。排名一直处于第一的InfluxDB和热度持续上升的Prometheus是我们重点关注的两个开源TSDB项目。

  监控数据有着写多读少的特点,同时要尽量控制资源消耗,因此能否充分发挥硬件性能,高效压缩同时又满足查询时延要求是TSDB存储引擎设计的关键。我们对现有的TSDB项目进行了一下综合比较:

  OPPO云可观测服务基础组件TSDB技术实践

  经过存储引擎分析和实际的性能测试,以InfluxDB和Prometheus为代表的类LSM存储引擎性能在众多TSDB中表现优异。在一般规模下,许多公司直接采用开源的版本解决方案就可以满足需求。但是随着机房和机器越来越多,监控规模越来越大,数量众多的单节点TSDB维护成本极高,各种维度聚合查询的任务很难开展,而监控粒度也无法真正到达秒级。而InfluxDB和Prometheus在扩展性、分布式、高可用等方面存在着较为明显的短板,以至于其在大规模海量数据支持的场景下无法较好的应对。

  为更好的满足秒级海量监控指标存储的需求,提供有竞争力的产品和服务,我们在分析了开源TSDB项目现状和当前监控系统痛点之后,决定通过“技术降成本”打造出比开源项目更有优势的OPPO云高性能分布式TSDB产品TSHouse:

  分布式:统一分布式集群,支持存储和服务的高可用、负载均衡和动态扩展;高性能:单节点400w/s写入能力,集群性能基本随着节点线性增长可达亿级/s写入;高压缩:高效压缩算法,可达10倍以上压缩比,支持海量时序数据存储;丰富查询:支持降精度、丰富的聚合查询方法;简单易用:通用的时序概念和接口,使用简单,全面的统计和运维工具;生态丰富:拥抱开源生态,兼容Prometheus的PromQL、Exporter、Pushgateway接口,支持Grafana;

  TSHouse在架构上采用分片和多副本的设计,支持分布式和高可用。同时为提高性能,在存储引擎上进行了大量的优化。

  OPPO云可观测服务基础组件TSDB技术实践

  TSHouse是使用golang语言进行开发,开箱即用,主要包括两个组件TSManager和TSNode。

  TSManager管理集群元数据信息,采用Raft协议保证数据一致性和高可用。元数据信息包括存储节点(TSNode)状态、分片(Range)和复制组(ReplicaGroup)信息。

  TSNode存储时序数据,包括Proxy和Storage Engine两个部分,Proxy负责查询元数据信息并进行多副本数据写入。Storage Engine提供高性能高压缩的存储服务。TSNode可以运行在Proxy模式,即只做查询代理服务,这样就可以配置独立的查询集群,和数据写入进行隔离,相互不影响。

  OPPO云可观测服务基础组件TSDB技术实践

  TSHouse根据时间段进行分片(Range),目前采用一天一个Range的分片方式,并在每天0点之前提前创建好。每个Range生成的时候根据当时的可用TSNode节点创建复制组(ReplicaGroup),绑定了TSNode多副本复制关系。时序数据写入时,根据时间戳找到Range(通常是最新那个Range)后,根据HASH算法分散到某个ReplicaGroup,然后根据复制组绑定关系写入多个TSNode后端。HASH算法我们采用了性能较高的xxhash,并使用了固定的时序数据标签(Tag)进行HASH计算(如目标节点IP作为HASH因子,有效提升HASH分片计算的性能)

  OPPO云可观测服务基础组件TSDB技术实践

  2.3.1 高可用

  TSHouse支持时序数据多副本存储,在跨机房部署时,TSNode上报TSManager其所属机房信息,TSManager选择多副本时,将来自多机房的TSNode组成ReplicaGroup,保证跨机房多活。

  时序元数据存储在TSManager,部署至少3台TSManager组成Raft复制组,使用Raft协议保证高可用和数据一致性。数据的持久化我们采用本地的LevelDB,通过Raft的Snapshot机制将LevelDB进行备份,并删除过期Raft的WAL文件释放磁盘空间。

  无论是写入还是查询服务,都可以从任意TSNode接入,通过内部Proxy进行分片数据的路由和实际写入和查询操作。

  TSHouse还支持提供单独的TSNode-Proxy集群,独立于TSNode主集群,用于大量聚合查询的服务,避免某些查询请求对CPU、内存消耗过大时对数据写入产生影响。

  2.3.2 负载均衡

  根据Range时长(默认为一天)定时生成Range时,TSManager获取到最新的TSNode状态信息,选取存储空间和IO负载可以满足未来Range写入需求的TSnode节点,组成ReplicaGroup提供数据写入服务。

  写入和查询的接入通过DNS Server的轮选机制进行负载均衡。客户端接入之后通过Route接口可以重新路由到提供实际服务的TSNode节点。Route接口会根据集群里各个节点的负载情况进行分片负载最轻的节点提供服务。

  2.3.3 水平扩展

  当存储空间不足或者时序数据写入量增大无法支撑时,支持动态扩容TSNode集群,部署新的TSNode将会在下一个Range里提供存储服务。由于默认的Range为一天,因此正常情况下,扩容时需要提前一天进行操作。紧急情况急需扩容时,我们提供了工具支持动态创建新的Range。

  同样,时序数据查询服务也可以动态进行扩展,部署新增的TSNode或者TSNode-Proxy(只提供查询服务)加入集群,立即扩展查询服务能力。

  2.3.4 数据恢复

  在同一个Range里,TSNode的复制关系是固定的,即这一天的数据在同一个ReplicaGroup的所有TSNode上是一样的。当一个TSNode出现故障时,数据写入其他的副本,Proxy会尝试重试,如果重试之后还是失败,则记录该TSNode失败的时间点。当故障的TSNode恢复后,TSManager后台发起恢复任务将失败的时间范围数据从其他副本进行同步。

  OPPO云可观测服务基础组件TSDB技术实践

  存储引擎的设计主要是满足高性能的数据的写入和满足需求的查询性能。时序数据具有写多读少的特点,比较适合使用类似LSM-Tree的数据结构。加上数据具有时序性,因此存储引擎采用一种TSM-Tree(Time Structured Merge Tree)的数据结构:

  最近的数据写入内存MemBlock,按Time Series + timestamp进行排序。MemBlock保留的时长可配置,默认2小时。MemBlock写满2小时后,设置为Closed,Closed之后将不再写入新的数据。通常为了保证采集的数据都能写入,MemBlock会在内存中多缓存一段时间(如1小时)再设置closed并下盘。后台进行Level Compaction将磁盘上的Block合并,对于时序数据来说,合并操作只需要比较Time Series,将相同的Time Series连接在一起即可,无需比较时间戳。针对时序数据特点,对时序数据进行了压缩:timestamp时间戳采用差值的差值算法(时间间隔相同的情况下,差值的差值为0),value采用XOR算法。实测压缩比可以达到10倍。WAL机制,数据除了写入MemBlock进行排序,还会写入一份到WAL日志文件(顺序IO),当异常重启后,从WAL日志文件恢复成Write Request重新构建Block。当数据量较大时,WAL文件恢复需要较长的时间,因此我们通过立即创建新的MemBlock,同时后台异步将WAL文件直接落盘为Block文件的方案,使得重启后立即能够提供服务。

  每个Block里需要通过索引文件对数据进行索引。因此在设计索引文件时,充分考虑了冗余性和查询性能:

  所有的字符串包括TagKey, TagValue, MetricName, MeasurementName进行统一编号,在索引文件其他地方用编号进行标识,减少字符串重复出现导致的数据冗余。Time Series也用一张表(逻辑上的表概念)进行编号,在数据索引的地方用编号进行标识,减少数据冗余并提升数据定位速度。为了提升按Tag进行查询的速度,设定倒排索引表,通过TagKey+TagValue反向定位到Time Series合集。索引文件是查询速度的关键,因此最近时间段(如一周)的索引文件全部缓存在内存里,提升查询的速度。

  压缩算法参考了Facebook论文--高性能内存时序数据库Gorilla里重点描述的时序数据压缩算法:

  timestamp:和上一个数据点进行差值后再进行的差值计算,秒级数据大多数时候压缩之后都是0值;value:和上一个数据点进行XOR对比压缩;

  该压缩算法压缩比很高,但不支持历史数据乱序插入,并且某些场景查询性能不是很理想:查询小范围时间数据时也需要将整个chunk读取后解压缩。因此我们重新设计了压缩算法,如下图所示,做了如下改进:

  OPPO云可观测服务基础组件TSDB技术实践

  压缩以chunk为单位,timestamp和chunk第一个数据点做差值计算,value和chunk第一个数据点做XOR计算。chunk大小设置为255个数据点,这样timestamp差值在1个字节以内。

  通过改进,可以支持历史数据的乱序写入,并在小范围时间查询时性能优势明显。

  因为网络等原因最近几分钟内的数据乱序到达TSHouse,为此我们专门开发了实时数据乱序插入功能。如下图所示:

  OPPO云可观测服务基础组件TSDB技术实践

  在XORChunk(数据压缩)之前增加一个RingChunk,保存最近10分钟未压缩的数据。RingChunk采用Ring buffer机制,buffer环里一共600秒/5=120个槽位,每个槽位保存5秒数据,最多放5个sample。一个指针指向Start位置(即将写入XORChunk),并对应start time时间戳。sample根据start time-timestamp计算后插入对应位置,以此来支持10分钟内乱序数据到达时随时插入。RingChunk数据不压缩,随着Start time/ End time的循环,将过期数据写入XORChunk。

  TSHouse经过了严格的性能测试,以确保其在大规模海量数据的性能和稳定性。

  下图所示为我们在物理机上测试的写入性能,在6个tags时序数据场景下可以达到最高400w/s数据点写入:

  OPPO云可观测服务基础组件TSDB技术实践

  相同硬件下,我们也对比测试并调优(如batch写入)了InfluxDB,达到150w/s以上,并会出现写入失败,而且CPU没有跑满,InfluxDB没有达到硬件的极限能力。

  下图所示为6个tag场景下,数据发送量(每秒50万~400万)下TSHouse和InfluxDB实际写入量和CPU使用率对比:

  OPPO云可观测服务基础组件TSDB技术实践

  OPPO云可观测服务基础组件TSDB技术实践

  下图所示为10个tag场景下,本科证书数据发送量(每秒50万~400万)下TSHouse和InfluxDB实际写入量和CPU使用率对比:

  OPPO云可观测服务基础组件TSDB技术实践

  OPPO云可观测服务基础组件TSDB技术实践

  可以看到,同等硬件和测试条件下,TSHouse写入指标性能是InfluxDB的3.5倍。

  下图所示为 点查询 (指定某一个时间序列最新时刻数据进行查询)对比测试数据:

  OPPO云可观测服务基础组件TSDB技术实践

  查询延迟这块TSHouse的性能是InfluxDB的2倍左右。并且TSHouse更加稳定,查询延时几乎无抖动,tp99仅为3.62ms,而InfluxDB的tp99高达21.09ms。

  下图所示为 范围查询 :

  OPPO云可观测服务基础组件TSDB技术实践

  从测试数据可以看到TSHouse的查询性能是InfluxDB的6倍左右,并随着查询数据量的增大,TSHouse性能越优秀。

  TSHouse作为OPPO云推出的时序数据库产品,不仅承载了OPPO云全量负载数据、调用链、负载均衡、业务TP等全链路全覆盖的监控存储,而且承接了IoT、安全等多个团队的时序数据需求。TSHouse配合OPPO云自研的LogHouse产品,共同构成了OPPO云的可观测能力。

  目前TSHouse线上写入QPS已超数千万(/s)并随着业务接入速度增长。未来我们继续完善TSHouse功能,并持续进行性能优化,在合适的时机进行开源,回馈社区。

  1. InfluxDB TSM存储引擎:

  docs.influxdata/influxdb/v1.7/concepts/storage_engine/

  2. Prometheus 2.0存储引擎设计:

  fabxc/tsdb/

  3. PromQL HTTP接口:

  prometheus/docs/prometheus/2.6/querying/api/

  4. xxHash:

  cyan4973.github/xxHash/

  5. Protobuf和JSON性能对比测试:

  52imthread-772-1-1.html

  本文来自微信公众号:OPPO互联网技术

    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多