内存表空间的真相和谎言

来自 PostgreSQL wiki
跳转至导航跳转至搜索

作者:Emanuel Calvo Franco

RAM 中的表空间(Linux)

感谢 Jose Vazquez 的合作。

此文章将随时变更

现在,“内存数据库”这个术语的使用频率很高。虽然存在采用这种工作方式的 Postgres 版本(FastDb 就是其中之一),但是使用一台小型服务器进行测试可能很有趣。

在本文中,我们将展示如何以基本且实用的方式进行操作以及一些结果。需要注意的是,这些测试都是在虚拟机上进行的,因此在其他专门的环境中可能会差异很大。

在一般情况下,这种设置(依我的经验)都会出现在 OLAP 服务器中,因为它们需要强大的处理能力。此外,它们通常是与数据集群分开的服务器,因此它们被用作复制的从属服务器,其数据在突然关机情况下可以轻松恢复。

在某种程度上,此技术允许使用表空间、物化视图等对象来占用该空间。

首先,为了简化操作,我们必须向内核发送一个参数来指定内存中磁盘的大小。在本例中,我们将其设置为 4 GB,但是为了让操作更加轻松,我们希望将其设置为更小的值(2 或 1 GB)

kernel /vmlinuz-2.6.28-13-server root=UUID=5ac65858-cdf5-4c26-8557-220563f52901 ro quiet splash ramdisk_size=4194304

如果希望永久保留此设置,我们可以触及 sysctl.conf

kernel.ramdisk_size=4194304

在操作系统启动时,从 shell 执行

mke2fs /dev/ram0
mkdir /mnt/ram0
mount /dev/ram0 /mnt/ram0
mkdir /mnt/ram0/pgspace
chown postgres:postgres /mnt/ram0/pgspace

使用上述命令,我们在 RAM 中格式化了一个空间,并将它挂载到分区表中的一个目录中。需要注意的是,这里我们使用的是 ext2 格式化工具。根据情况,可以使用其他分区。

现在,我们需要操作数据库

ubuntu=# CREATE TABLESPACE ram_space LOCATION '/mnt/ram0/pgspace';
CREATE TABLESPACE
ubuntu=# create table test_ram (i integer, name text) tablespace ram_space;
CREATE TABLE
ubuntu=# create temp table test_ram_temp (i integer, name text) tablespace ram_space;
CREATE TABLE
ubuntu=# create temp table test_disk_temp (i integer, name text);
CREATE TABLE
ubuntu=# create table test_disk (i integer, name text);
CREATE TABLE

我们在该目录中创建了一个表空间,然后在两个可组合的位置中创建了两个类型的表:临时-标准备在内存-磁盘中。


我们来看看部分结果

ubuntu=# explain analyze insert into test_ram values (generate_series(1,1000000),random()::text);
                                         QUERY PLAN                                          
---------------------------------------------------------------------------------------------
 Result  (cost=0.00..0.02 rows=1 width=0) (actual time=0.019..9354.014 rows=1000000 loops=1)
 Total runtime: 22836.532 ms
(2 rows)


ubuntu=# explain analyze insert into test_ram_temp values (generate_series(1,1000000),random()::text);
                                         QUERY PLAN                                          
---------------------------------------------------------------------------------------------
 Result  (cost=0.00..0.02 rows=1 width=0) (actual time=0.025..7507.349 rows=1000000 loops=1)
 Total runtime: 12773.371 ms
(2 rows)


ubuntu=# explain analyze insert into test_disk values (generate_series(1,1000000),random()::text); 
                                        QUERY PLAN                                          
---------------------------------------------------------------------------------------------
 Result  (cost=0.00..0.02 rows=1 width=0) (actual time=0.025..7948.205 rows=1000000 loops=1)
 Total runtime: 16902.042 ms
(2 rows)

ubuntu=# explain analyze insert into test_disk_temp values (generate_series(1,1000000),random()::text);
                                         QUERY PLAN                                          
---------------------------------------------------------------------------------------------
 Result  (cost=0.00..0.02 rows=1 width=0) (actual time=0.018..8135.287 rows=1000000 loops=1)
 Total runtime: 13716.049 ms
(2 rows)

我们所做的是,插入一个与生成随机数相加的序列,并将其转换为文本。在此类小型测试中,我们插入了 1,000,000 条记录(数量不可小视!)。


我们来看一下摘要

RAM 中的标准表:22836.532 磁盘中的标准表:16902.042

RAM 中的临时表:12773.371 磁盘中的临时表:13716.049

在你的机器上,结果可能会不同。在本案例中,我使用了一个装有 PGLive(Pgsql 8.3.5)的虚拟机 (VBox) 运行的。

构想

乍一看,我们发现在处理表类型时存在差异(不管它位于何处)。在进行选择时,这可能是一个决定性因素。

也许可以将此类操作与内存中的物化视图以及临时类型结合起来。

需要考虑的另一件事是,记住当启动操作系统时,它会删除表空间的内容,因此此类技术仅在使用临时表时才有效。即使我们可以从这些表更新到磁盘中的表,但这种工作系统也不一致,因此始终建议先刻录到磁盘,然后更新到内存中。

构想 2

但是,http://www.linux.com/feature/142658 中提出了一种办法,那就是使用 SSD 来存储索引。

这更加有条理,并且并不是什么新鲜事,因为人们往往倾向于使用更快的媒体来存储索引。此外,就本文而言,如果供电突然中断或服务器当机,我们唯一需要做的事情就是重新建立索引。

就引用的本文而言,此文建议使用 XFS 来存储索引。我认为应该使用我们操作系统支持的最轻量级文件系统,因为我们寻求的是速度,而不是安全性

我们可以这样创建内存(或在钢笔或 SSD 中创建)中的索引:

create index indice_ on tabla_ ( i ) tablespace ram_space;


构想 3

其他构想包括使用钢笔驱动器来存储 WAL。这可以通过一个相对简单的操作来实现,即创建一个名为 pg_xlog 的符号链接,并指向相关设备(我们可以在 PGDATA 中找到此目录)。将原装 pg_xlog 的内容复制到钢笔驱动器中(或移动过去),创建该链接,然后就完成了。


此构想与内存中的表空间非常相似,但与 WAL 一起执行的巨大差异在于这样做很危险。WAL 中的损坏可能会产生各种问题,因此服务器当机将使得我们无法使用 WAL!(除非我们拥有一个同步备份)。


为了解决钢笔驱动器可能造成的潜在不稳定性(可能是因为钢笔驱动器较为脆弱,或者可能因任何原因导致 WAL 丢失),我们需要将钢笔中的内容同步到另一块磁盘中。这样,Postgres 服务器就可以写入到钢笔中,但操作系统会对内容执行备份操作。

对于 WAL,我们需要至少一个带日志的文件系统(例如 ext3)。

第 4 个观点

我们正在与 AOSUG 社区(开放 Solaris - www.aosug.com.ar)合作,研究如何使用 ZFS 来管理内存存储设备。有了这种方式,将增加许多非常有用的特性。