MatrixDB如何实现单机5000万数据点/秒写入速度

作为一款高性能时序数据库,数据写入是最普遍场景,所以数据写入速度尤为重要。数据写入框架如下图所示:

整体结构图

设备产生实时数据,通过数据采集系统发送到IoT网关,再写入到MatrixDB中。 为此,MatrixDB专门开发了MatrixGate组件,来优化数据写性能。本文将详细讲解MatrixGate的实现方式。

1 MatrixDB数据写入方式

首先,先介绍一下MatrixDB进行数据写入的两种方式:

1.1 直接INSERT

直接INSERT,顾名思义,就是通过INSERT INTO TABLE VALUES语句插入数据,这是一种最基本最简单的方式,也是所有数据库都支持的方式。当今数据库系统在处理查询时都拥有高并发、低延迟的特性,尤其对于HTAP系统,这种方式在处理对吞吐量要求不是特别高的场景完全可以,比如每秒20000行或几十万数据点每秒。那么,当吞吐量逐渐加大,直接INSERT面临的问题是什么呢?这要从MatrixDB如何执行查询说起。

MatrixDB是一款中心化分布式数据库系统,系统由master节点总控,负责客户端连接、查询执行路径生成、计划下发、结果汇总等。

对于一条INSERT语句,执行过程如下: INSERT查询执行图

从上图执行INSERT流程可以看出:

  1. 直接INSERT意味着所有查询都要通过master做计划、下发。每个查询都经历相同的一整套流程,master要消耗大量资源
  2. 每条数据都要经历一整套从客户端到master,再到segment的过程,延时也不可忽略。

对于直接INSERT有一个小小的优化方法,就是批量插入,即每条INSERT语句VALUES后面跟多个行。

批量INSERT可以减少master做查询计划的次数,但是每条数据还是要通过master节点,进行解析与分发,master仍然是瓶颈。

1.2 使用MatrixGate

MatrixGate是MatrixDB提供的一个数据写入组件,目的是提高数据写入性能。其设计理念就是充分发挥分布式数据系统的优势,将数据解析的过程下发到了segment。具体使用方式,请参考数据加载服务器MatrixGate

1.3 两种写入方式对比

写入方式 优势 劣势 适用场景
直接INSERT 接口简单 吞吐量低 吞吐量低,几十万数据点/秒
MatrixGate 吞吐量高
准实时
需要额外部署,有运维成本 吞吐量高,千万数据点/秒

2 MatrixGate实现原理

本节详细介绍MatrixGate是如何做到高吞吐的。

2.1 外部表

首先要提到一种新的表类型,外部表。 外部表

与其他表类型数据存储在数据库内部不同,外部表数据存储在数据库外部,内部只存了表的元信息。在创建表的时候通过LOCATION关键字指定,可以是文件路径,PXF,S3或HTTP接口。

当查询外部表时,会根据LOCATION的协议和路径去读取指定的内容,从SQL接口层面看起来和普通表没有任何区别,也可以与其他普通表做连接。

如下SQL语句,创建了一张名为ext的外部表,LOCATION路径为file://mdw/home/mxadmin/e1.csv,格式为csv:

CREATE EXTERNAL TABLE ext(
 c1 int,
 c2 varchar(100)
)LOCATION ('file://mdw/home/mxadmin/e1.csv') format 'csv' (delimiter ',');

2.2 基于外部表并行导入数据

那么,如何将外部表数据导入到数据表呢?

通过执行如下语句:

INSERT INTO dest SELECT * FROM external;

其中dest是目标数据表,external是外部表,并且两个表的列数和类型必须相同。

如上SQL与普通的INSERT INTO VALUES最大的区别就是,数据解析与重分布执行在segment节点上,这样充分利用了分布式多机资源。 数据移动

如上图所示,在实际运行过程中,会有两组Gang,一组负责从MatrixGate拉取数据并分发到对应的segment,另一组负责接收分发的数据然后存储到本地。

所以,master节点并不处理实际数据,真正的解析与转发都是由segment进行,master节点不再是瓶颈。

2.3 MatrixDB数据写入流程

MatrixGate利用了外部表导入数据的优势,实现了HTTP协议,和创建外部表、执行INSERT SELECT的过程。 MatrixGate框架图

从上图可以看出:

  1. MatrixGate提供了两个数据接口
    1. 设备数据写入的推送接口
    2. 外部表数据获取的拉取接口
  2. 数据从推送到被segment拉取中间无数据落盘,减少了IO次数
  3. MatrixGate通过master执行INSERT INTO dest SELECT * FROM external,实现数据从外部表到数据表的导入,即从设备到数据表

如要增加并发,在MatrixGate中启动多个任务并行执行INSERT INTO dest SELECT * FROM external即可。目前,MatrixGate默认配置了10个并行任务。

2.4 准实时

最后,还有一个问题。那就是INSERT INTO dest SELECT * FROM external语句什么时候执行结束呢?

因为设备数据是一直在发送的,永不停歇,这就意味着segment一直能从MatrixGate拉到数据。如果插入语句一直执行不结束的话,数据就一直无法被其他会话看到;同时,事务太大,数据库维护成本也太高。

为此,MatrixGate的每个并行任务在执行一段时间后,会向所有取数据的segment发送EOF,即结束符。segment收到结束符后,认为数据已经取完,随之SELECT * FROM external子查询执行结束。在INSERT成功后,整个查询完成。

随后,会继续执行INSERT INTO dest SELECT * FROM external,写入后面的数据。每个接收数据任务的默认执行时间间隔为100ms,即过100ms发送EOF。也就是说,数据在百毫秒级别时延后就会被查询到,基本接近实时。

流程图

从上图可以看出,MatrixGate的每个数据写入任务内部有很多Slot,每个Slot都会执行INSERT INTO dest SELECT * FROM external语句来实现数据从外部表导入到数据表。SQL语句执行分为如下两个阶段:

  1. 发送数据
  2. 重分布与提交

每次发送数据时间窗口为100ms,不同Slot之间发送数据是互斥的(因为一个Slot就会占满网络带宽)。发送数据时间窗口到达后,发送EOF结束SELECT子句。新写入的数据则进入下一个Slot的发送数据窗口。

3 结论

从上面可以看出,使用MatrixGate这种架构模型包含如下优点:

  1. 数据从客户端到segment之间没有落盘,实时转发,无本地IO消耗
  2. 数据解析过程转移到了segment上,充分发挥了分布式系统多机资源
  3. 多任务并行处理,最大限度利用集群资源
  4. 微批量,保证了实时性
  5. 外部表维护操作对用户透明,降低了维护成本

经测试,使用MatrixGate进行数据导入与竞品相比,性能可以提升几十倍。具体数据可参考时序数据库插入性能评测:MatrixDB是InfluxDB的78倍