本文首发于泊浮目标简书:https://www.jianshu.com/u/204...
版本 | 日期 | 备注 |
---|---|---|
1.0 | 2021.10.19 | 文章首发 |
0. 背景
题目来源于InfluxDB对于它们的存储引擎诞生的背景介绍:
The workload of time series data is quite different from normal database workloads. There are a number of factors that conspire to make it very difficult to get it to scale and perform well:- Billions of individual data points- High write throughput- High read throughput- Large deletes to free up disk space- Mostly an insert/append workload, very few updatesThe first and most obvious problem is one of scale. In DevOps, for instance, you can collect hundreds of millions or billions of unique data points every day.To prove out the numbers, let’s say we have 200 VMs or servers running, with each server collecting an average of 100 measurements every 10 seconds. Given there are 86,400 seconds in a day, a single measurement will generate 8,640 points in a day, per server. That gives us a total of 200 * 100 * 8,640 = 172,800,000 individual data points per day. We find similar or larger numbers in sensor data use cases.
最近负责了产品中一部分的监控事宜。我想到时序数据库的对于RT和IOPS的要求应该很高,因而想看看它外部是怎么实现的——会不会和我意识的Kafka、HBase很像。
先简略做一下科普。时序数据库是用于存储追随工夫而变动的数据,并且以工夫(工夫点或者工夫区间)来建设索引的数据库。 那么它最早是利用于工业(电力行业、化工行业)利用的各类型实时监测、查看与剖析设施所采集、产生的数据,这些工业数据的典型特点是产生频率快(每一个监测点一秒钟内可产生多条数据)、重大依赖于采集工夫(每一条数据均要求对应惟一的工夫)、测点多信息量大(惯例的实时监测零碎均可达到成千上万的监测点,监测点每秒钟都在产生数据)。 其数据是历史烙印,它具备不变性、唯一性、有序性。时序数据库同时具备数据结构简略、数据量大的特点。
1.问题
用过时序数据库的同学都晓得。时序数据库的数据通常只是追加,很少删改或者基本不容许删改,查问的场景个别也是有连续性的。比方:
- 咱们通常会在监控页面上依据察看某个工夫端的数据。在须要时,会寻找其中更细的时间段来察看。
- 时序数据库会将告警零碎关怀的指标推送过来
1.1 Prometheus踩过的坑
在这里,咱们先简略温习一下Prometheus中的数据结构。其为典型的k-v对,k(个别叫Series)由MetricName
,Lables
,TimeStamp
组成,v则是值。
在晚期的设计中,雷同的Series会依照肯定的规定组织起来,同时也会依据工夫去组织文件。于是就变成了一个矩阵:
长处是写能够并行写,读也能够并行读(无论是依据条件还是时间段)。但毛病也很显著:首先是查问会变成一个矩阵,这样的设计容易触发随机读写,这无论在HDD(限度于转速)还是SSD(写放大)上都很好受。
于是Prometheus又改良了一版存储。每一个Series一个文件,每个Series的数据在内存里存满1KB往下刷一次。
这样缓解了随机读写的问题,但也带来新的问题:
- 在数据没达到1KB还在内存里时,如果机器carsh了,那么数据则失落
- Series很容易变成特地多,这会导致内存占用居高不下
- 持续下面的,当这些数据一口气被刷下去时,磁盘会变得很忙碌
- 继上,很多文件会被关上,FD会被耗费完
- 当利用很久没上传数据时,内存里的数据该刷不该刷?其实是没法很好的断定的
1.2 InfluxDB踩过的坑
1.2.1 基于LSM Tree的LevelDB
LSM Tree的写性能比读性能好的多。不过InfluxDB提供了删除的API,一旦删除产生时,就很麻烦——它会插入一个墓碑记录,并期待一个查问,查问将后果集和墓碑合并,稍后合并程序则会运行,将底层数据删除。并且InfluxDB提供了TTL,这意味着数据删起来是Range删除的。
为了防止这种较慢的删除,InfluxDB采纳了分片设计。将不同的时间段切成不同的LevelDB,删除时只需敞开数据库并删文件就好了。不过当数据量很大的时候,会造成文件句柄过多的问题。
1.2.2 基于mmap B+Tree的BoltDB
BoltDB基于单个文件作为数据存储,基于mmap的B+Tree在运行时的性能也并不差。但当写入数据大起来后,事件变得麻烦了起来——如何缓解一次写入数十万个Serires带来的问题?
为了缓解这个问题,InfluxDB引入了WAL,这样能够无效缓解随机写入带来的问题。将多个相邻的写入缓冲,而后一起fresh上来,就像MySQL的BufferPool。不过这并没有解决写入吞吐量降落的问题,这个办法仅仅是迁延了这个问题的呈现。
2. 解决方案
细细想来,时序数据库的数据热点只集中在近期数据。而且多写少读、简直不删改、数据只程序追加。因而,对于时序数据库咱们则能够做出很激进的存储、拜访和保留策略(Retention Policies)。
2.1 要害数据结构
- 参考日志构造的合并树(Log Structured Merge Tree,LSM-Tree)的变种实现代替传统关系型数据库中的B+Tree作为存储构造,LSM 适宜的利用场景就是写多读少(将随机写变成程序写),且简直不删改的数据。个别实现以工夫作为key。在InfluxDB中,该构造被称为Time Structured Merge Tree。
- 时序数据库中甚至还有一种并不常见却更加极其的模式,叫做轮替型数据库(Round Robin Database,RRD),它是以环形缓冲的思路实现,只能存储固定数量的最新数据,超期或超过容量的数据就会被轮替笼罩,因而它也有着固定的数据库容量,却能承受无限量的数据输出。
2.2 要害策略
- WAL(Write ahead log,预写日志):和诸多数据密集型利用一样,WAL能够保证数据的长久化,并且缓解随机写的产生。在时序数据库中,它会被当作一个查问数据的载体——当申请产生时,存储引擎会将来自WAL和落盘的数据做合并。另外,它还会做基于Snappy的压缩,这是个耗时较小的压缩算法。
- 设置激进的数据保留策略,比方依据过期工夫(TTL),主动删除相干数据以节俭存储空间,同时进步查问性能。对于一般的数据库来说,数据会存储一段时间后被主动删除的这个做法,能够说是不可设想的。
- 对数据进行再采样(Resampling)以节俭空间,比方最近几天的数据可能须要准确到秒,而查问一个月前的冷数据只须要准确到天,查问一年前的数据只有准确到周就够了,这样将数据从新采样汇总,能够节俭很多存储空间。
3.小结
总体看下来,相比Kafka、HBase来说,时序数据库的内部结构并不简略,十分有学习价值。
3.1 参考链接
- https://prometheus.io/docs/pr...
- https://docs.influxdata.com/i...
- https://blog.csdn.net/cymm_li...
- https://zhuanlan.zhihu.com/p/...
- https://archive.docs.influxda...
- 周志明:《凤凰架构》