编辑
2022-11-21
💻数据库
00
请注意,本文编写于 941 天前,最后修改于 225 天前,其中某些信息可能已经过时。

目录

1.基础
2. 关系型数据库的不足
两者之间的存在的冲突:
3. redis的不足
3. 时序数据库
1. 时序数据模型
2. 常见的时序数据库
OpenTSDB
InfluxDB
3. 深入influxDB
数据模型
series
查询语言
整体架构
WAL
Cache
TSM File

1.基础

时序数据TimeSeries是一连串随时间推移而发生变化的相关事件

常见的时序数据有:

  • 监控日志:机器的 CPU 负载变化
  • 用户行为:用户在电商网站上的访问记录
  • 金融行情:股票的日内成交记录

此类数据的特点:

  • 必然带有时间戳,可能存在时效性
  • 数据量巨大,并且生成速度极快
  • 更关注数据变化的趋势,而非数据本身

2. 关系型数据库的不足

当面对时序数据时,传统的关系型数据就显得力不从心

关系型数据模型时序数据库需求
数据按住建索引组织、存储数据按时间戳进行组织、存储,便于按时间维度查询
数据持久后永久存在数据具有的生命周期,定期清理过期数据
支持复杂的OLTP功能(点查、改、删)支持的OLAP操作(基于时间窗口)
并发修改加锁,提供事务保证Last Write Win解决写冲突,无需事务

两者之间的存在的冲突:

  • 如果主键设计的不好,时序数据的顺序插入可能变为随机写入,影响写入性能
  • 传统关系型数据为提高数据生命周期管理功能,需要定时执行清理任务,避免磁盘空间耗尽
  • 关系型数据库对事务的支持,对于时序数据来说略显多余,还会影响写入能力

除此之外,关系型数据库还存在以下天然短板:

  • 需要通过分表分库sharding实现横向扩展

    分库分表引入额外复杂度,需要维护映射关系。 此时 SQL 语言的查询优势不复存在,多数查询都会退化为 KV 查找

  • 写时模式schema on write灵活度不足 关系数据库新增字段属于 DDL 操作,会导致锁表锁库。 频繁的库表变更影响系统稳定,无法适应快速的业务变更。

注意,修改表结构的操作,MySQL8.0之前的版本默认是会锁表的,所以,不要在业务高峰期做这些操作,而是选择在晚间进行操作,当然,我们也可以在晚间使用在线的DDL工具来处理这些事情,避免锁表对业务造成影响。

常用的在线DDL工具

  • MySQL的Online。
  • pt-osc,推荐使用。

3. redis的不足

存储时序数据库的另一个挑战就是其夸张的数据生成速度。以用户行为数据为例,如果一个接口的QPS是1万。就意味着一秒钟内会生成1万条用户行为记录。假设这样的接口有100个,那么每秒钟生成的记录数可达100万。

 一种解决方式是将消息积压至 Kafka 这类中间件,然后进行异步处理。但对于某些业务场景来说,这一处理方式则显得不合时宜。以股票成交数据为例,为了保障行情的时效性,无法采用异步批处理的方式实现。为了实现极高的写入吞吐量,通常会考虑使用 Redis 实现这一功能。

然而这一方案也存在以下问题:

  • redis 不适合存储大 Key,删除 Key 的内存释放操作可能导致长时间的阻塞
  • 假设数据以 list 的形式存储,执行 lrange 命令的时间复杂度为O(S+N),访问性能较差
  • 内存空间有限,无法存储大量的数据

3. 时序数据库

时序数据库是一类专门用于存储时序数据的数据管理系统,这类数据库的设计思想大致可以总结为下面几条:

  • 使用特殊设计的外存索引来组织数据
  • 强制使用 timestamp 作为唯一的主键
  • 不检查写冲突,避免加锁,提高写入性能
  • 对按时间顺序写入进行优化,提高写入性能
  • 不支持细粒度的数据删除功能,提高查询写入性能
  • 牺牲强一致性来提高系统的查询吞吐量,提高查询性能
  • 提供基于时间窗口的 OLAP 操作,放弃关联查询等高级功能
  • 通过无模式schemaless设计使系统更易于水平扩展

1. 时序数据模型

类似于关系型数据库,时序数据库也有自己的数据模型,并且两者直接存在不少相似之处:

关系模型时序模型含义
tablemetric/measurement表——指标(时间序列)
columnvalue/field列——值(无索引序列)
indextag索引——标签(索引列)
rowpoint记录行——数据点(时间序列中某个时刻的数据)
primary keytimestamp行主键——点时间戳(时间序列内唯一标识)

其中 tag 的概念较为重要:

  • tag 是一个字符串类型的键值对
  • tag 并不是时序数据,而是元数据
  • tag 的唯一组合确定一个时间序列
  • tag 可以方便实现粗粒度的聚合
  • tag 决定了索引的组织形式
  • tag 组合的数量数量不宜过多

2. 常见的时序数据库

OpenTSDB

OpenTSDB 是一种基于 HBase 来构建的分布式、可扩展的时间序列数据库。OpenTSDB 被广泛应用于存储、索引和服务从大规模计算机系统(网络设备、操作系统、应用程序)采集来的监控指标数据,并且使这些数据易于访问和可视化。

image.png

OpenTSDB 由时间序列守护程序 (TSD) 以及一组命令行实用程序组成。每个 TSD 都是独立的。 没有主节点,没有共享状态。

  • 优点

    TSD 是无状态的,所有状态数据保存在 HBase 中,天然支持水平扩展

  • 缺点

    1. Hadoop 全家桶运维难度较大,需要专人负责。新版本的 OpenTSDB 底层支持 Cassandra
    2. 存储模型过于简化。单值模型且只能存储数值类型数据,单个 metric 最多支持 8 个 tag key
    3. 虽然利用了 HBase 作为底层存储,但是没有提供对 MapReduce 的支持。可以通过 Spark 实现复杂的处理逻辑

InfluxDB

时序数据库 InfluxDB 是一款专门处理高写入和查询负载的时序数据库,基于 InfluxDB 能够快速构建具有海量时序数据处理能力的分析和监控软件。该项目的发起者是 influxdata 公司,该公司提供了一套用于处理时序数据的完整解决方案,InfluxDB 是该解决方案中的核心产品。

image.png

  • 优点

    1. 开箱即用,运维简单
    2. 多值存储模型、丰富的数据类型
    3. 提供了类 SQL 的查询语言
    4. 独创 TSM 索引
  • 缺点

    1. 开源版本不支持集群部署,对于大规模应用来说,使用前需要慎重考虑

3. 深入influxDB

数据模型

InfluxDB 的数据模型已经很接近传统的关系模型:

database命名空间,相互隔离
retention policy保存策略,定义数据生命周期
bucketdatabase+retention policy
measurement相关时间序列集合
tag标签索引,索引列
field时序数据,无索引列
point数据点,时间序列中某个时刻的数据
time时间戳,时间序列内唯一标识

image.png

保留策略retention policy 用于管理数据生命周期,其中包含了:

  • 持续时间duration:指定了数据保留时间,过期的数据将自动从数据库中删除

  • 副本个数replication factor:指定了集群模式下,需要维护数据副本的个数(仅在集群模式下有效)

  • 分片粒度hard duration):指定了 shard group 的时间跨度(影响数据分片大小)

保留策略与 database 存在以下关系:

  • 一个 database 可以有多个 RP,每个 RP 只属于一个 database 1
  • 创建 point 时可以指定 RP,一个 measurement 可以有不同的 RP N

这意味着:

同个 measurement 可能存在两个有着完全相同的 time 的 point。为了解决数据重复的问题,InfluxDB 2 引入了一个 bucket 的概念,用于避免这一情况。

series

时间序列 Series 在 InfluxDB 中也是个核心概念:

series keymeasurement+tag+field key
series时间序列,serial key相同的数据集合
seriescardinality序列基数,series key的数量

为了唯一标识一个时间序列,InfluxDB 引入了 Serieskey 的概念:

每个数据点都有 Serieskey,Serieskey 相同的数据点属于同个时间序列,会存储在同一个文件中,方便后续查询

Serieskey 的数量称为序列基数 series cardinality:

序列基数是一个重要的性能指标,InfluxDB 会为每个 Serieskey 在内存中维护一个索引记录,因此序列基数能够直观反映当前数据的内存压力

image.png

上图的 series cardinality 为 4,其中包含以下 series key:

measurement + tags + field
census, location=1, scientist=langstroth, butterflier
census, location=1, scientist=langstroth, honeybees
census, location=1, scientist=perpetual, butterflier
census, location=1, scientist=perpetual, honeybees

注意:即便两条记录的 measurement、time、tag、field 完全一致,但只要使用的是不同的 RP,那么它们就属于不同的 series,会被存储在不同的 bucket 中。

查询语言

InfluxDB 提供了两种查询语言:

  • InfluxQL:类 SQL 的声明式查询语言,同时具有 DDL 与 DML 功能
  • Flux:函数式查询语言,仅支持 DML 功能,能支持复杂的查询条件,但不支持增删改操作 下面通过一些实际操作来熟悉一下 InfluxQL:
sql
# 创建数据库 CREATE DATABASE "sample_data" USE sample_data # 插入样例数据,格式参考:https://docs.influxdata.com/influxdb/v1.8/write_protocols/line_protocol_tutorial INSERT census,location=1,scientist=langstroth butterflies=12i,honeybees=23i 1439827200000000000 INSERT census,location=1,scientist=perpetua butterflies=1i,honeybees=30i 1439827200000000000 INSERT census,location=1,scientist=langstroth butterflies=11i,honeybees=28i 1439827560000000000 INSERT census,location=1,scientist=perpetua butterflies=3i,honeybees=28i 1439827560000000000 INSERT census,location=2,scientist=langstroth butterflies=2i,honeybees=11i 1439848440000000000 INSERT census,location=2,scientist=langstroth butterflies=1i,honeybees=10i 1439848800000000000 INSERT census,location=2,scientist=perpetua butterflies=8i,honeybees=23i 1439849160000000000 INSERT census,location=2,scientist=perpetua butterflies=7i,honeybees=22i 1439849520000000000 # 显示数据库中的表 # measurement 无需预先定义,由 InfluxDB 动态创建 SHOW MEASUREMENTS # 显示数据库中的 field key SHOW FIELD KEYS # 显示数据库中的 tag key SHOW TAG KEYS # 显示数据库中的 tag value SHOW TAG VALUES WITH KEY = scientist # 查询所有数据 SELECT * FROM census; # 对 location = 1 的数据求和 SELECT SUM(butterflies) AS butterflies, SUM(honeybees) AS honeybees FROM census WHERE location = '1'; # 删除 location = 1 的数据 DELETE FROM census WHERE location = '1'; SELECT * FROM census; # 更新特定数据 SELECT * FROM census; INSERT census,location=2,scientist=perpetua butterflies=10i,honeybees=50i 1439849520000000000 SELECT * FROM census; # 更新数据时要保证数据类型一致,否则会报错 INSERT census,location=2,scientist=perpetua butterflies=abc,honeybees=efg 1439849520000000000 # 删除数据库 DROP DATABASE sample_data;

Flux 无命令行支持,只能通过 http 接口请求。有兴趣可以参考下面的脚本,动手尝试一下:

curl -XPOST 127.0.0.1:8086/api/v2/query -sS \ -H 'Accept:application/csv' \ -H 'Content-type:application/vnd.flux' \ -H 'Authorization: Token root:123456' \ -d ' from(bucket:"sample_data") |> range(start:time(v: 1439827200000), stop:time(v: 143984952000)) |> filter(fn:(r) => r._measurement == "census" and r.location == "1" and (r._field == "honeybees" or r._field == "butterflies")) |> limit(n: 100)'

整体架构

在了解完查询语言之后,接下来看看 InfluxDB 的整体架构:

image.png

上图将 InfluxDB 分为了 4 层,上面 database 与 RP 这两层之前已经介绍过,我们重点关注下面两层:

shard存储的时序数据的磁盘文件
shard groupshard 容器,责管理数据的生命周期,清除过期的数据
shard durationshard duration
由于时序数据的数据量通常十分巨大,因此 InfluxDB 的设计中引入了分片的策略。并且同时采用了两种分片策略:
  • shard group 层采用了基于时间的分片策略,方便实现按照时间条件范围查询
  • shard 层则是基于 hashmod 进行分片,避免出现写热点产生性能瓶颈   每个 shard 由 WAL、Cache、TSM文件 3 部分组成:

image.png

整个数据的写入流程简化为 3 个步骤:

  1. 先写入 WAL
  2. 然后写入 Cache
  3. 最终持久化为 TSM File
WAL

 预写日志Write-Ahead-Log是一种常见的提高数据库优化手段,能够在保证数据安全的同时,提升系统的写入性能。  InfluxDB WAL 由一组定长的 segement 文件构成,每个文件大小约为 10MB。这些 segment 文件只允许追加,不允许修改。

Cache

Cache 是 WAL 的一个内存快照,保证 WAL 中的数据对用户实时可见。 当 Cache 空闲或者过满时,对应的 WAL 将被压缩并转换为 TSM,最终释放内存空间。 每次重启时会根据 WAL 重新构造 Cache。

TSM File

TSM 是一组存储在磁盘上的外存索引文件,细节将在后续进行介绍。

它们之间的关系可以简单描述为:

influxdb的安装 python操作influxdb

本文作者:Eric

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!