InfluxDB从入门到放弃
2019-08-17 Programming来墨刀实习接到的第一个任务,是用InfluxDB做一些用户操作的统计,跟之前的笔试题也算是前后照应了。
自己在 InfluxDB 上面花了将近两周的时间,最终却发现其并不能满足我们的需要。浪费的时间有点长,一方面是因为自己第一次接触时序数据库,基本算是从零开始学习 InfluxDB;但另一方面,更主要的原因则是自己分析问题的能力还需要提升,要学会更加全面地思考问题。
这里就对自己近两周 InfluxDB 的学习做一个简单的总结。
学习资料
刚开始时想在当当或者京东上找找相关的书籍,结果以“influxdb”为关键字根本搜不到东西,所以学习资料就只能从网上找了。而网上关于 InfluxDB 的资料也不多,搜到的大部分相关内容都很浅,因此主要的学习资料就只剩下了官方提供的文档。
InfluxDB 当前的稳定版本是1.7,新版的2.0还处于 alpha 测试中,官方并不推荐使用,这里就列举出1.7版本的官方文档中一些我觉得比较有用的内容:
- 常见术语含义:InfluxDB key concepts
- 所有术语含义:InfluxDB glossary
常见术语含义
中通过一个例子解释了最基础的tag,field,series等术语在数据库中对应的具体内容,刚接触 InfluxDB 时适合从这里入手;全部术语含义
则涉及到更多内容,可以用来检查自己哪一块相关知识还不了解,查漏补缺。
- 降低采样和数据保留:Downsampling and data retention
- 连续查询:InfluxQL Continuous Queries
- 保留策略:Retention policy management
上面的降低采样和数据保留
对应着下面的连续查询
和保留策略
。连续查询
通过设置定时执行的查询语句,将一段时间内的多个样本点聚合成一个,达到压缩数据、加快查询的效果;保留策略
通过设置保留多长时间内的数据,自动删除旧数据,防止硬盘空间占用过大。两者通常搭配使用:连续查询
将原始数据压缩,存到另一表里,保留策略
负责定时删除旧的原始数据。
所有的函数主要分为聚合、选择、转换、分析等几大类,其中常用的有计算个数,求平均值,求和,找最大或最小的数据,找最新或最旧的数据,计算前缀和,计算相邻两次数据变化值或变化率,使用 Holt-Winters 算法进行简单的预测等,更专业的还有计算钱德动量摆动指标,计算移动平均,计算考夫曼效率比等,连续查询
中经常会用到这里的函数。
因为 InfluxDB 的数据库格式相对于一般的关系型数据库更加固定,所以它的数据库设计起来比较简单,设计数据库的时候就主要参考这里的设计原则
。
不要以为它只是个硬件推荐
,里面其实藏着干货,例如不同配置的机器所能承担的数据量,InfluxDB 所能承担的最大数据规模。
知识点
field
不会被索引,tag
会被索引,所以查询时where
或者group by
从句中以tag
为过滤条件查询速度会更快。field
的类型可以是字符串,浮点,整型,布尔值,tag
的类型只能是字符串。- 提供的内建函数基本都是用于
field
的,大部分都不能用于tag
和timestamp
。 database names
,measurements
,tag keys
,field keys
,和tag values
只会存储一次,而field values
和timestamps
每一个数据点都会存储一次。- 生成测试数据时将一批数据合并成一个
batch
,再一次性写入数据库,会比一条一条写入快得多。单个batch
官方推荐包含5000-10000条数据。 influxdb
设计的是运行在固态硬盘上,没有测试过在机械硬盘或者网络存储设备上的表现,因此对硬盘的IO要求比较高。- 更大的内存有助于提升查询速度,对内存的需要主要来自于
series cardinality
,当series cardinality
达到千万级别时,即使是large amounts of RAM
也会出现OOM,此时只能重新设计数据库结构。 influxdb
将tag
和time
作为索引,若插入多条tag
和time
完全相同的数据,则只会保留最后一次插入的field
。
坑点
- 配置文件中有
max-series-per-database
和max-values-per-tag
的限制,是为了防止数据量太大影响到数据库性能而设定的值。自己测试时遇到该限制可以去配置文件里改掉,但此时就该考虑 InfluxDB 是否能满足自己的需要了。 - 官方文档
硬件推荐
部分的原文:The major component that affects your RAM needs is series cardinality. A series cardinality around or above 10 million can cause OOM failures even with large amounts of RAM. If this is the case, you can usually address the problem by redesigning your schema.
这正是我们最终选择放弃的原因。得知了半年内的实际活跃用户量后,我预估了一下数据规模,根据InfluxDB glossary: series cardinality的规则计算series数量后,发现多个tag的设计很容易就会超出千万series的限制,除非只保留单tag。设置为单tag后重新生成测试数据并执行查询,发现查询速度过慢,满足不了线上环境的要求。因此 InfluxDB 并不适用于我们当前的场景,只能寻找其它解决办法。
语句
- 交互模式下查询
testdb
数据库的series
数量:
select * from _internal.."database" where "database"='testdb' order by time desc limit 1;
- 命令行中查询单个
measurement
的series
数量:
influx -database 'testdb' -execute 'show series from testmeasurement' -format 'csv' | wc -l
- 交互模式下分析并执行语句,获取实际执行时间:
explain analyze select count(*) from testmeasurement;
收获
- 回顾整个过程,自己从一开始是没有考虑 InfluxDB 能否承载当前数据规模的,只是在考虑功能的具体实现细节。自己生成的测试数据规模太小,也一直没有遇到内存瓶颈,结果就是到了最后,功能设计好了,却发现因为 InfluxDB 本身的限制而无法投入使用。
数据库最关键的就是性能,所以我应该在开始时就先向前辈请教一下线上环境的实际数据量,确保数据库承载这么多数据没问题之后再去考虑具体的实现细节,反映了自己还是缺少实践经验。 - 中间自己设计的一套统计方案用到了计算某字段前缀和的方法,但和其它同事交流时才意识到还要考虑各种异常情况,例如用户由于网络问题少提交了事件,或者服务器由于崩溃丢失了一部分数据,这样之后的所有前缀和都会产生偏移,且难以得到纠正,这里则反映出了自己思考问题还不够全面。
注
- 文中基本没有提到关于 InfluxDB 的基础知识,基础知识官方文档中讲的就很清楚,没必要在这里再重复一遍,这里主要是记录一些关键点。
- 因为是直接阅读的官方文档,没有权威的中文文档进行对照,所以文中的一些翻译可能不够准确,推荐根据相关链接阅读官方文档。
- 后续又尝试了基于 PostgreSQL 的 TimescaleDB,根据业务需求预估了半年的数据量,单表三千万的规模下首次查询在 50ms 内,最终就选择了 TimescaleDB。