关于数据库:深度解密-OpenMLDB-毫秒级实时在线特征计算引擎

1次阅读

共计 5080 个字符,预计需要花费 13 分钟才能阅读完成。

本文整顿自 OpenMLDB Meetup No.5 中 OpenMLDB PMC 邓龙的演讲。本文深刻解析 OpenMLDB 架构设计背地的硬核技术,率领大家理解 OpenMLDB 毫秒级实时在线特色计算引擎外部实现。分享视频如下:接下来作者将从“OpenMLDB 整体架构”、“在线实时 SQL 执行引擎和存储引擎”、“在线引擎性能测试”三个板块为大家介绍 OpenMLDB 毫秒级的实时在线特色计算引擎。一、OpenMLDB 整体架构 1.1 OpenMLDB 是线上线下统一的生产级特色平台

OpenMLDB 是一个提供线上线下一致性的生产级特色平台,咱们对外提供的是一整套的 SQL 语言。用户能够通过 SQL 语言写成脚本,再用 OpenMLDB 离线引擎做批量计算,进行模型摸索。摸索实现后,SQL 脚本能间接上线通过 OpenMLDB 的在线实时引擎实现实时特色计算。在离线局部,OpenMLDB 的离线特色计算引擎是基于 Spark 做了一个革新。Spark 会用 JNI 的形式来调用咱们生成的 SQL 解析执行库。在线局部,咱们用自研实时计算引擎来做实时计算。OpenMLDB 离线和在线引擎应用同一套一致性执行打算生成器,运行同一套代码,人造保障了线上线下的一致性。1.2 OpenMLDB 线上引擎整体架构 1.2.1 次要模块 ✦OpenMLDB 线上引擎蕴含的次要模块有 Apache ZooKeeper, Nameserver 以及 Tablet(Tablet 包含 SQL Engine 和 Storage Engine)。下图显示了这些模块之间的关系。其中 Tablet 是整个 OpenMLDB 存储和计算的外围模块,也是耗费资源最多的模块。

ZooKeeper 在 OpenMLDB 中用于服务发现和元数据存储和治理性能。ZooKeeper 和 OpenMLDB SDK,Tablet, Namesever 之间都会存在交互。Nameserver 次要用来做 Tablet 治理以及故障转移(failover)。当一个 Tablet 节点宕机后,Nameserver 就会触发一系列工作来执行故障转移。当节点复原后会从新把数据加载到该节点中。同时,为了保障 Nameserver 自身的高可用,Nameserver 在部署时会部署多个实例,并采纳 primary/secondary 的模式。同一时刻只会有一个 primary 节点。多个 Nameserver 通过 ZooKeeper 实现 primary 节点的抢占。因而,如果以后 primary 节点挂掉,则 secondary 节点会通过 ZooKeeper 从新选出一个 primary 节点。Tablet 模块负责执行 SQL、存储数据。从性能上看,Tablet 蕴含了 SQL Engine 和 Storage Engine 两个模块。Tablet 也是 OpenMLDB 部署资源时可调配的最小单元。一个 Tablet 不能被拆分到多个物理节点;然而一个物理节点上能够有多个 Tablet。1.2.2 执行流程 ✦首先,咱们会提供一个 OpenMLDB SDK(目前已有 Java SDK、Python SDK,Go SDK 正在开发当中)。当然咱们也提供 HTTP 的形式,用 HTTP 的形式须要部署一个 API Server。API Server 外面集成了 OpenMLDB SDK 对 HTTP 申请做转发。SDK 启动时,会连贯到 ZooKeeper,获取一些信息。例如 Nameserver 和 Tablet 的节点信息,还有表的元数据信息等。而后 SDK 再根据 SQL 中的信息依照肯定策略把申请发送到对应的 Tablet 的节点上。Tablet 节点收到申请后会通过 SQL 引擎做 SQL 解析,造成分布式的执行打算。这个 Tablet 可能会给其余 Tablet 发送子工作。其余 Tablet 在执行子工作的过程中,会和存储引擎做一些数据的交互,计算完把后果返回到最后的 Tablet 上汇总。最初把计算结果返回到 SDK。二、在线实时 SQL 执行引擎和存储引擎 2.1 SQL 执行引擎 SQL Engine 负责 SQL 执行。SQL engine 收到 SQL 查问的申请后的执行过程如下图所示:

最开始由 Parser 实现 SQL 解析和校验,生成逻辑打算并进行优化。而后 Codegen 生成 LLVM IR,再编译成机器可执行代码。最初生物理执行打算。SQL 引擎基于执行打算,通过 Catalog 获取存储层数据做 SQL 执行运算。OpenMLDB SQL Engine 提供上百个内置的函数。例如单行的一些函数,对年月日做的简略解决,字符串拼接以及一些聚合函数如 sum/avg 等等。这些内置函数基本上能满足用户的罕用需要。但针对特色逻辑比较复杂的用户场景,咱们还提供了 UDF 的形式,用户能够本人实现解决逻辑。目前只反对 C++ 语言。对 SQL 引擎咱们还做了很多优化,如循环绑定和窗口合并。在一个窗口内,可能会有多种聚合的特色,循环绑定只遍历一次窗口数据就会把基于这个窗口的所有聚合特色计算出来,防止屡次遍历进步执行效率。窗口合并是指如果多个窗口应用雷同的 partition by 列和 order by 列,只是窗口大小不一样,执行引擎只会把最大的窗口从存储引擎中把数据拉进去,不会屡次拉取。2.2 在线存储引擎

Storage Engine 负责 OpenMLDB 数据的存储,以及高可用相干的性能。OpenMLDB 提供基于内存和基于外存两种存储引擎。自研的内存存储引擎具备低提早、高并发的劣势,能够提供毫秒级的提早响应,但老本较高。对性能要求不高的用户也能够应用外存存储引擎,老本较低。经测试基于 SSD 老本可降落 75%。两种引擎对于下层业务代码无感知,能够零老本随便切换。2.3 内存存储引擎外围数据结构

OpenMLDB 内存存储引擎的外围数据结构是一个双层跳表。这里应用跳表是因为跳表领有良好的查问和插入性能。跳表自身是一个链表构造,这样就很容易实现成 lock free,进步性能。而且跳表做 TTL 也十分便捷,只须要批改下对应节点指针。在第一层跳表中 key 是对应索引列的值,value 指向二级跳表。二级跳表中的 key 是工夫戳,value 是一行数据编码后的值。二级跳表是按工夫排好序的,这样就很容易查问一段时间内的数据。2.4 外存存储数据模型——基于 RocksDB

基于 RocksDB 优良的性能体现以及丰盛的性能,OpenMLDB 外存存储引擎抉择基于 RocksDB 存储。在 OpenMLDB 创立表时会基于创立指定多个索引。这里每一个索引就会对应一个 Column family。不同的 Column family 会有独自的 SST 文件和独自的数据淘汰策略,然而它们共享一个 Memory Table。一个 key 和一个 ts 会拼接起来造成 RocksDB 的一个 key。RocksDB 外部 key 是排好序的,这样雷同的 OpenMLDB key 的数据就会挨在一起,不便做一段时间内的数据查问。2.5 高效的编解码格局

因为咱们存储引擎是全副放在内存里边,所以对数据的内存比拟敏感,咱们设计了一套更高效的编解码形式。FVersion 示意数据编码格局版本号, 占用一个字节。如果编码方式做批改,版本号会加 1。不同的版本号对应不同的编解码计划。SVersion 示意 schema 的版本号, 占用一个字节。减少和删除字段版本号都会加 1。Size 示意整条数据大小, 占用四个字节。BitMap 示意哪个字段为 NULL,如果 schema 字段数为 N, 占用长度为: (N+7) / 8。根本类型存储区域寄存 bool/int8/int16/int32/int64/float/double 类型的字段。字符串地址存储区域存储字符串的理论地位,字符串数据存储区域存储的是字符串理论内容。2.6 数据分片

OpenMLDB 集群版是一个分布式的数据库,一张表的数据会进行分片,并且建设多个正本,最终散布在不同的节点中。这里开展阐明两个重要的概念:正本和分片。正本(replication):为了保障高可用以及晋升分布式查问的效率,数据表将会被寄存多个拷贝,这些拷贝就叫做正本。分片(partition):一张表(或者具体为一个正本)在具体存储时,会进一步被切割为多个分片用于分布式计算。分片数量能够在创立表时指定,然而一旦创立好,分片数就不能动静批改了。分片是存储引擎主从同步以及扩缩容的最小单位。一个分片能够灵便的在不同的 tablet 之间实现迁徙。同时一个表的不同分片能够并行计算,晋升分布式计算的性能。OpenMLDB 会使得每一个 tablet 上的分片数目尽量均衡,以晋升零碎的整体性能。一张表的多个分片可能会散布在不同 tablet 上,分片的角色分为主分片(leader)和从分片(follower)。当取得计算申请时,申请将会被发送到数据对应的主分片上进行计算;从分片用于保障高可用性。如上图显示了一个数据表,在两个正本的状况下,在三个 Tablet 上的存储布局。理论应用中,如果某一个或者几个 tablet 的负载过高,能够基于分片,进行数据迁徙,来改善零碎的负载平衡和整体的吞吐。2.7 主从同步

目前版本的 OpenMLDB 的在线数据全副保留在内存中,为了实现高可用会把数据通过 binlog 以及 snapshot 的模式长久化到硬盘中。如上图所示,服务端收到 SDK 的写申请后会同时写内存和 binlog。binlog 是用来做主从同步的,数据写到 binlog 后会有一个后盾线程异步的把数据从 binlog 中读出来而后同步到从节点中。从节点收到同步申请后同样进行写内存和 binlog 操作。Snapshot 能够看作是内存数据的一个镜像,不过出于性能思考,snapshot 并不是从内存 dump 进去,而是由 binlog 和上一个 snapshot 合并生成。在合并的过程中会删除掉过期的数据。OpenMLDB 会记录主从同步和合并到 snapshot 中的 offset, 如果一个 binlog 文件中的数据全副被同步到从节点并且也合并到了 snapshot 中,这个 binlog 文件就会被后盾线程删除。2.8 预聚合技术

某些场景中,工夫窗口内的数据量比拟大,可能达到上百万条,那么用实时计算的形式来计算特色,性能会急剧下降,可能达到了几百毫秒甚至秒级的延时。所以咱们用预聚合技术,针对长时间窗口、大数据量做一些优化,晋升在线计算的性能。预聚合会依照设定的预聚合窗口提前聚合计算,当 SQL 上线之后,会做预聚合表的 初始化。当数据插入进来的话,咱们会主动判断这条数据所在表有无关联预聚合表,若有关联,则会更新预聚合表。目前这块是同步计算,可能对性能会有肯定的影响,后续会做成异步更新。

当收到读取申请时,OpenMLDB 会判断这个申请是否为长窗口优化,若是那咱们能够从这个长窗口边界把原始数据拿取出来,通过这个曾经预聚合的数据计算失去后果。因为窗口中数据曾经提前算好了,所以性能必定会有大幅的晋升。三、在线引擎性能测试 3.1 OpenMLDB 是线上线下统一的生产级特色平台

测试场景配置如图所示。右侧的 SQL 里边有两个窗口,别离定义了 WINDOW1 和 WINDOW2,也有两个 last join,在接下来的性能测试展现中会对窗口做一些预聚合的操作,以及根底的特色计算。3.2 变动 Window 数目以及 LAST JOIN 数目

上图中咱们能看到不同窗口的性能体现。左上图展现了随着窗口的大小的增大,Latency 也会有相应的一个晋升。因为窗口变多,那么数据申请和特色计算也会占用更多的资源,耗费更多的工夫。即便达到十个窗口,TP999 提早也在 七毫秒 以内。右上图展现了吞吐量随窗口的变动。下半局部的两张图展现的是 LAST JOIN 表个数对 OpenMLDB 的提早和吞吐的影响。左下图可见随着 LAST JOIN 个数减少,Latency 也是会有迟缓的一个回升,当然这里的回升并不显著,而吞吐性能也能失去相应降落。3.3 变动窗口内数据条数和索引列基数

在窗口大小为两千的时候,提早大略是在四毫秒左右,当窗口回升到了一万的时后,提早超过十毫秒以上了。大部分状况下能将提早管制提早在十毫秒内。索引列基数变动对性能基本上没什么影响。3.4 长窗口优化

在应用了预聚合优化技术后,长窗口的查问无论是提早还是吞吐都失去了两个数量级的性能晋升。写在最初心愿本文可能帮大家 OpenMLDB 疾速了解把握如何应用如果想进一步理解 OpenMLDB 或者参加社区技术交换,能够通过以下渠道取得相干信息和互动~Github: https://github.com/4paradigm/… 官网:https://openmldb.ai/Email: c[email protected]OpenMLDB 微信交换群:

正文完
 0