1. MOT 概述
openGauss引入了MOT存储引擎,它是一种事务性行存储,针对多核和大内存服务器进行了优化。MOT完全支持ACID特性,并包括严格的持久性和高可用性支持。
MOT与基于磁盘的普通(堆)表并排创建。MOT的有效设计实现了几乎完全的SQL覆盖,并且支持完整的数据库功能集,如存储过程和自定义函数。
MOT命令的语法与基于磁盘的表的语法相同,并支持大多数标准,如PostgreSQL SQL、DDL和DML命令和功能,如存储过程。只有MOT的创建和删除表语句与openGauss中基于磁盘的表的语句不同。
MOT在高性能(查询和事务延迟)、高可扩展性(吞吐量和并发量)以及高资源利用率(某些程度上节约成本)方面拥有显著优势。
- 低延迟(Low Latency):提供快速的查询和事务响应时间。
- 高吞吐量(High Throughput):支持峰值和持续高用户并发。
- 高资源利用率(High Resource Utilization):充分利用硬件。
使用了MOT的应用程序可以达到普通表2.5到4倍的吞吐量。
所有MOT数据和索引都驻留在内存中,因此内存容量必须能够支撑数据容量,并且还有进一步增长的空间。
MOT是一个持久的数据库,使用永久性存储设备(磁盘/SSD/NVMe驱动器)进行事务日志操作和存储定期检查点。
推荐采用低延迟的存储设备,如配置RAID-1的SSD、NVMe或者任何企业级存储系统。当使用适当的硬件时,数据库事务处理和竞争将成为瓶颈,而非IO。
1.1 内存配置
openGauss数据库和标准Postgres类似,其内存上限是由max_process_memory设置的,该上限在postgresql.conf文件中定义。MOT及其所有组件和线程,都驻留在openGauss进程中。因此,分配给MOT的内存也是在整个openGauss数据库进程的max_process_memory定义的上限内分配。
MOT为自己保留的内存是maxprocess_memory的一部分。可以通过百分比或通过小于max_process_memory的绝对值定义。这个部分在mot.conf配置文件中由
max_process_memory中可以除了被MOT使用的部分之外,必须为Postgres(openGauss)封装留下至少2GB的可用空间。为了确保这一点,MOT在数据库启动过程中会进行如下校验:
(max_mot_global_memory + max_mot_local_memory) + 2GB < max_process_memory
当总内存使用量接近所选内存限制时,MOT不再允许插入额外数据。不再允许额外数据插入的阈值即是MOT最大内存百分比(如上所述,这是一个计算值)。MOT最大内存百分比默认值为90,即90%。尝试添加超过此阈值的额外数据时,会向用户返回错误,并且也会注册到数据库日志文件中。
1.2 全局和本地
MOT使用的内存由两部分组成:
- 全局内存:全局内存是一个长期内存池,包含MOT的数据和索引。它平均分布在NUMA节点,由所有CPU核共享。
- 本地内存:本地内存是用于短期对象的内存池。它的主要使用者是处理事务的会话。这些会话将数据更改存储在专门用于相关特定事务的内存部分(称为事务专用内存)。在提交阶段,数据更改将被移动到全局内存中。内存对象分配以NUMA-local方式执行,以实现尽可能低的延迟。
被释放的对象被放回相关的内存池中。在事务期间尽量少使用操作系统内存分配(malloc)函数,避免不必要的锁和锁存。
这两个内存的分配由专用的min/max_mot_global_memory和min/max_mot_local_memory设置控制。如果MOT全局内存使用量太接近最大值,则MOT会保护自身,不接受新数据。超出此限制的内存分配尝试将被拒绝,并向用户报告错误。
在典型的OLTP工作负载中,平均读写比例为80:20,每个表的MOT内存使用率比基于磁盘的表高60%(包括数据和索引)。
如下统计查询可以确定customer表的数据大小和customer_pkey索引大小:
数据大小:pg_relation_size(’customer’);
索引:pg_relation_size(’customer_pkey’);
2. MOT使用
2.1 授予用户权限
以授予数据库用户对MOT存储引擎的访问权限为例。每个数据库用户仅执行一次,通常在初始配置阶段完成。
要使特定用户能够创建和访问MOT(DDL、DML、SELECT),以下语句只执行一次:
openGauss=# GRANT USAGE ON FOREIGN SERVER mot_server TO omm;
GRANT
openGauss=#
2.2 创建/删除MOT
只有MOT中的创建和删除表语句与openGauss中基于磁盘的表的语句不同。SELECT、DML和DDL的所有其他命令的语法对于MOT表和openGauss基于磁盘的表是一样的。
创建MOT:
openGauss=# create FOREIGN table mot(id int) server mot_server;
ERROR: Cannot create MOT tables while incremental checkpoint is enabled.
openGauss=#
以上语句中:
- 始终使用FOREIGN关键字引用MOT。
- 在创建MOT表时,[server mot_server]部分是可选的,因为MOT是一个集成的引擎,而不是一个独立的服务器。
- openGauss默认开启了增量检查点,无法创建MOT。需要先将enable_incremental_checkpoint设置为off。
[omm@oracle2 ~]$ gs_guc set -N all -I all -c "enable_incremental_checkpoint=off"
The gs_guc run with the following arguments: [gs_guc -N all -I all -c enable_incremental_checkpoint=off set ].
Begin to perform the total nodes: 3.
Popen count is 3, Popen success count is 3, Popen failure count is 0.
Begin to perform gs_guc for datanodes.
Command count is 3, Command success count is 3, Command failure count is 0.
Total instances: 3. Failed instances: 0.
ALL: Success to perform gs_guc!
[omm@oracle2 ~]$ gs_om -t restart
openGauss=# create FOREIGN table mot(id int) server mot_server;
CREATE FOREIGN TABLE
openGauss=# /d mot
Foreign table "public.mot"
Column | Type | Modifiers | FDW Options
--------+---------+-----------+-------------
id | integer | |
Server: mot_server
FDW permition: read/write
删除MOT表:
openGauss=# drop FOREIGN table mot;
DROP FOREIGN TABLE
ALTER TABLE:
支持添加列、删除列和重命名列。
2.3 创建索引
支持标准的PostgreSQL创建和删除索引语句。
openGauss=# create index mot_index1 on mot(id) ;
ERROR: Can't create index on nullable columns
DETAIL: Column id is nullable
这里因为id列是允许空的,所以不能创建索引,创建一个非空列:
openGauss=# create FOREIGN table mot2(id int not null);
CREATE FOREIGN TABLE
openGauss=# create index mot_index1 on mot2(id);
CREATE INDEX
创建一个用于TPC-C的ORDER表,并创建索引:
openGauss=# create FOREIGN table bmsql_oorder (
o_w_id integer not null,
o_d_id integer not null,
o_id integer not null,
o_c_id integer not null,
o_carrier_id integer,
o_ol_cnt integer,
o_all_local integer,
o_entry_d timestamp,
primary key (o_w_id, o_d_id, o_id)
);
openGauss=# create index bmsql_oorder_index1 on bmsql_oorder(o_w_id, o_d_id, o_c_id, o_id) ;
CREATE INDEX
2.4 将磁盘表转换为MOT
2.4.1 操作说明
目前openGauss不支持直接将磁盘表转换为MOT,可以使用gs_dump工具导出数据,然后再利用gs_restore工具导入MOT表。
在转换之前还需要先检查磁盘表的列实际都满足MOT,MOT表有很多列类型不支持,具体不支持的列可以参考官方手册:
如果有不支持特定列,需要先对原磁盘表进行修改,使其仅包含MOT支持的类。
转换过程如下:
- 暂停应用程序活动。
- 使用gs_dump工具将表数据转储到磁盘的物理文件中。请确保使用data only。
- 重命名原始基于磁盘的表。
- 创建同名同模式的MOT。请确保使用创建FOREIGN关键字指定该表为MOT。
- 使用gs_restore将磁盘文件的数据加载/恢复到数据库表中。
- 浏览或手动验证所有原始数据是否正确导入到新的MOT中。
- 恢复应用程序活动。
2.4.2 操作示例
查看原表结构和数据:
openGauss=# /d+ cndba
Table "public.cndba"
Column | Type | Modifiers | Storage | Stats target | Description
---------+------------------------+-----------+----------+--------------+-------------
id | integer | | plain | |
website | character varying(100) | | extended | |
Indexes:
"idx_cndba_id" btree (id) TABLESPACE pg_default
Has OIDs: no
Options: orientation=row, compression=no
openGauss=# select * from cndba limit 5;
id | website
----+----------------------
1 | https://www.cndba.cn
1 | https://www.cndba.cn
2 | https://www.cndba.cn
3 | https://www.cndba.cn
4 | https://www.cndba.cn
(5 rows)
使用gs_dump转储表数据:
[omm@oracle2 ~]$ gs_dump -Fc postgres -a --table cndba -f cndba.dump -p 15500 -U omm -W omm@123456
gs_dump[port='15500'][postgres][2023-05-31 15:24:56]: dump database postgres successfully
gs_dump[port='15500'][postgres][2023-05-31 15:24:56]: total time: 3716 ms
[omm@oracle2 ~]$ ll cndba.dump
-rw------- 1 omm dbgrp 1042 5月 31 15:24 cndba.dump
[omm@oracle2 ~]$
openGauss 逻辑备份与恢复 操作示例
https://www.cndba.cn/dave/article/116549
重命名源表:
openGauss=# alter table cndba rename to cndba2;
ALTER TABLE
创建与源表完全相同的MOT:
openGauss=# create foreign table cndba(id int, website varchar(100));
CREATE FOREIGN TABLE
将源转储数据导入到新MOT中:
[omm@oracle2 ~]$ gs_restore -C -d postgres cndba.dump -p 15500 -U omm -W omm@123456
start restore operation ...
table cndba complete data imported !
Finish reading 3 SQL statements!
end restore operation ...
restore operation successful
total time: 27 ms
[omm@oracle2 ~]$
验证:
openGauss=# /d+ cndba
Foreign table "public.cndba"
Column | Type | Modifiers | FDW Options | Storage | Stats target | Description
---------+------------------------+-----------+-------------+----------+--------------+-------------
id | integer | | | plain | |
website | character varying(100) | collate C | | extended | |
Server: mot_server
FDW permition: read/write
Has OIDs: no
openGauss=# select * from cndba limit 5;
id | website
----+----------------------
1 | https://www.cndba.cn
1 | https://www.cndba.cn
2 | https://www.cndba.cn
3 | https://www.cndba.cn
4 | https://www.cndba.cn
(5 rows)
2.5 监控MOT
查看表和索引大小:
openGauss=# select pg_relation_size('cndba');
pg_relation_size
------------------
40960
(1 row)
openGauss=#
检查MOT全局内存大小,主要是数据和索引:
openGauss=# select * from mot_global_memory_detail();
numa_node | reserved_size | used_size
-----------+---------------+-----------
-1 | 25165824 | 25165824
0 | 25165824 | 25165824
(2 rows)
其中,
1.-1为总内存。
2.0之后的正整数表示NUMA内存节点。
检查MOT本地内存大小,包括会话内存:
openGauss=# select * from mot_local_memory_detail();
numa_node | reserved_size | used_size
-----------+---------------+-----------
-1 | 20971520 | 20971520
0 | 20971520 | 20971520
(2 rows)
会话管理的内存从MOT本地内存中获取。所有活动会话(连接)的内存使用量可以通过以下查询:
openGauss=# select * from mot_session_memory_detail();
sessid | total_size | free_size | used_size
----------------------------+------------+-----------+-----------
0.0 | 6291456 | 3640374 | 2651082
0.0 | 6291456 | 3640374 | 2651082
0.0 | 6291456 | 3640374 | 2651082
1685517610.139921462327040 | 2097152 | 492598 | 1604554
(4 rows)
openGauss=#
其中:
total_size:分配给会话的内存。
free_size:未使用的内存。
used_size:使用中的内存。
DBA可以通过以下查询确定当前会话使用的本地内存状态:
openGauss=# select * from mot_session_memory_detail() where sessid =pg_current_sessionid();
sessid | total_size | free_size | used_size
----------------------------+------------+-----------+-----------
1685517610.139921462327040 | 2097152 | 492598 | 1604554
(1 row)
版权声明:本文为博主原创文章,未经博主允许不得转载。