1. 时序数据库简介
时间序列数据最简单的定义就是数据格式里包含timestamp字段的数据。比如股票市场的价格,环境中的温度,主机的CPU使用率等。几乎所有的数据都可以打上一个timestamp字段。时间序列数据更重要的一个属性是如何去查询它。在查询的时候,对于时间序列我们总是会带上一个时间范围去过滤数据。同时查询的结果里也总是会包含timestamp字段。
1.1 时序数据库技术选型
1.1.1 基于关系型数据库
几乎任意数据库都可以存时间序列数据。但是不同的数据能支持的查询类型并不相同。按照能支持的查询类型,我们可以把时间序列数据库分为两类,第一类的数据库按照关系型数据库的说法,其表结构是这样的:
[metric_name] [timestamp] [value]
其优化的查询方式是:
SELECT value FROM metric WHERE metric_name=”A” AND timestamp >= B AND timestamp < C
也就说这类数据库是什么样子的数据存进去,就什么样子取出来。
在这种模式下,首先要知道需要的图表是什么样子的。然后按照这个图表的数据,去把数据入库。查询的字段,就是数据库存储的字段。然后再按照数据库存储的字段,去从原始数据里采集上报。存储什么字段,就上报什么字段。这种模式很容易优化,可以做到非常快。但是这种模式有两个弊端。
- 无法快速响应变化:如果需要的图表有变更,需要从上报的源头重新来一遍。而且要等新数据过来之后,才能查看这些新数据;
- 存储膨胀:总有一些数据是需要从不同维度查询的要求。比如广告点击流数据,需要按省份聚合,按运营商聚合,按点击人的喜好聚合等。这些维度的交叉组合会产生非常巨大的组合数量,要预先把所有的维度组合都变成数据库里的表存储起来会很浪费空间;
这类时间序列数据库最多,使用也最广泛。一般人们谈论时间序列数据库的时候指代的就是这一类存储。按照底层技术不同可以划分为三类:
- 直接基于文件的简单存储:RRD Tool,Graphite Whisper。这类工具附属于监控告警工具,底层没有一个正规的数据库引擎。只是简单的有一个二进制的文件结构;
- 基于K/V数据库构建:opentsdb(基于hbase),blueflood,kairosDB(基于cassandra),influxdb,prometheus(基于leveldb);
- 基于关系型数据库构建:mysql,postgresql 都可以用来保存时间序列数据;
1.1.2 另一种选择
另外一类数据库其表结构是:
[timestamp] [d1] [d2] .. [dn] [v1] [v2] .. [vn]
其优化的查询方式不限于查询原始数据,而是可以组合查询条件并且做聚合计算,比如:
SELECT d2, sum(v1) / sum(v2) FROM metric WHERE d1 =
“A” AND timestamp >= B AND timestamp < C GROUP BY d2
我们希望时间序列数据库不仅仅可以提供原始数据的查询,而且要支持对原始数据的聚合能力。这种聚合可以是在入库阶段完成的,所谓物化视图。也可以是在查询阶段完成,所谓实时聚合。根据实际情况,可以在这两种方式中进行取舍。
想要在在查询阶段做数据的聚合和转换,需要能够支持以下三点:
- 检索:这是搜索引擎最擅长的领域。代表产品是Lucene。其核心技术是基于高效率数据结构和算法的倒排索引;
- 加载:这是分析型数据库最擅长的领域。代表产品是C-store和Monetdb。其核心技术是按列组织的磁盘存储结构;
- 分布式计算:这是大数据计算引擎最擅长的领域。代表产品是Hadoop和spark。其核心技术是sharding 和 map/reduce等等;
如果要实时从十亿条里取百万记录出来,再做聚合运算,对于opentsdb这样的时序数据库可能就勉为其难了。满足海量数据实时聚合要求的数据库不多,比较常见的有这么几种:
- 基于Lucene构建的“搜索引擎”:Elasticsearch, Crate.io(虽然是基于Elasticsearch,但是聚合逻辑是自己实现的),Solr;
- 列式存储数据库:Vertica(C-store的后裔)Actian(Monetdb的后裔)等;
1.2 Elasticsearch在时序数据库场景下的技术特点
Elasticsearch是市面上能够在检索、加载和分布式计算三个方面都做得一流的数据库。而且是开源并且免费的。它使用了很多技术来达到飞一般的速度。这些主要的优化措施可以列举如下:
- Lucene的inverted index可以比mysql的b-tree检索更快;
- 在 Mysql中给两个字段独立建立的索引无法联合起来使用,必须对联合查询的场景建立复合索引。而lucene可以任何AND或者OR组合使用索引进行检索;
- Elasticsearch支持nested document,可以把一批数据点嵌套存储为一个document block,减少需要索引的文档数;
- Opentsdb不支持二级索引,只有一个基于hbase rowkey的主索引,可以按行的排序顺序scan。这使得Opentsdb的tag实现从检索效率上来说很慢;
- Mysql 如果经过索引过滤之后仍然要加载很多行的话,出于效率考虑query planner经常会选择进行全表扫描。所以Mysql的存储时间序列的最佳实践是不使用二级索引,只使用clustered index扫描主表。类似于Opentsdb;
- Lucene 从 4.0 开始支持 DocValues,极大降低了内存的占用,减少了磁盘上的尺寸并且提高了加载数据到内存计算的吞吐能力;
- Lucene支持分segment,Elasticsearch支持分index。Elasticsearch可以把分开的数据当成一张表来查询和聚合。相比之下Mysql如果自己做分库分表的时候,联合查询不方便;
- Elasticsearch 从1.0开始支持aggregation,基本上有了普通SQL的聚合能力。从 2.0 开始支持 pipeline aggregation,可以支持类似SQL sub query的嵌套聚合的能力。这种聚合能力相比Crate.io,Solr等同门师兄弟要强大得多;
2. 基于ElasticSearch构建数据数据模型
用数据举例:
CPU host=1.1.1.1,region=r1 usage=90,system=3 1499255387
Metric:CPU
Tags:host=1.1.1.1,region=r1
Fields:usage=90,system=3
Time:1499255387
术语 | 说明 | 关系型数据库对照 |
---|---|---|
Metric | 业务关注的一份数据集合 | Table |
Tags | 维度列,可指定条件搜索 | 具有索引的Column |
Time | 时间列,一个特殊的维度 | 具有索引的Column |
Fileds | 指标列,数值随时间变化 | 不具有索引的Column |
时序数据的数据量一般都很庞大,即使是使用Elasticsearch,每个Metric使用一个索引也会有性能问题。Elasticsearch的开发人员在设计之初就想到了这个问题:Elasticsearch可以根据规则将一个大索引拆分成若干个小索引(类似于MySQL分表),然后通过在每个索引上设置同样的别名,将索引数据在逻辑上聚合。
如CPU Metric可以按时间拆分索引:
Elasticsearch数据写入方式例子如下(kibana):
POST /cpu/_bulk
{"index":{}}
{"region":"gz","host":"10.12.13.14","time":1499255387,"usage":90,"system":3}
{"index":{}}
{"region":"sh","host":"14.12.13.10","time":1499255387,"usage":50,"system":1}
2.1 权限系统
Elasticsearch 6.8版本,xpack开源索引级别的权限系统,对索引进行精确的权限控制,可实现业务读写分离等日常需求。
索引层面,权限划分为:
- manager;
- monitor;
- read;
- index;
- create;
- delete;
- write;
- delete_index;
- create_index;
- view_index_metadata;
- read_cross_cluster;
- manage_follw_index;
- manage_ilm;
- manage_leader_index;
同时,也有ES Stack各个组件的权限控制,如kibana、logstash等,这里不再赘述。
2.2 数据处理
存储在Elasticsearch的数据,是未经加工的原始数据,数据量巨大,查询困难。为了解决该问题,可以在原始数据基础上,进行预聚合处理。通过离线服务,降低时间维度精度,保留粗粒度历史数据。收益是可加快时间跨度的查询性能、降低历史数据存储成本。
同时,可按照索引规则,设置保留策略,数据超出过期时间后自动清理。如,索引规则是index-yyyy.MM.DD,数据保留策略是7天。那么清理任务会在每天0点根据数据策略检查索引是否存在7天前的索引,如果存在,则根据测录决定是删除还是分配到冷数据存储的服务器上。
2. 几种数据存储对比
ES | InfluxData | Prometheus | OpenTSDB | |
---|---|---|---|---|
数据模型 | labels | labels | labels | labels |
写入性能 | ***** | ***** | *** | |
压缩编码 | **** | ***** | ***** | |
读取性能 | ***** | **** | **** | |
数据生命周期管理 | √ | √ | √ | 手动 |
集群化支持 | √ | √商业版 | 单机 | √ |
降精度 | √ | √商业版 | × | × |
权限管理 | √ | √商业版 | × | × |
外部依赖 | 无 | 无 | 无 | Hadoop & Hbase |
接口 | Rest(SQL付费) | 类SQL | Rest | Rest |
社区生态 | ***** | *** | ** | ** |
聚合分析 | 强 | 弱 | 弱 | 弱 |
延伸应用 | 日志、全文检索等 | × | × | × |