前言
Influxdb是一个基于golang编写,没有额外依赖的开源时序数据库,用于记录metrics、events,进行数据分析。这篇文章谈论的influxdb版本在1.2.0以上。这篇文章只谈论influxdb在监控中的数据存储应用,不会谈论influxdb提供的整套监控方案。本文主要谈论五个方面:时序数据库选型、influxdb基本概念、存储引擎、实践、数据聚合。
选型
Influxdb vs Prometheus
influxdb集成已有的概念,比如查询语法类似sql,引擎从LSM优化而来,学习成本相对低。
influxdb支持的类型有float,integers,strings,booleans,prometheus目前只支持float。
influxdb的时间精度是纳秒,prometheus的则是毫秒。
influxdb仅仅是个数据库,而prometheus提供的是整套监控解决方案,当然influxdb也提供了整套监控解决方案。
influxdb支持的math function比较少,prometheus相对来说更多,influxdb就目前使用上已经满足功能。
2015年prometheus还在开发阶段,相对来说influxdb更加稳定。
influxdb支持event log,prometheus不支持。
更详细的对比请参考:对比。
我们其实仅仅需要的是一个数据库,其他组件都是自己开发的,而且存储的数据类型不仅仅是数字,因此选择了influxdb。希望上面的比较对大家有帮助。
Influxdb基本概念
Database
数据库是个逻辑容器,包含了measurement、retention policies、continuous queries、time series data,类似于mysql的database。
Measurement
描述了相关数据的存储结构,类似于mysql的table,但是不需要创建,写入数据的时候自动创建。关于schema的设计建议参考:设计建议。
Line Protocol
Line Protocol定义了influxdb的数据写入格式,如下:
weather,location=us,server=host1 temperature=82 1465839830100400200
| -------------------- -------------- |
| | | |
| | | |
+-----------+--------+-+---------+-+---------+
|measurement_name|,tag_set| |field_set| |timestamp|
+-----------+--------+-+---------+-+---------+
Tag
上面的location和server就是tag key,us和host1是tag value,tag是可选的。不过写入数据时最好加上tag,因为它可以被索引。tag的类型只能是字符串。
Field
上面的temperature是field key,82是field value。field value会用于展示,value支持的类型有floats,integers,strings,booleans。
Timestamp
格式是:RFC3339 UTC。默认精确到纳秒,可选。
Series
measurement, tag set, retention policy相同的数据集合算做一个 series。理解这个概念至关重要,因为这些数据存储在内存中,如果series太多,会导致OOM。
Retention Policy
保留策略包括设置数据保存的时间以及在集群中的副本个数。默认配置是:RP是autogen,保留时间是永久,副本为1。这些配置在创建数据库时可以修改。
Continuous Query
CQ是预先配置好的一些查询命令,定期自动执行这些命令并将查询结果写入指定的measurement中,这个功能主要用于数据聚合。具体参考:CQ。
Shard
存储一定时间间隔的数据,每个目录对应一个shard,目录的名字就是shard id。每一个shard都有自己的cache、wal、tsm file以及compactor,目的就是通过时间来快速定位到要查询数据的相关资源,加速查询的过程,并且也让之后的批量删除数据的操作变得非常简单且高效。
存储引擎
概述
TSM Tree是在LSM Tree的基础上稍作修改优化而来。它主要包含四个部分:cache、wal、tsm file、compactor。
Cache
插入数据时,先往cache中写入再写入wal中,可以认为cache是wal文件中的数据在内存中的缓存。
WAL
预写日志,对比mysql的binlog。其作用就是为了持久化数据,当系统崩溃后可以通过wal文件恢复cache。
TSM File
每个tsm文件的大小上限是2GB。当达到cache-snapshot-memory-size
,cache-max-memory-size
的限制时会触发将cache写入tsm文件。
Compactor
主要进行两种操作,一种是cache数据达到阀值后,进行快照,生成一个新的tsm文件。另外一种就是合并当前的tsm文件,将多个小的tsm文件合并成一个,减少文件的数量,并且进行一些数据删除操作。 这些操作都在后台自动完成。
目录结构
InfluxDB的数据存储有三个目录,分别是meta、wal、data。meta用于存储数据库的一些元数据,meta目录下有一个meta.db文件。wal目录存放预写日志文件,以.wal结尾。data目录存放实际存储的数据文件,以.tsm结尾。基本结构如下:
-- wal
-- test
-- autogen
-- 1
-- _00001.wal
-- 2
-- _00002.wal
-- data
-- test
-- autogen
-- 1
-- 000000001-000000001.tsm
-- 2
-- 000000001-000000010.tsm
-- meta
-- meta.db
其中 test是数据库名称,autogen是存储策略名称,再下一层目录中的以数字命名的目录是 shard 的 ID 值,比如 autogen存储策略下有两个 shard,ID 分别为 1 和 2,shard存储了某一个时间段范围内的数据。再下一级的目录则为具体的文件,分别是 .wal
和 .tsm
结尾的文件。
更详细的参考
实践
项目介绍
gateway用于检测和压缩influxdb的数据,用于跨机房传输,采用udp接受数据。
influxdb-relay是官方提供的高可用方案,但是它只提供简单的写入功能。
influxdb-proxy是用于替代influxdb-relay的高可用方案。
前期架构图
使用问题
influxdb-relay是官方提供的高可用方案,但是它只提供简单的写入功能。在初期使用时,并没有多大的问题,随着influxdb在公司的推广,接入方越来越多,意味着查询方越来越多,这就带来了以下问题:
grafana需要配置很多个数据源。
用户不能根据measurement来订阅数据。
数据库挂掉,就需要修改grafana的数据源。
维护困难,比如需要新增数据库,用户需要配置多个数据源,不能统一接入点。
用户查询直连数据库,用户
select *
数据库直接OOM,数据库会重启。relay提供的重写功能,数据是保留在内存中,一旦influxdb挂掉,就会导致relay机器内存疯涨。
踩过的坑
max-row-limit
不为0,会导致influxdb OOM。目前这个问题已经修复,但是grafana展示时会存在问题,配置时请设置为0。配置查询限制参数时,会导致一些奇怪的问题,官方是不限制,请保留默认配置。
没有制定schema规范,接入方把field写成tag了,导致内存疯涨,最后OOM。理解series的概念很重要。
写入超时时间默认是10s,有时候数据写入了但返回500。可以将这个时间设置成大点。
优化后的架构图
influxdb-proxy是为了解决上面的使用问题而开发出来的。具有以下功能:
同时支持写和查询功能,统一接入点,类似cluster。
支持重写功能,写入失败时写入文件,后端恢复时再写入。
限制部分查询命令和全部删除操作。
以measurement为粒度区分数据,支持按需订阅。
measurement优先精确匹配,然后前缀匹配。
提供数据统计,比如qps,耗时等等。
数据聚合
CQ
influxdb提供数据聚合的功能,就是上面基本概念里提到的Continuous Query。预先定义好cq,就可以定期根据不同的tag进行聚合数据。目前它有个设计问题:cq是顺序执行的,cq越多,数据延迟越高,一般延迟在几分钟内。如果需要更实时的聚合,cq不能满足,需要引入其他工具,比如spark。关于cq的语法请参考:语法。
Spark
经过内部调研,发现spark+kafka是个更好的聚合方案。spark支持流式处理且支持sql功能,我们只需要将cq改成sql就行。目前这个处于尝试阶段,已经上线部分功能。目前的处理流程如下:
总结
上文讲的整套架构已经支撑起饿了么2万台机器的监控,目前每秒写入的点数是300k。后端influxdb的机器数量是20台左右,维护成本基本趋于零。我们的焦点目前已经从influxdb转移到数据聚合和分析上。
有疑问加站长微信联系(非本文作者)