当前位置: 首页 > article >正文

图数据库 | 10、图数据库架构设计——高性能图存储架构(上)

老夫在之前的三大篇内容中,介绍了图数据库的三大组件—图计算、图存储以及图查询语言。(都归拢在图数据库原理、架构与应用这个专栏中了,感兴趣的朋友可以在去找阅读。)

接下来,老夫还将继续深化这三大组件,因为这三者是相辅相成的,这也是图数据库架构设计关键所在,也是需要读者去厘清的。

今儿我们先聊高性能存储架构,严格意义上说任何数据库都需要存储引擎,它承载着数据持久化的职责。

在这个数字化转型、分布式架构概念随处可见的时代,似乎是唾手可得的。然而,曾经很长一段时间Apache Hadoop系统也被认为是数据处理的“神器”​,很多从业者甚至认为Hadoop系统也是高性能的,但所有系统只有在真实场景中对标才会分出性能高低、稳定与否、拓展性如何、实操易用性如何。

和所有其他类型数据库的相同之处是,设计高性能的图数据库至少需要关注3大环节:计算、存储和查询解析与优化

数据库的计算层(或计算组件、计算环节)要解决的问题是,根据查询指令对数据库中存储的数据进行必要的(计算)处理后,返回给请求发起方。具体步骤如下:

1)客户端从数据库服务器端发起查询请求;

2)服务器端收到该查询请求,解析及优化查询指令;

3)从存储引擎读取数据(部分数据可能需要进入内存)​;

4)中央处理器进行相应的计算(各种聚合、排序、过滤等数学运算)​;

5)返回相应的结果。

结合下图,对于一个高性能系统而言,以上5步最核心的是在第3​、4步,即存储层和计算层。本篇内容主要介绍存储环节,计算、查询解析与优化在后面进行介绍。

图1: 数据库管理系统架构分层示意图

1.高性能存储系统的特点

高性能存储系统有3大特点,即存储高效、访问高效和更新高效。

存储高效主要指两个方面:一方面是写入效率高,传统意义上写入可以等同于落盘(持久化在硬盘文件系统上)​,但是随着持久化内存等新技术的出现,​“落盘”这个概念并不准确,读者需要注意区分,写入效率可以体现为TPS(Transactions Per Second)​,即每秒钟写入的记录(或交易笔数)的数量;另一方面是存储这些数据记录(Payload)产生的额外开销小。

关于存储效率,有两个方面在工业界经常被关注:空间换时间和性价比。空间换时间是提升存储效率的一种常见做法,不仅仅是狭义的存储操作,还包括访问、更新等各类操作。NoSQL类型的很多数据库设计理念都采用了用更大存储空间来提升存储引擎时效性的策略,例如使用一些中间过渡的数据结构来实现更高的并发写入性能,即更高的TPS;还有存储放大的情况,例如数据会有多份拷贝,在满足数据安全的同时实现访问效率(避免实时迁移所带来的IO压力)的提升;当然也有一些数据库采用写拷贝(copy-on-write)的方式,通过使用倍增的存储空间来实现并发的读写操作。

在商业化场景中,存储系统的性价比问题也常被关注。在对延时不敏感的场景中就会采用价格低廉的硬件和软件解决方案,反之则会根据业务需求设计高性能、高成本的方案。

访问高效指的是用最小的时耗(或者是最少的操作步数、最低的算法复杂度)来定位并读取需要的数据记录。更新操作的高效性指的是当有记录需要更新或有增量的数据写入或旧记录删除的时候,在存储引擎层面的操作复杂度最低(最小规模的更新、最低数量的更新步骤)​。

存储引擎的复杂度在不同的存储硬件层面上是不同的。内存层面的数据结构的设计复杂度要低于硬盘级的数据结构;而硬盘级的基于固态硬盘(SSD)的数据结构设计和基于磁盘(HDD)的数据结构设计也有很大差异。可以说,没有任何一种针对某一类存储介质优化的存储引擎设计可以普适、泛化到全部其他类的存储介质,通常都会因为存储介质的变化而导致某些读或写性能的大幅改变。这也是存储引擎的架构设计复杂的地方之一。

为了更好地解释存储介质的多样性和复杂性,我们用下图的7层模型示意图帮助分析,理解什么样的存储架构、数据结构的组合可实现高性能的存储(与计算)​。

图2:数据库存储引擎的7层分层示意图

目前,业界掀起一股自2015年前后开始的“存储与计算分离”潮流,这一说法最早是全球存储巨头EMC公司提出的,在逻辑上指的是随着大数据与云计算的蓬勃发展,存储不应仅限于一台机器的本地存储,而应实现存储层与网络层的逻辑分离,也就是说存储资源可以相对独立地(水平)扩展。显然,存储与计算分离隐含的是存储远离计算。

当存储远离计算,即数据在进行计算的时候,它需要经过一个迁移路径才能被CPU所处理,而这个迁移路径的长短有指数级的性能落差,例如在上图中,最下层的网络存储模块中的数据与最上层的CPU中的数据之间有着百万级的性能落差。如果任何一个数据库的查询操作需要触发如此远离CPU的一组网络存储层的操作,那么这个操作的时耗之大可想而知。另一方面,我们不可能把所有数据都堆叠在CPU的缓存层中(尽管理论上这是最低延迟的操作)​,也不太可能把全量数据都压缩在动态内存之内(尽管业界的持久化内存发展有这个趋势)​。

分层存储的逻辑给了我们一个很好的启发,事实上,这是所有数据库都会用到的存储引擎设计逻辑:

·全量数据持久化在“尽可能快的”存储介质上;

·使用内存时采用索引、缓存等快速定位寻址的加速类型的数据结构;

·当内存无法承载后,溢出到持久化层,充分利用持久化层的存储介质访问的特点(区分HDD、SSD、PMEM等)来进行访问加速;

·尽可能利用CPU多核、多线程并发能力;

·尽可能利用数据库查询规律等特征来优化CPU的多级缓存利用率(命中率)​。

最后两点是图计算加速的重要设计思路(传统意义上的数据库存储引擎部分是默认包含计算逻辑的,但是图数据库中有必要把图计算引擎部分作为一个独立的逻辑功能模块介绍,因为在存储与计算分离的大趋势下,计算层有其相对独立的特征)​,我们会在下一篇文章中展开分析。本篇着重分析前三点。

2.高性能存储架构设计思路

存储架构以及核心数据结构的设计思路通常围绕如下4个维度来进行:

·外存与内存使用占比(角色分配及分配比例)​;

·是否利用缓存,如何优化缓存;

·是否进行数据或记录的排序,如何排序;

·是否允许数据或记录的更改(可变性)​,以及如何更改。

先开个头,高性能存储架构设计思路要聊的东西很多、很细,需要另起一篇着重介绍一下。今天先这样,周末继续更。

· END ·

(文/Ricky - HPC高性能计算与存储专家、大数据专家、数据库专家及学者)


http://www.kler.cn/a/416088.html

相关文章:

  • 多线程 03 实现方式
  • 使用Native AOT发布C# dll 提供给C++调用
  • nfc中继测试
  • 多线程+线程池
  • docker-compose 升级
  • python代码示例(读取excel文件,自动播放音频)
  • Zookeeper实现分布式锁、Zookeeper实现配置中心
  • 使用Ansible进行Red Hat Linux自动化运维
  • 基于 SpringBoot 的夕阳红公寓管理系统资源整合与高效利用
  • Python 3 教程第33篇(MySQL - mysql-connector 驱动)
  • 长短期记忆网络 (LSTM) 简介
  • 基于Java Springboot蛋糕商城
  • 开源测试_log4net
  • C语言数据结构——详细讲解《队列》
  • uniapp App端在renderjs层渲染echarts获取不到service层id的问题
  • 数字化转型背景下,高职院校计算机网络应用的革新策略
  • C++算法练习-day49——108.将有序数组转换为二叉搜索树
  • 【人工智能基础】计算机视觉
  • ElementUI:el-drawer实现在父组件区域内打开抽屉组件非全屏
  • git如何创建一次没有修改的commit
  • windows C#-取消任务列表(下)
  • python画图plt.close()一直闪烁
  • webpack5提升打包构建速度(四)
  • 详解 YOLOv5 模型运行参数含义以及设置及在 PyCharm 中的配置方法
  • uniapp首页样式,实现菜单导航结构
  • 【LeetCode热题100】优先级队列