Multi-Model多模数据库引擎设计与实现_欧晨eli的博客-程序员秘密_多模数据库

技术标签: 数据库  多模数据库  

如今,随着业务“互联网化”和“智能化”的发展以及架构 “微服务”和“云化”的发展,应用系统对数据的存储管理提出了新的标准和要求,数据的多样性成为了数据库平台面临的一大挑战,数据库领域也催生了一种新的主流方向。

数据库多模Multi-Model是指同一个数据库支持多个存储引擎,可以同时满足应用程序对于结构化、半结构化、非结构化数据的统一管理需求。

  1. 数据库云化需求催生Multi-Model多模

企业使用云数据库对接的应用越来越多,需求多种多样,传统的做法是在dbPaaS里面提供十几个不同的数据库产品分别应对各种需求,这样的方法在系统增加后,整体维护性和数据一致性管理成本很高,会影响到整个系统的使用。

 

云数据库的“多模”示意图

为了实现业务数据的统一管理和数据融合,新型数据库需要具备多模式(Multi-Model)数据管理和存储的能力。通常来说,结构化数据特指表单类型的数据存储结构,典型应用包括银行核心交易等传统业务; 而半结构化数据则在用户画像、物联网设备日志采集、应用点击流分析等场景中得到大规模使用;非结构化数据则对应着海量的的图片、视频、和文档处理等业务,在金融科技的发展下增长迅速。

多模式数据管理能力,使得数据库能够进行跨部门、跨业务的数据统一存储与管理,实现多业务数据融合,支撑多样化的应用服务。在架构上,多模Multi-model也是针对云数据库需求的,则使得数据库使用一套数据管理体系可以支撑多种数据类型,因此支持多种业务模式,大大降低使用和运维的成本。

  1. Multi-Model存储引擎架构 

数据库是现有许多业务系统的核心。随着数据生成与采集技术的飞速发展,数据量不断爆炸式增长,数据的结构也越来越灵活多样。传统基于关系型理论构建起来的数据库管理系统,面对大数据、人工智能的真正到来,在成本、性能、扩展性、容错能力等方面遭遇到了不小的挑战。

面对多类型的的结构化数据、半结构化数据、非结构化数据,现代应用程序对不同的数据提出了不同的存储要求,数据库因此也需要适应这种多类型数据管理的需求。

比较流行的两种解决思路分别是:混合持久化(Polyglot Persistence)与多模数据库(Multi-Model Database)。

1)混合持久化 Polyglot Persistence

混合持久化的思路是指,用户根据工作的不同需求分别选择使用合适的数据库,这样在一个完整的系统中,可能同时运行着多种不同的数据库。

 

图1 Polyglot Persistence示意图

混合持久化一个显著的优点就是单一流程的性能提升,但缺点也同样的显而易见:以增加复杂性和学习成本为代价,在部署、使用及维护上带来了挑战。

2)多模Multi-Model

Multi-model多模数据库则是另一种解决思路,在同一个数据库内有多个数据引擎,将各种类型的数据进行集中存储和使用。多个不同类型的应用,同时接入一个数据库,并在同一个分布式数据库内进行管理,大大简化应用程序的开发及后期维护成本。

 

图2:多模数据库引擎架构示意图

图为多模Multi-Model数据库的示意图,我们可以看到在同一个存储引擎里面同时具备 关系型数据、JSON半结构化数据、对象数据以及全文检索引擎等等多个数据引擎,统一提供给应。这一架构大大降低开发和运维的难度,应用统一连接到数据库,数据库内部进行数据的划分、隔离和管理,对应用来说只需要连接到数据库即可,无需为了每个应用搭建对应的数据后台。

3. 存储数据结构

针对多模数据库的需求,分布式数据库的存储数据结构也会有新的创新。以下就是SequoiaDB在Multi-model方面,进行的数据存储结构和访问的设计和实现,可以作为Multimodel数据库的一个很好的参考。

3.1 结构化、半结构化数据存储

结构化数据的特点是结构固定,每一行的属性是相同的,如传统关系型数据库表中的数据。半结构化数据是一种自描述结构,它包含相关标记用来分隔语义元素及对记录和字段进行分层,如 XML,JSON 等。

存储结构

如何在数据引擎中同时管理结构化和半结构化数据呢?SequoiaDB 使用JSON 数据模型,在数据库内部使用BSON 格式来将结构化及非结构化数据以文档的形式存储在集合中。

BSON(Binary JSON)是对 JSON 的一种二进制编码数据格式,和 JSON 一样,BSON支持嵌入式的文档和数组。BSON 由若干个键值对存储为单个实体,这种实体称为文档。BSON 包含了 JSON 中的数据类型,并扩展了一些 JSON 中没有的数据类型,如Date,BinData 等。BSON 结构的一个简单示例如下图所示。

图3:  BSON 结构示例

BSON 具有以下几个特性:轻量级(Lightweight),可遍历性(Traversable),高效性(Efficient)。由于BSON结构包含足够的自描述信息,因此它是一种 schema-less 的存储形式。

SequoiaDB将 BSON作为记录的存储结构,由于其良好的灵活性,不需要事先对集合的结构进行定义,每一个记录中包含的字段信息可以相同,也可以不同,并可随时进行修改,这样对结构及半结构化的数据都能以一致的方式统一存储和访问。

SequoiaDB中的数据管理模型如图4所示。

 

图4: SequoiaDB 数据管理模型架构图

数据最终都是要在磁盘文件中进行持久存储,与之相关的三个概念如下:

  • 文件(File):磁盘上的物理文件,用于持久存储集合数据、索引及 LOB 数据。
  • 页(Page):页是数据库文件中用于组织数据的一种基本结构,SequoiaDB中使用页来对文件中的空间进行管理与分配。
  • 数据块(Extent):由若干个页组成,用于存放记录。

在该模型中,与结构/半结构化数据存储相关的三个核心逻辑概念包括:

  • 集合空间(Collection Space):用于存储集合的对象,物理上对应于一组磁盘上的文件。
  • 集合(Collection):存放文档的逻辑对象。
  • 文档(Document):存储在集合中的记录,以 BSON 结构存储。

一个集合会包含若干个 extent,所有这些 extent使用链表串联起来。当向集合中插入文档时,需要从 extent 中分配空间。如果当前 extent 没有足够空间,则分配新的 extent(必要时对文件进行扩展),挂到该集合的 extent 链表上,然后向其中插入文档。每个 extent 内的记录也通过链表的形式组织起来,这样在进行表扫描时,可顺序读取块内的所有记录。

数据访问

1)SQL

当前大量基于数据库的应用使用 SQL 来进行数据库访问,因此对的 SQL 支持是数据库必不可少的能力。SequoiaDB支持标准 SQL 接口,完全兼容 PostgreSQL 及 MySQL语法和协议,现有的应用可平滑地将存储系统切换为 SequoiaDB,以获得分布式存储系统所带来的扩展性、性能及可靠性等立面的巨大提升。

2)API

SequoiaDB 在结构化数据提供了丰富的 API 接口用于管理整个集群及操作数据,提供了各种主流编译语言的驱动。

数据压缩

对于JSON/BSON数据结构,因为其嵌套结构,在拥有灵活的存储结构同时,也会造成数据的膨胀。JSON数据存储的膨胀问题,也是早期如MongoDB等JSON数据库性能瓶颈的一个重要原因。

SequoiaDB在使用JSON/BSON作为数据存储结构时,为了避免过度的膨胀问题,在数据引擎中加入了数据压缩的机制。目前SequoiaDB引擎提供了两类压缩方式:行压缩与表压缩。行压缩使用Snappy算法,是一种不需要字典的快速压缩机制。表压缩则使用LZW算法,是一种基于字典的压缩机制。

数据压缩机制,一方面从存储上节省空间和成本,另一方面提升单位I/O的效率。在IO吞吐量非常高的查询场景下,基于数据字典的深度压缩机制能够大幅降低IO开销,有效提高查询效率。

3.2非结构化数据存储

存储结构

非结构化数据即没有固定结构的数据,如文档、图片、音频/视频等,这种类型的数据在现在的很多业务中所占的比重越来越大。在SequoiaDB中,使用大对象(LOB,Large Object)来对这种类型的数据进行管理。

大对象依附于普通集合存在,当用户上传一个大对象时,系统为它分配一个唯一的 OID 值,后续对该大对象的操作可通过该值来进行指定。

大对象在存储时会进行分片,并使用hash算法将分片分散存储在相应的分区组中,其哈希空间与所属集合的哈希空间一致。分片大小为 LOB 页大小,在创建集合空间时指定,默认为 512KB。

为了对 LOB 数据进行有效的存储和管理,SequoiaDB内部将 LOB 数据抽象为元数据和数据本身,并使用两种文件来存储这些数据: LOBM 文件用于存储 LOB 分片的元数据,LOBD 文件用于存储真正的 LOB 数据分片。它们的逻辑结构如下图所示。

图5: LOB 文件逻辑结构

其中LOBM 文件主要包括:

  • 文件头:包含该文件的一些元数据信息。
  • 空间管理段(SME):用来标记页的使用情况。
  • 桶管理段(BME):hash 值相同的分片所占用的页以双向链表的形式挂在一个桶上。
  • 页:与 LOBD 中的页一一对应,记录该页所属的集合信息,OID及sequence 值等。

LOBD 文件主要包括:

  • 文件头:包含该文件的一些元数据信息。
  • 真正的数据页:用于存储 LOB 分片。LOB 还有一些自身的元数据,保存在 sequence 为0的分片中,包括该 LOB 数据的大小、创建时间、版本号等。

数据访问

1)写入LOB

当需要写入 LOB 数据时,LOB 数据会在协调节点上进行分片,每一个分片分配了一个 sequence 值,它表示这些分片在原始 LOB 数据中的顺序。因此,LOB 的OID与分片的 sequence 值唯一地标识了这个分片。

在存储一个 LOB 分片时,使用其 OID + sequence 计算 hash 值。先使用集合的分区 hash函数来计算出该分片要存储到哪个分区组上,然后使用 LOB 分片的 hash 函数来计算出其挂接到哪个桶上,之后在 LOBD 及 LOBM 文件中分配数据页,完成数据写入,LOBM 中的页挂到对应的桶上。

2)读取LOB

在获取 LOB 数据时,需要指定其 OID值。引擎根据OID值获取 sequence 值为0的分片,从中读出 LOB 的元数据信息,然后进行分片计算,确定所有分片信息,向所有包含分片的分区组发送请求。

当协调节点接收到各级返回的分片数据后,按 sequence 的顺序对 LOB 数据进行合并还原,以获取完整的 LOB 数据。

3)标准 Posix文件系统接口

除了LOB的API之外,目前提供SequoiaFS文件系统,它是基于FUSE在Linux系统下实现的一套文件系统,支持通用的文件操作API。SequoiaFS利用SequoiaDB的集合存储文件和目录的属性信息,LOB对象存储文件的数据内容,从而实现了类似NFS分布式网络文件系统。用户可以将远程SequoiaDB的某个集合通过映射的方式挂载到本地节点,从而在挂载节点的目标目录下可以通过通用文件系统API对文件和目录进行操作。

4. 小结

根据Gartner的报告,Multi-Model多模是数据库领域近年兴起的一个主要的技术方向之一,其代表了在云化架构下,多类型数据管理的一种新理念,也是简化运维、节省开发成本的一个新选择。

SequoiaDB的Multi-Model数据库产品,目前已经在许多行业的到了应用,这也证明市场正在慢慢接受这一新的数据库架构。我们也看到MySQL,PostgreSQL等数据库也在开始支持JSON等多类型格式,也在朝着Multi-model的方向发展。未来相信各产品也会持续保持创新,出现更多Multi-model的数据库产品。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/xiao_yi_xiao/article/details/123063543

智能推荐

Session理解_SunsetFeng的博客-程序员秘密

Cookie和Session都可以实现会话跟踪,将上一次的请求传入下一次内,但它们的实现方式有一个显著的区别,如下:Cookie:将当前会话的信息存在浏览器端,每次请求时将Cookie信息传入服务器 Session:将会话的信息存在服务器端,浏览器保存一个JSESSIONID,每次传入JSESSIONID去取信息很显然,2种会话跟踪的实现方式,Session是在服务器端保持状态的方案,Co...

【IDEA】idea写java代码运行按钮是灰色的解决办法_宾有为的博客-程序员秘密_idea运行按钮是灰色

因对百度经验作者无法删除自己的帖子,特将此文转到CSDN,以此方式表达对百度经验的不满!!!问题描述Run按钮灰色状态,无法点击运行,如图:原因分析上图估计大佬一看就看出问题了,其实就是因为少了一个main函数问题解决我现在把main函数补上去public static void main(String[] args){ int a; for (a=0;a<=100;a++){ System.out.println(a); }}把

python微信公众号文章爬虫(上)_倚东的博客-程序员秘密_公众号爬虫

微信公众号爬虫关键是获取请求地址。这篇文章是方法之一。登录自己的公众号后台,微信公众平台,进入图文消息编辑界面,输入超链接,选择公众号文章,搜索公众号,比如人民日报,然后会弹出最新的文章列表。此时可以找到相应的请求,通过公众号文章翻页,可以找到请求的参数规律。注意:请求是需要cookies参数,可以拷贝浏览器访问的cookies。代码如下:''' the key is to use cookies'''import requestsheaders={'User-Agent':'...

signature=ad248ee50cb35fb429594f302bf99ddf,Error Detection Using Dynamic Dataflow Verification_风华秋实的博客-程序员秘密

摘要:A significant fraction of the circuitry in a modern processor is dedicated to converting the linear instruction stream into a representation that allows the execution of instructions in data depend...

textview 与textsize_jks456的博客-程序员秘密

在设计安卓界面的时候我发现一个TextView在布局上占用的高度和属性textSize的大小不一样,要比textSize要来的大(比如textSize="12dp",实际的高度大概有14-16dp),仔细看的话会发现文字的上方和下发留有空白。 这个问题我纠结了很久。。。因为这严重影响布局的效果啊。不过这么基础的问题网上竟然找不到资料。。。 在安卓文档中发现一个TextVie

[转]TOKUDB VS. INNODB FLASH MEMORY_z-pan的博客-程序员秘密

Details on the software settings for these tests can be found at the end of this page.IIBENCH TESTINGTokutek created the iiBench benchmark in 2008. The point of the benchmark is to measure the per...

随便推点

Ubuntu下部署Django项目_他-途的博客-程序员秘密_ubuntu部署django

1.首先要进入环境把项目所需要的环境导出来1 pip freeze >requirements.txt2.安装python环境3.安装python3.6版本(阿里云服务器默认3.5,可以选择不用安装,看心情吧)3. 安装虚拟环境(这个也看心情吧)4.把得到的requirements.txt打开,每个环境之间以一个空格隔开 然后复制到Ubuntu通过pip下载...

java8之parallelStream并发_ylf尘风的博客-程序员秘密_parallelstream 设置线程池大小

java8之stream一、stream介绍1、基础用法二、parallelStream并行parallelStream并行,底层实现采用ForkJoin,线程池大小默认为:cpu核心数*获取cpu核心数代码:Runtime.getRuntime().availableProcessors();*手动设置ForkJoin线程池大小// 线程池大小配置String FORK_JOIN_POOL_PARALLELISM = "java.util.concurrent.ForkJoinPool

【Android自动化打包】03. APK的数字签名_weixin_34087503的博客-程序员秘密

1. 什么是数字签名?数字签名就是为你的程序打上一种标记,来作为你自己的标识,当别人看到签名的时候会知道它是与你相关的2. 为什么要数字签名?最简单直接的回答: 系统要求的。Android系统要求每一个Android应用程序必须要经过数字签名才能够安装到系统中,也就是说如果一个Android应用程序没有经过数字签名,是没有办法安装到系统中的!And...

01-Grafana+Prometheus+exports+Alertmanager监控告警系统基础配置_zhangpfly的博客-程序员秘密

Grafana+Prometheus+Exporter+Alertmanager监控告警系统1. GrafanaPrometheusExporter+Alertmanager监控告警系统说明1.1 简述1.2 要实现的功能2. Grafana+Prometheus安装与简单配置2.1 Grafana安装2.2 Prometheus安装1. GrafanaPrometheusExporter+Alertmanager监控告警系统说明1.1 简述grafana+Prometheus的组合是现在一个比较流行

docker常见报错[email protected]的博客-程序员秘密

在我们实际使用docker的过程中,难免出现各种各样的错误,下面我将自己遇到的比较难解决的错误和解决方法记录下来。1.docker启动报错一(1).描述docker启动报错 :Error starting daemon: SELinux is not supported with the overlay2 graph driver on this kernel. Either boot...

面向对象提高———友元_過去※的博客-程序员秘密

友元函数:1:一个类的友元函数可以访问该类的私有成员.#include <iostream>using namespace std;class CCar ; //提前声明 CCar类,以便后面的CDriver类使用class CDriver{ public: void ModifyCar( CCar * pCar) ; //改装汽车};class CCar{ private: int price; public: CCar(int p):pric

推荐文章

热门文章

相关标签