背景

InfluxDB是db-engines排名第一的时序数据库,目前在ApsaraDB团队中有着广泛应用。本文旨在分享在使用InfluxDB过程中进行的一些调优措施及运维过程中的问题,主要涵盖配置调优和问题排查技巧两个方面。

配置调优

对InfluxDB的配置优化,主要通过调整一些配置参数来提升其性能。

性能优化

InfluxDB的存储引擎是TSM Tree,其整体思想与LSM Tree类似,并在时序数据存储结构上进行了特定的优化。需要增大cache-snapshot-memory-size的值。

[data]
  # CacheSnapshotMemorySize 是缓存达到指定大小时,快照缓存并写入TSM文件,从而释放内存的大小。
  cache-snapshot-memory-size = 562144000

cache-snapshot-memory-size值控制LSM中缓存的大小,当缓存达到阈值后,会写入到磁盘生成TSM文件,文件初始为Level 0,两个相同Level的TSM文件会合并生成一个更高级别的TSM文件,即两个Level 0的TSM文件会生成一个Level 1的TSM文件,这种设计导致了TSM Tree的写入放大问题。

由于InfluxDB固定两个低级别文件合并成一个高级别TSM文件,所以如果缓存越小,生成TSM文件的频率越高,合并频率也越高,写入放大越显著。在高写入频率场景下,InfluxDB的吞吐量会显著下降。

当合并频率增加时,写入放大的一个重要原因是TSM文件数据经过编码压缩,占用磁盘空间。在合并时需要解码数据,会带来显著的性能损耗。

为优化此问题,InfluxDB在合并时分为优化合并(optimize compact)和完全合并(full compact)两种类型。在完全合并场景下,首先会对TSM文件中的块进行解码,然后根据每个块存储的点数量,将解码后的点值按时间顺序重新编码成块,写入新的TSM文件,这一过程的性能损耗非常显著。而在优化合并场景下,不会读取块内部数据,而是对多个块进行拼接,减少性能消耗。

目前,在部分场景下InfluxDB仍会选择完全合并。虽然优化合并可以提升合并速度和减少资源消耗,但会引起查询放大问题,需要从多个块中才能获取所需数据。

说明

理论上,cache-snapshot-memory-size值越大越好,但需关注硬件配置。

cache-snapshot-memory-size值与当前并发写入标签数量相关,如果标签数量较多,一定要增大此值;如果标签数量不多,但少数标签的数据写入频率高,此值稍低也不会对性能有太大影响。

超时设置

此问题主要在InfluxDB的老版本(低于1.5版本)存在,并且有一定风险。InfluxDB在控制内存使用量上的设计较为粗糙。建议生产环境不要随意执行SQL,一旦SQL导致内存使用过多,容易导致InfluxDB OOM。此外,在当前倒排索引的设计中,InfluxDB OOM后重新启动速度很慢,因为启动过程中需要重新遍历TSM文件生成内存中的倒排索引,加上数据均进行了编码,在数据量较大的情况下,启动速度非常慢。因此建议打开上述读取数量开关,因为默认情况下不会发生如此大请求。如果有这种特殊SQL存在,请酌情考虑。

[coordinator]
  # 查询允许执行的最大时间,超过此时间系统将终止查询。此设置可防止运行时间过长的查询。将值设为0可禁用此限制。
  query-timeout = "120s"

  # SELECT语句允许处理的最大点数,设置为0将使最大点数无限制。每10秒检查一次,因此不会立即中止查询。
  max-select-point = 1000000

  # SELECT语句允许运行的最大序列数,设置为0将使最大序列数无限制。
  max-select-series = 1000000

[http]
  # 默认结果集的分块大小。
  max-row-limit = 1000000

InfluxDB对内存使用量的控制主要体现在几个方面:

  1. 返回结果集很大时,数据会缓存于内存中,计算完成后统一返回给客户端。InfluxDB内部算子通过流水线方式流式交互,但返回给客户端时需要客户端调用时传递"chunked"参数才能实现流水线方式返回。因此建议打开max-select-pointquery-timeoutmax-row-limit以防止误操作查询。1.6版本后据称有了杀死进程功能,可以及时终止,这部分未具体调研,不做介绍。

  2. 如果SQL没有对标签进行过滤条件,每条SQL都会在内存中拷贝一份全量的序列。因此SQL查询的过滤条件需明确定义。

正常的时序使用场景下,InfluxDB的OOM问题不会发生,但一不小心仍可能陷入“坑”中。

数据层面

max-series-per-database可调整为0,如注释所示:该参数控制每个数据库的最大序列数量。

max-values-per-tag可调整为0,如注释所示:该参数控制每个标签的标签值数量。

[data]
  # 每个数据库允许的最大序列数,超过此限制将丢弃写入。此限制可防止数据库层面的高基数问题。将值设为0可禁用此限制。
  max-series-per-database = 0

  # 每个标签允许的最大标签值数,超过此限制将丢弃写入。此限制可防止高基数标签值写入到度量。将值设为0可禁用此限制。
  max-values-per-tag = 0

InfluxDB这两个参数需要控制的根源来自于内部设计中的倒排索引实现,如果InfluxDB使用方数据结构设计不合理,会导致内存过大。因此建议使用方不要将这两个参数调整为0,而是估计一个合理的序列数量。

安全层面

如果在线上环境使用,reporting-disabled需配置上,不仅提升系统安全性,同时有助于风控。

# 每24小时,InfluxDB将向usage.influxdata.com报告使用数据。数据包括随机ID、操作系统、架构、版本、序列数等使用数据。用户数据库中的数据不会被传输。将此选项设为true以禁用报告。
reporting-disabled = true