InfluxDB存储引擎
InfluxDB存储引擎保证以下几点
- 数据安全写入磁盘
- 查询数据返回的结果正确且完整
- 数据准确性优先其次才是性能
存储引擎从收到API写请求开始处理数据,直到将数据写到物理磁盘。数据被写入InfluxDB,使用通过HTTP POST请求发送到/api/v2/write端点或/write 1.x兼容端点的line protocol。成批的point被发送到InfluxDB,经过压缩,并写入WAL,以达到即时的持久化。points也被写入一个内存缓存,并立即成为可查询的。内存缓存以TSM文件的形式定期写入磁盘。随着TSM文件的积累,存储引擎将其合并并压缩成更高级别的TSM文件。
虽然point可以单独发送,但为了提高效率,大多数应用都是分批发送point。一个POST主体中的point可以来自任意数量的series, measurements和tag sets。一批中的point不一定是来自同一个measurements或tag sets。
Write Ahead Log (WAL)
当存储引擎重启时, WAL会保留InfluxDB的数据; WAL确保数据在发生意外故障时是持久的
当存储引擎收到一个写入请求时, 会执行下列步骤:
- 写请求被追加到WAL文件末尾
- 使用*fsync()*将数据写入磁盘
- 内存缓存被更新
- 当数据成功写入磁盘后, 返回写入成功的响应
fsync()接收文件并将待处理的写操作全部推到磁盘上; 作为系统调用fsync()会触发内核上下文切换, 计算成本很高, 但保证数据在磁盘上是安全的;
当存储引擎重启时, WAL文件被读回内存数据库中, 然后influxDB响应对/read接口的请求
Cache
cache是当前存储在WAL中的point的内存拷贝; WAL和cache是独立存在的实体, 两者之间没有交互; 存储引擎会协调两者的写入
cache特点
- 按measurement, tag set, unique field来组织point, 每个field都存储在它自己的时序范围内
- 存储未压缩的数据
- 每次存储引擎重启时, 从WAL获取更新; 缓存在运行时被查询并与存储在TSM文件中的数据合并
- 缓存的最大值由maxSize(字节)配置控制
缓存快照是目前正在写入TSM文件的缓存对象; (缓存->缓存快照->TSM)
缓存快照在刷新时被保留在内存中所以可以和高速缓存一起被查询;
对存储引擎的查询将缓存中的数据与TSM文件中的数据合并, 在查询处理时, 查询是在缓存中的数据副本上执行的, 这样当查询运行时写入的数据就不会影响结果;
发送到高速缓存的删除信息会清除指定的键或指定键的时间范围
疑问1: 缓存数据为什么要与TSM数据合并之后再返回结果?
疑问2: 查询时缓存副本多久会被更新?
Time-Structured Merge Tree (TSM)
TSM数据模型为列式存储, 数据拆分如下图所示:
带有tags时如下所示:
为了有效地压缩和存储数据,存储引擎按series key,对字段值进行分组,然后按时间排列这些字段值。(一个series key由measurement, tag key, value, field key定义)。
存储引擎使用时间结构化合并树(TSM)数据格式。TSM文件以柱状格式存储压缩的series数据。为了提高效率,存储引擎只存储series中数值之间的差异(或三角)。面向列的存储让引擎按series key读取并省略不相干的数据。
在字段被安全地存储在TSM文件中后,WAL被清空,缓存被清除。压缩进程创建了读取优化的TSM文件。TSM压缩代码是相当复杂的。然而,高层次的目标是相当简单的:将series的值组织在一起,能够持久运行,以最好地优化压缩和扫描查询。
Time Series Index (TSI)
随着数据基数不断增长(series数量), 请求大量的series key会变得越来越慢; TSI能够保证在数据增长的情况下快速查询;
TSI存储了按measurement, tag, field分组的series key, 这使得数据库可以很好的回答下列两个问题: 1.存在哪些measurement, tag, field(发生在元查询中)?;2.给定的measurement, tag, field存在哪些series key?