当前位置: 代码迷 >> 综合 >> MMAP vs POSIX:PostgreSQL动态共享内存
  详细解决方案

MMAP vs POSIX:PostgreSQL动态共享内存

热度:90   发布时间:2024-02-28 06:56:52.0
[postgres@stagdb pg_dynshmem]$ ls -lrt
total 8
-rw------- 1 postgres postgres 6928 Feb 17 16:36 mmap.2106693104
[postgres@stagdb pg_dynshmem]$ pwd
/u01/pgsql/10/pg_dynshmem

PostgreSQL数据目录下的pg_dynshmem子目录中有这样一个文件。

那么,这个文件是干嘛的呢?

在我们解答这个问题之前,我们将必须了解一些基础知识。如果你想从实践上快速理解这些内容,那么我强烈建议你先掌握好这些理论知识。

1、PostgreSQL动态共享内存类型

PostgreSQL支持以下动态共享内存类型:

  1. posix
  2. sysv
  3. windows
  4. mmap

1.1、什么是进程,什么是进程间通信(IPC)?

进程是实现某件事的一系列动作或步骤。

系统内的进程可以是独立的也可以是合作的。如果该进程是独立的,则不受其他进程的执行的影响;另一方面,如果该进程是协作的,则可能会受到其他进程的影响。

进程间通信是一种允许进程相互通信并同步其动作的机制。

Linux内核提供了不同类型的IPC机制,其中PostgreSQL使用System V或POSIX IPC或MMAP机制。

PostgreSQL的共享缓冲区便是使用上述机制之一来缓存其页面。

1.2、共享内存如何工作?

当一个进程的数据需要与另一个进程共享时,第一个进程只是将数据写入共享内存段。

一旦写入,数据将可用于第二个进程。

创建共享内存对象后,有权访问该对象的进程可以使用指针直接对其进行读写。

1.3、为什么要动态共享内存控制段?

正如我们所讨论的,PostgreSQL支持四种动态共享内存类型,但是由于我们这里使用的是Linux操作系统,因此我们的讨论仅限于POSIX和MMAP,而POSIX是SYS V的较新版本。

创建和管理动态共享内存是操作系统的任务。

  1. 动态共享内存段需要进行引用计数,以便在删除最后一个映射后,该段会自动消失。
  2. 如果backend进程被恶意终止,则postmaster进程需要在崩溃并重新启动的过程中删除所有剩余的段,就像它需要重新初始化主共享内存段一样。
  3. 而且,如果所有进程都被异常终止,那么下一次postmaster进程启动则需要清理仍然存在的所有段,就像我们对主共享内存段所做的一样。

注意:POSIX和MMAP都不会跟踪这些详细信息。

因此,我们需要自己去跟踪这些未完成的。
确保在那里有必要的后端和段的映射。

为了解决上述的难题,PostgreSQL致力于实现一个称为“动态共享内存控制段”的概念。

2、动态共享内存控制段

动态共享内存控制段是在启动(或重新初始化)时由postmaster进程在创建任何用户进程之前创建的。它用于存储我们拥有的所有其他动态共享内存段的标识列表以及每个段的引用计数。

动态共享内存控制段负责执行以下操作:

  1. 如果postmaster进程经历崩溃和重置周期,它将扫描控制段并删除其中提到的所有其他段,然后重新创建控制段本身。
  2. 如果postmaster进程被kill(例如kill -9)并重新启动,它将找到旧的控制段并继续进行类似的操作。
  3. 如果整个操作系统重新启动,则旧的控制段将不复存在,除非在mmap-a-regular-file实施下,该实现通过扫描相关目录而不是依靠控制段来进行清理。

总而言之,因此,在四种不同的情况下,我们将删除共享内存段:

  • 资源所有者自己清理。
  • backend进程exit(用于任何 session-lifespan映射以及其他任何可穿越漏洞的映射),
  • postmaster进程exit(防止其子进程死亡后不清理自己),
  • postmaster进程启动时(以防postmaster进程死后不清理)。

3、实例

3.1、当dynamic_shared_memory_type为MMAP时,动态共享内存控制段存储在哪里?

确保你的dynamic_shared_memory_type为mmap。如果没有在postgresql.conf文件中设置它,那么可以使用下面的命令去修改:

alter system set dynamic_shared_memory_type=’mmap’;
postgres=# alter system set dynamic_shared_memory_type='mmap';
ALTER SYSTEMpostgres=# select name, setting from pg_settings where name like 'dynamic_shared_memory_type';
name | setting
----------------------------+---------
dynamic_shared_memory_type | mmap
(1 row)

重启PostgreSQL集群:

/usr/local/pgsql_10/bin/pg_ctl stop -D /u01/pgsql/10

重新启动群集后,您可以看到文件mmap.345067392,这就是你的动态共享内存控制段

[postgres@stagdb pg_dynshmem]$ ls -lrt
total 56
-rw------- 1 postgres postgres 50128 Feb 17 21:38 mmap.345067392

[postgres@stagdb pg_dynshmem]$ pwd /u01/pgsql/10/pg_dynshmem [postgres@stagdb pg_dynshmem]$

告警日志信息如下:
2020-02-17 21:38:30.463 IST [4831] DEBUG: dynamic shared memory system will support 2088 segments
2020-02-17 21:38:30.463 IST [4831] DEBUG: created dynamic shared memory control segment 345067392 (50128 bytes)

让我们再重启数据库,可以看到:
2020-02-17 21:43:09.920 IST [4831] DEBUG: cleaning up dynamic shared memory control segment with ID 345067392
….
2020-02-17 21:43:10.129 IST [4953] DEBUG: dynamic shared memory system will support 2088 segments
2020-02-17 21:43:10.138 IST [4953] DEBUG: created dynamic shared memory control segment 1230606383 (50128 bytes)

注意:正常关闭会清除动态共享内存控制段,并在下次启动时会创建一个新的段。

[postgres@stagdb pg_dynshmem]$ ls -rlt mmap.1230606383
-rw——- 1 postgres postgres 50128 Feb 17 21:43 mmap.1230606383

当我删除文件并停止集群时,出现以下错误:
2020-02-17 21:49:16.698 IST [4953] LOG: could not remove shared memory segment “pg_dynshmem/mmap.1230606383”: No such file or directory

因此pg_dynshmem下的文件称为动态共享内存控制段。

3.2、当我的dynamic_shared_memory_type为POSIX时,我的动态共享内存控制段存储在哪里?

如果动态共享内存段类型为POSIX,则动态共享内存控制段存储在/ dev / shm目录下:
[postgres@stagdb 10]$ cd /dev/shm/
[postgres@stagdb shm]$ ls -rlt
total 60
-rw------- 1 postgres postgres 50128 Feb 17 21:52 PostgreSQL.659433638
[postgres@stagdb shm]$ pwd
/dev/shm]$

通常在任何平台上都不建议使用mmap选项,因为操作系统可能会反复将修改后的页面写回到磁盘上,从而增加系统I / O负载。

但是,当pg_dynshmem目录存储在RAM磁盘上或其他共享内存功能不可用时,它可能对调试很有用。

4、动态共享内存类型–benchmark测试

以下基准测试清楚地表明POSIX的性能优于MMAP。
在这里插入图片描述

在这里插入图片描述

上述基准测试的设置:

  • RAM : 12 GB
  • DISK : HDD
  • CPU : 8
  • SHARED BUFFERS : 128 MB
  • TABLES: pgbench_accounts(260 MB), pgbench_branches (168 kB),
    pgbench_history (0 bytes), pgbench_tellers (744 kB)

使用脚本如下:

#!/bin/sh
for clients in 2 4 6 8 10
do
THREADS=${
    clients}
/usr/local/pgsql_10/bin/pgbench -h 127.0.0.1 -j ${
    THREADS} -c ${
    clients} -T 20 -S postgres 
> result_mmap${
    clients}.txt
done
  相关解决方案