StoneDB 2.0 调研:架构解析内存引擎详细设计

2023-10-14 04:10

本文主要是介绍StoneDB 2.0 调研:架构解析内存引擎详细设计,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

StoneDB 官方介绍:StoneDB 是一款支持行列混存+内存计算的 HTAP 数据库。其采用完全自主研发的存储和计算引擎,可将 MySQL 的分析性能提高100倍;其创新的一体化 HTAP 架构,打破传统 TP 型数据库能力边界,为用户提供一站式 OLTP+OLAP 解决方案。

一句话概括:StoneDB 一体化实时 HTAP 开源数据库

最近stonedb官方发布了内存引擎详细设计的视频,打算调研一下。

找到了官方发布在b站的视频解说:

StoneDB 2.0 架构解析:内存引擎详细设计(一)_哔哩哔哩_bilibili

 StoneDB 2.0 架构:内存引擎设计(二)_哔哩哔哩_bilibili

stonedb的次引擎

在stonedb1.0之中,只支持基于磁盘的列存引擎 Tianmu。同 InnoDB 角色一样,可以作为 MySQL 的另外一个主引擎。在 StoneDB 2.0 版本中,我们将引入 MySQL 8.0.2 中的新特性:次引擎。

StoneDB 2.0 版本中,将推出基于内存计算的列存引擎,该版本将基于 MySQL 8.0 构建,基于此引擎我们将实现 AP 负载的全内存计算。

使用次引擎的原因?

  1. 次引擎是一个 MySQL 框架,用于提供多引擎的能力。基于通用的接口和框架,MySQL 可以根据每个工作负载的类型将不同的工作负载路由到相应的引擎,发挥其优势以提供优质的服务。次引擎也可以使 MySQL 拥有增强多模能力的机会,例如让 ClickHouse 成为一个次引擎来提供分析服务。
  2. 逻辑上讲,将子任务路由到次引擎,主任务放到主引擎去执行,比较自然能想到。
  3. 业内也有一些样例,Oracle 已经将次引擎的特性用在了它们的在线服务中。比如说MySQL HeatWave: 一个内置机器学习的内存查询加速器。

ps:启用 HeatWave能将分析和混合负载的性能提高几个数量级。启用 HeatWave 后,MySQL HeatWave 比 Amazon Redshift 快 6.5 倍,成本只有一半,比 Snowflake 快 7 倍,成本只有五分之一,比 Amazon Aurora 快 1,400 倍,成本只有一半。客户对存储在 MySQL 数据库中的数据进行分析,无需单独的分析数据库和 ETL 复制。

为什么要使用基于内存的列式引擎?

 首先从当前分析处理系统存在的一些挑战来讲,好的分析查询性能要满足以下几个要求:

  • 了解用户的访问模式
  • 提供良好的性能,通常需要创建索引、物化视图和 OLAP 多维数据集。

 这样比较极端的情况是,对每一列都会创建一个索引,会造成创建索引的空间比表占用空间还要大的一种情况。

 为了提升性能,StoneDB 在 1.0 的版本中使用了基于列的数据格式。列式数据格式以列的形式组织数据,而不是行。

 (使用列存的好处大家可以自行搜索,网上的资料非常之多。)

行存和列存没有孰优孰劣之分,在不同的应用场景中会有不同的表现,具体为"增改查"的区别。 

  • 行存的优势在于写入和修改的效率很高,同时对于每行数据的完整性上具有天生的优势,适用于面向事务型处理的应用场景。
  • 列存的优势在于读取的效率很高,并且可以使用高效的压缩算法来节省储存空间,适用于查询密集型的应用场景

大体上来说使用列存在分析型事务中可以更方便呢的过滤多余数据。

那么问题就是:应用程序要么实现快速分析,要么实现快速交易,但不能同时实现两者。混合工作负载数据库的性能问题并不能通过仅以一种单一格式存储数据来解决。

所以stonedb在2.0中引入了新的引擎,即基于内存列的存储,用于分析工作负载。内存中的基于列的引擎也称Tianmu

stonedb2.0的内存列式引擎Tianmu的概述

 数据在加载到基于列的内存引擎之前会被压缩和编码,但是并非所有类型的数据都适合编码和压缩。

官方给出了基于列的内存引擎的一些简单概述:RFC: Architecture of StoneDB V2.0 · Issue #436 · stoneatom/stonedb · GitHub1 Overview of StoneDB V2.0 2 SQL Syntaxes 3 Massive Parallel Processing 3.1 Data Distribution Approaches 3.2 Redistribution Approaches 3.3 Metadata Management 4 Query Engine 5 Execution Engine 6 In-Memory Column-Based Engine 6.1 Memory O...https://github.com/stoneatom/stonedb/issues/436

也给出了针对于哪些数据类型可以做编码和压缩:https://github.com/stoneatom/stonedb/issues/423icon-default.png?t=M85Bhttps://github.com/stoneatom/stonedb/issues/423

NUMA & MySQL

Linux kerner: What is NUMA?

NUMA(Non Uniform Memory Access)非一致存储访问结构。

 现代cpu是多核,那么核数越多,并发访问竞争越高,要实现内存一致性访问效率就越慢。

 NUMA 的内存分配策略有 localalloc、preferred、membind、interleave四种:

  • localalloc: 进程从当前 node(比如上图整个处理器一分为二,左边为一个node,右边为一个node) 上请求 alloc memory;
  • preferred: 指定一个推荐 node 来获取内存,如果被推荐的 node 上没有足够内存,可以尝试别的 node
  • membind: 可以指定若干个 node,进程只能从这些指定的 node 上请求分配内存
  • interleave: 进程从指定的若干个 node 上以 Round Robin (轮询调度)算法请求分配内存。

MySQL 在 NUMA 架构上会出现的问题,ref from Jeremy Cole

https://blog.jcole.us/2010/09/28/mysql-swap-insanity-and-the-numa-architecture/

A brief update on NUMA and MySQL – Jeremy Cole

结论就是,推荐使用 NUMA 内存分配策略为:numactl --interleave=all

因为MySQL 数据库外部请求随机性强,各个线程访问内存在地址上平均分布,Interleave 的内存分配模式相较默认模式可以带来一定程度的性能提升

mysql buffer pool

 mysql buffer pool是mysql的innodb自带的一个缓冲池。

(关于buffer pool,网上也有一大堆资料可以看)

InnoDB 缓冲池是数 GB 的范围,内存分布在不同的 NUMA 节点中。

而且,cross-NUMA访问是多核系统的性能瓶颈。因此,NUMA 节点中的内存分配算法(或策略)应谨慎选择。

 在 innobase/buf/buf0buf.cc 中,它使用 buf_block_alloc 函数来分配一个缓冲块,并传播到所有 buffer pool 实例。

buf_block_t *buf_block_alloc(buf_pool_t *buf_pool) /*!< in/out: buffer pool instance,or NULL for round-robin selectionof the buffer pool */
{buf_block_t *block;ulint index;static ulint buf_pool_index;if (buf_pool == nullptr) {/* We are allocating memory from any buffer pool, ensurewe spread the grace on all buffer pool instances. */index = buf_pool_index++ % srv_buf_pool_instances;buf_pool = buf_pool_from_array(index);}block = buf_LRU_get_free_block(buf_pool);buf_block_set_state(block, BUF_BLOCK_MEMORY);return (block);
}

在redhat中,numa内存分配策略:NUMA memory allocation policies in RedHat.

 在 MySQL 中,我们建议在 NUMA 架构中使用 interleave 内存分配策略。结构set_numa_interleave_t 用于将内存分配策略设置为MPOL_INTERLEAVE

struct set_numa_interleave_t {
// 构造函数set_numa_interleave_t() {if (srv_numa_interleave) {ib::info(ER_IB_MSG_47) << "Setting NUMA memory policy to"" MPOL_INTERLEAVE";struct bitmask *numa_nodes = numa_get_mems_allowed();if (set_mempolicy(MPOL_INTERLEAVE, numa_nodes->maskp, numa_nodes->size) !=0) {ib::warn(ER_IB_MSG_48) << "Failed to set NUMA memory"" policy to MPOL_INTERLEAVE: "<< strerror(errno);}numa_bitmask_free(numa_nodes);}}// 析构函数~set_numa_interleave_t() {if (srv_numa_interleave) {ib::info(ER_IB_MSG_49) << "Setting NUMA memory policy to"" MPOL_DEFAULT";if (set_mempolicy(MPOL_DEFAULT, nullptr, 0) != 0) {ib::warn(ER_IB_MSG_50) << "Failed to set NUMA memory"" policy to MPOL_DEFAULT: "<< strerror(errno);}}}
};

一般情况下,在 MySQL 中,会创建多个缓冲池实例,由innodb_buffer_pool_instances控制。缓冲池实例的数量应根据缓冲池的大小进行调整。

对于具有数 GB buffer pool 的系统,将 buffer pool 划分为单独的一个个实例,通过减少不同线程读取和写入缓存页面时的争用来提高并发性。

说白了就是在从空间上减少锁的粒度。

 缓冲池大小由 innodb_buffer_pool_size 设置。每个缓冲池实例的大小需要满足:

 size_of_an_instance = innodb_buffer_pool_size / innodb_buffer_pool_instances

 

缓冲池使用了lru的管理。


tianmu引擎

[RFC] Tianmu In-Memory Column Store Engine · Issue #424 · stoneatom/stonedb · GitHub1 Why do we use seconardy engine? 2 Why do we employ an in-memory column-based engine? 3 Overview of In-memory column-based engine, Tianmu 3.1 MySQL Buffer Pool 3.2 MySQL Change Buffer 3.3 MySQL Log Buffer 3.4 Tianmu In-memory engine 3.4...https://github.com/stoneatom/stonedb/issues/424

 tianmu引擎是通过buffer pool划分多个实例来提高并发行的 

图中有多个tianmu节点,空白部分是给bufferpool本身使用的。

所以需要确定两个参数,一个是tianmu引擎本身占用的大小TIANMU_IN_MEM_SIZE;另外一个是占用的百分比TIANMU_IN_MEM_SIZE_PCT。

[mysqld]#configure the mem usage of tianmu in-memory engine
TIANMU_IN_MEM_SIZE = 100GB
TIANMU_IN_MEM_SIZE_PCT = 0.6

比如说tianmu占用60%,那么剩下的40%是给mysql buffer pool使用的。

 

tianmu引擎的内存池(Memory pools in Tianmu in-memory)

内存池的结构中,会划分为两个子分池。

一部分用来存储列数据,一部分用来存储元数据。

元数据和列数据一一对应,(就是fields和data的关系) 

tianmu内存引擎设计

 将会从数据组织和数据加载两个方面来说内存引擎设计这块内容。

1.数据组织

内存布局概述: 

  • IMCU:The column data subpool will be divided into N partition(known as In-memory column-based unit, IMCU),  
  • IMCDP : in-memory column-based data pack(IMCDP or abbrv called Chunk or RowGroup).

 左边是列数据的缓冲池,用来保存数据本身,

整个内存区会被切分成很多块(IMUC),这里和1.0的实现有所不同,1.0是会对每个列做压缩,2.0中每个列还会切割成多个矩阵,每个矩阵也会有单独的元数据管理。

  • DP:datapack 

 

由于dp的header中包含了DP的一些统计信息,比如最大最小值,数量等等,所以可以看做是数据的索引。,可以对DP本身进行过滤。

比如,如果想进行一个sql查询,select * from t where order_id > 100 and order_id < 1000

那么就可以过滤掉IMCDP M的包,留下符合条件的IMCDP N的包。

这样可以很快的过滤出符合条件的数据包。

 每个IMCDP(chunk)是由多个列的数据包组合成的,所有的数据块都是驻扎在内存中的。

header部分会包含元数据的信息。 

 

 IMCU的纵向拆解图如下:

2.数据加载

使用数据加载, 可以将数据从innodb的行存加载到tianmu的内存列引擎中。

 

 设置的隔离级别是RC 。

innodb(TP)数据更新到stoneDB(AP)的时机有三种情况:

  • population Buffer已满
  • 设定的时间已到
  • 查询负载引用到该项数据

此时会将TP变化数据更新到AP之中:

 

 

 并且在加载时,不需要进行全量数据的加载,只需要加载需要使用到的列即可。

所以需要可以选择需要哪些列进行加载。

 与加载相对应,也会有卸载的方法:

 卸载操作也会进行数据的持久化,即刷盘到磁盘之中,这样,之后恢复数据到内存的速度会加快,也会使分层存储系统成为可能。

为了缩短加载时间,stonedb启用了并行加载。利用了mysql8.0的并行扫描功能。

并行使用到的参数是innodb_paraller_read_threads

目前stonedb只给出了存储的组织形式,对于计算引擎如何使用还没有什么资料,大家可以自行看源码。

官网:

StoneDB - A Real-time HTAP Database | StoneDBhttps://stonedb.io/GitHub - stoneatom/stonedb: StoneDB is an open-source, MySQL HTAP and MySQL-native database for oltp, real-time analyticsStoneDB is an open-source, MySQL HTAP and MySQL-native database for oltp, real-time analytics - GitHub - stoneatom/stonedb: StoneDB is an open-source, MySQL HTAP and MySQL-native database for oltp, real-time analyticshttps://github.com/stoneatom/stonedb

 

这篇关于StoneDB 2.0 调研:架构解析内存引擎详细设计的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/208045

相关文章

DeepSeek模型本地部署的详细教程

《DeepSeek模型本地部署的详细教程》DeepSeek作为一款开源且性能强大的大语言模型,提供了灵活的本地部署方案,让用户能够在本地环境中高效运行模型,同时保护数据隐私,在本地成功部署DeepSe... 目录一、环境准备(一)硬件需求(二)软件依赖二、安装Ollama三、下载并部署DeepSeek模型选

Spring IOC控制反转的实现解析

《SpringIOC控制反转的实现解析》:本文主要介绍SpringIOC控制反转的实现,IOC是Spring的核心思想之一,它通过将对象的创建、依赖注入和生命周期管理交给容器来实现解耦,使开发者... 目录1. IOC的基本概念1.1 什么是IOC1.2 IOC与DI的关系2. IOC的设计目标3. IOC

java中的HashSet与 == 和 equals的区别示例解析

《java中的HashSet与==和equals的区别示例解析》HashSet是Java中基于哈希表实现的集合类,特点包括:元素唯一、无序和可包含null,本文给大家介绍java中的HashSe... 目录什么是HashSetHashSet 的主要特点是HashSet 的常用方法hasSet存储为啥是无序的

Linux内存泄露的原因排查和解决方案(内存管理方法)

《Linux内存泄露的原因排查和解决方案(内存管理方法)》文章主要介绍了运维团队在Linux处理LB服务内存暴涨、内存报警问题的过程,从发现问题、排查原因到制定解决方案,并从中学习了Linux内存管理... 目录一、问题二、排查过程三、解决方案四、内存管理方法1)linux内存寻址2)Linux分页机制3)

电脑密码怎么设置? 一文读懂电脑密码的详细指南

《电脑密码怎么设置?一文读懂电脑密码的详细指南》为了保护个人隐私和数据安全,设置电脑密码显得尤为重要,那么,如何在电脑上设置密码呢?详细请看下文介绍... 设置电脑密码是保护个人隐私、数据安全以及系统安全的重要措施,下面以Windows 11系统为例,跟大家分享一下设置电脑密码的具体办php法。Windo

JSON字符串转成java的Map对象详细步骤

《JSON字符串转成java的Map对象详细步骤》:本文主要介绍如何将JSON字符串转换为Java对象的步骤,包括定义Element类、使用Jackson库解析JSON和添加依赖,文中通过代码介绍... 目录步骤 1: 定义 Element 类步骤 2: 使用 Jackson 库解析 jsON步骤 3: 添

将sqlserver数据迁移到mysql的详细步骤记录

《将sqlserver数据迁移到mysql的详细步骤记录》:本文主要介绍将SQLServer数据迁移到MySQL的步骤,包括导出数据、转换数据格式和导入数据,通过示例和工具说明,帮助大家顺利完成... 目录前言一、导出SQL Server 数据二、转换数据格式为mysql兼容格式三、导入数据到MySQL数据

Redis的Zset类型及相关命令详细讲解

《Redis的Zset类型及相关命令详细讲解》:本文主要介绍Redis的Zset类型及相关命令的相关资料,有序集合Zset是一种Redis数据结构,它类似于集合Set,但每个元素都有一个关联的分数... 目录Zset简介ZADDZCARDZCOUNTZRANGEZREVRANGEZRANGEBYSCOREZ

Java循环创建对象内存溢出的解决方法

《Java循环创建对象内存溢出的解决方法》在Java中,如果在循环中不当地创建大量对象而不及时释放内存,很容易导致内存溢出(OutOfMemoryError),所以本文给大家介绍了Java循环创建对象... 目录问题1. 解决方案2. 示例代码2.1 原始版本(可能导致内存溢出)2.2 修改后的版本问题在

大数据小内存排序问题如何巧妙解决

《大数据小内存排序问题如何巧妙解决》文章介绍了大数据小内存排序的三种方法:数据库排序、分治法和位图法,数据库排序简单但速度慢,对设备要求高;分治法高效但实现复杂;位图法可读性差,但存储空间受限... 目录三种方法:方法概要数据库排序(http://www.chinasem.cn对数据库设备要求较高)分治法(常