Cal Huang

  • 首页
  • About Me
Cal Huang
  1. 首页
  2. InfluxDB Internal
  3. 正文

InfluxDB 是如何工作的(1)用户故事及思路

2022年5月8日 889点热度 0人点赞 0条评论

前言:在云厂的工作中,总是会面对大量的时序数据。InfluxDB 是工作中最常用的时序数据库。时序数据与更为常用的关系数据的区别是什么,为什么 InfluxDB 可以高性能低存储空间消耗的存储海量时序数据。

​

一、用户故事

时序数据有什么特点?分析一个具体的需求:如何存储一个数据中心内所有服务器 CPU 分核心使用率?

就是需要表达:设备在某个时间的状态。

打开任务管理器,切换到性能 Tab,就可以看见自己设备的 CPU 使用率图。

任务管理器

只看其中 CPU 占用率的图,如果把它还原成表的形式:

IP地址 CPU核 时间 使用率
192.168.1.1 #0 5 1
192.168.1.1 #1 5 17
192.168.1.1 #0 6 3
192.168.1.1 #1 6 15

可以归类为:

  • IP地址、CPU核:共同表达了是哪一个设备,把这些统称为标签
  • 时间
  • 使用率:设备的状态,即值

这就是时序数据的基本数据模型。

对比常见的用户表:

用户名 密码 上次登陆时间
tsrs $2a$10$Tf9Qw0W8UOW2P…… 5
rsts $2a$10$EvLK4wtA4xSHYU…… 10

发现时序数据会有这些特点:

  • 一定会存在时间及值
  • 标签会经常重复,因为一个设备会持续的产生数据,同一个设备的标签是一致的。

数据操作的需求:

  • 增:批量增,所有的设备会间隔 1s 上报自己的 CPU 使用率
  • 删:区间删,删除 7 天之前的所有数
  • 改:不会改,不会出现「把 4 月份的CPU使用率改为 0」的情况
  • 查:时间区间+标签查,找出过去十分钟 192.168.1.1 CPU#0 核的使用率

对比用户系统:

  • 增:单条增,注册
  • 删:单条删,销户
  • 改:单条改,改密
  • 查:单条查,登录

然后是计算机本身的特点:

无论是HDD、SSD还是内存连续读写性能都远高于随机读写,这种差距甚至可以达到三个数量级,其中,内存的随机读写性能是最高的。如下图(注意对数坐标)

各存储操作对比

二、思路

假设现在重新设计一个时序数据库:

因为硬盘和内存的大小总是有限的,如果能尽量少的存储数据,就可以极大的降低成本。而且同一个数据源上报的数据的标签值总是一致的。在存储数据中心内所有服务器 CPU 分核心使用率这个场景中,数据中发生变化的只有时间和值。那么标签只需要存一次。

可以把拥有同样标签的数据称之为一个系列。

根据这个思路改造一下上面的表,拆分成两张:

方案一:

系列表:

编号 标签值
1 IP=192.168.1.1;CPU=#0
2 IP=192.168.1.1;CPU=#1

数据表:

系列编号 时间 使用率
1 5 1
2 5 17
1 6 3
2 6 15

因为查询请求总是类似 「找出过去十分钟 192.168.1.1 #0 CPU核的使用率」这样的针对一个系列的查询。而连读写总是比随机读写要快得多得多。那么把一个系列的数据组织到一起将会有很大的益处。再改造一下设计,把数据按系列拆分开:

方案二:

系列表:

表号 标签值
1 IP=192.168.1.1;CPU=#0
2 IP=192.168.1.1;CPU=#1

表①:

时间 使用率
5 1
6 3

表②:

时间 使用率
5 17
6 15

但是,这导致了写变成随机操作。

因为内存是所有存储设备中随机性能最好的,可以利用内存先存起来,再改一改方案二。

方案二A:

把数据先按方案二写到内存上,攒一段时间的数据再统一写到硬盘上。

似乎很完美了。

但是,假如在内存上的数据写入硬盘之前发生了意外断电,这些数据就会丢失。继续改方案二。

方案二B:

写入内存的同时,也按照 方案一中数据表 的形式写一份到硬盘中,把它称之为 WAL(Write-ahead logging),对硬盘来说是连续写,可以有很好的性能 。内存和硬盘上的两份数据都写入成功才是成功。

如果发生断电,程序重启后先读取硬盘上的 WAL,恢复内存中尚未写入硬盘的数据。虽然读取 WAL 恢复内存结构的成本比较高,但断电并不总是发生。

三、InfluxDB 是怎么干的

InfluxDB 的做法是类似的:

func (e *Engine) WritePoints(ctx context.Context, points []models.Point) error {
  // 略去预处理代码
​
  // first try to write to the cache
  if err := e.Cache.WriteMulti(values); err != nil {
    return err
  }
​
  if e.WALEnabled {
    if _, err := e.WAL.WriteMulti(ctx, values); err != nil {
      return err
    }
  }
  return seriesErr
}

 

先写入了内存上的 Cache,然后写入硬盘上的 WAL两者都写入成功后才返回。

最后:我们根据时序数据和计算机本身的特点重新梳理了思路,反推出了与 InfluxDB 类似的方案 。虽然一直在用关系数据库中的表进行说明,但是这并不表示 InfluxDB 使用关系数据库做为其存储引擎。在下一篇文章中将了解如何把 InfluxDB 在自己的机器上编译运行起来,进行断点调试,并详细的探索 InfluxDB 中 Cache 的结构。

扩展阅读:

  • 连续操作 VS 随机操作:缓存亲和性(cache affinity)
  • 行存、列存、数据布局:CMU Advanced Database Systems - 10 Storage Models & Data Layout
  • Paul Dix 在 CMU 做的关于 InfluxDB 的介绍,解释了早期 InfluxDB 的各种技术选型及遇到的问题:Time Series Database Lectures #1 - Paul Dix (InfluxDB)
  • InfluxDB 的这个技术方案叫做 TSM-Tree ,受到了 LSM-Tree 的启发,LSM 原始论文:The Log-Structured Merge-Tree (LSM-Tree)
标签: 暂无
最后更新:2022年5月8日

Cal Huang

这个人很懒,什么都没留下

点赞

文章评论

razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
取消回复

COPYRIGHT © 2021 hhyhhy.com. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang