随笔 - 10  文章 - 0 评论 - 0 trackbacks - 0

上一篇我们知道怎么一步步的安装并部署PostgreSQL,接下来我们就要测试一下在Azure上PostgreSQL可以达成什么样的性能,并且尝试修改数据库的参数,看看怎么优化数据库性能。

对于数据库新手来说,想要做数据库的性能测试遇到的第一个问题就是:我可以用什么测试工具?万幸的是安装了PostgreSQL后,我们可以使用自带的pgbench来进行性能测试。

测试所使用的虚拟机配置如下:

Standard DS4 v2 (8 vcpus, 28 GB memory), 4 X 1023G, 4 X 5000 IOPS, Raid0, 记做 VM-SSD

Standard DS4 v2 (8 vcpus, 28 GB memory), 16 X 128G, 16 X 500 IOPS, Raid0, 记做 VM-HDD

两台虚机放在同一个VNET,有对外发布的公网地址。

 

通过分别测试这两台虚拟机,我们来看看在各种情况下PostgreSQL的性能。

首先建立测试数据库,并创建5000万条的记录:

创建测试数据库

$ createdb pgbench

初始化测试数据库,会创建4张表

$ pgbench -i pgbench

插入5000万条记录

$ pgbench -i -s 500 pgbench

 

第一步测试:PostgreSQL安装部署完成,不作任何优化

 

VM-SSD:

$ pgbench -r -c 16 -j 16 -n -T 180 pgbench

 

transaction type: <builtin: TPC-B (sort of)>

scaling factor: 500

query mode: simple

number of clients: 16

number of threads: 16

duration: 180 s

number of transactions actually processed: 333504

latency average = 8.636 ms

tps = 1852.672083 (including connections establishing)

tps = 1852.742252 (excluding connections establishing)

script statistics:

 - statement latencies in milliseconds:

         0.002  \set aid random(1, 100000 * :scale)

         0.001  \set bid random(1, 1 * :scale)

         0.001  \set tid random(1, 10 * :scale)

         0.000  \set delta random(-5000, 5000)

         0.071  BEGIN;

         0.248  UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE a id = :aid;

         0.150  SELECT abalance FROM pgbench_accounts WHERE aid = :aid;

         0.171  UPDATE pgbench_tellers SET tbalance = tbalance + :delta WHERE tid = :tid;

         0.265  UPDATE pgbench_branches SET bbalance = bbalance + :delta WHERE bid = :bid;

         0.117  INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP);

         7.607  END;

 

VM-HDD:

$ pgbench -r -c 16 -j 16 -n -T 180 pgbench

 

transaction type: <builtin: TPC-B (sort of)>

scaling factor: 500

query mode: simple

number of clients: 16

number of threads: 16

duration: 180 s

number of transactions actually processed: 223638

latency average = 12.879 ms

tps = 1242.328936 (including connections establishing)

tps = 1242.365821 (excluding connections establishing)

script statistics:

 - statement latencies in milliseconds:

         0.002  \set aid random(1, 100000 * :scale)

         0.001  \set bid random(1, 1 * :scale)

         0.001  \set tid random(1, 10 * :scale)

         0.000  \set delta random(-5000, 5000)

         0.070  BEGIN;

         0.250  UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid;

         0.150  SELECT abalance FROM pgbench_accounts WHERE aid = :aid;

         0.174  UPDATE pgbench_tellers SET tbalance = tbalance + :delta WHERE tid = :tid;

         0.331  UPDATE pgbench_branches SET bbalance = bbalance + :delta WHERE bid = :bid;

         0.116  INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP);

        11.679  END;

 

可以看到使用SSD的虚机比使用HDD的虚机下性能好了接近50%,时延也差了近50%,差距还是很明显的。

 

第二步测试:优化PostgreSQL参数

修改数据库目录下的postgresql.conf文件

max_connections = 2000

shared_buffers = 4GB

temp_buffers = 2GB 

max_prepared_transactions = 2000

work_mem = 512MB            

maintenance_work_mem = 2GB

 

我们来挨个解释下这几个参数的含义:

max_connections : 决定和数据库连接的并发连接数目的最大值。 缺省通常是 100,但是如果你的内核设置不支持这么大(在 initdb 的时候判断),可能会比这个数少。这个参数的上限收到操作系统并发连接数的限制。修改本参数需要重启PostgreSQL服务。

shared_buffers:这是最重要的参数,postgresql对数据操作时都要先将数据从磁盘读取到内存中,然后进行更新,最后再将数据写回磁盘。因此应该尽量大,让更多的数据缓存在shared_buffers中。按照文档建议设置范围一般在实际内存的25%~40%之间。修改本参数需要重启PostgreSQL服务。

temp_buffers:临时缓冲区,用于数据库会话访问临时表数据,系统默认值为8M。可以在单独的session中对该参数进行设置,尤其是需要访问比较大的临时表时,将会有显著的性能提升。

max_prepared_transactions :设置可以同时处于"准备好"状态的事务的最大数目。 把这个参数设置为零则关闭准备好的事务的特性。max_prepared_transactions 设置成至少和 max_connections 一样大, 以避免在准备步骤的失败。 修改本参数需要重启PostgreSQL服务。

work_mem:工作内存或者操作内存。负责内部的sort和hash操作,合适的work_mem大小能够保证这些操作在内存中进行。定义太小的话,sort或者hash操作将需要与硬盘进行swap,这样会极大的降低系统的性能;太大的话致使在能够在内存中完成的操作数量减少,其他的部分需要与磁盘进行swap操作,增加IO降低性能。系统提供的默认值是1M,在实际的生产环境中,要对系统监控数据进行分析,作出最好的选择。对于work_mem内存分配时还要考虑数据库的并发情况,不论如何调整work_mem都要考虑max_connections*work_mem+shared_buffers+temp_buffers+maintenance_work_mem+操作系统所需内存不能够超过整个的RAM大小

maintenance_work_mem:维护工作内存,主要是针对数据库的维护操作或者语句。尽量的将这些操作在内存中进行。主要针对VACUUM,CREATE INDEX,REINDEX等操作。

 

可以看到修改的这几个参数的主要目的就是尽可能将所有的数据库和操作放在内存里进行,通过这种方式来提高性能。

 

经过参数调整,得到测试结果如下:

VM-SSD

$ pgbench -r -c 16 -j 16 -n -T 180 pgbench

 

transaction type: <builtin: TPC-B (sort of)>

scaling factor: 500

query mode: simple

number of clients: 16

number of threads: 16

duration: 180 s

number of transactions actually processed: 457226

latency average = 6.300 ms

tps = 2539.724092 (including connections establishing)

tps = 2539.832161 (excluding connections establishing)

script statistics:

 - statement latencies in milliseconds:

         0.002  \set aid random(1, 100000 * :scale)

         0.001  \set bid random(1, 1 * :scale)

         0.001  \set tid random(1, 10 * :scale)

         0.001  \set delta random(-5000, 5000)

         0.077  BEGIN;

         0.204  UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid;

         0.155  SELECT abalance FROM pgbench_accounts WHERE aid = :aid;

         0.168  UPDATE pgbench_tellers SET tbalance = tbalance + :delta WHERE tid = :tid;

         0.231  UPDATE pgbench_branches SET bbalance = bbalance + :delta WHERE bid = :bid;

         0.120  INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP);

         5.340  END;

 

VM-HDD

$ pgbench -r -c 16 -j 16 -n -T 180 pgbench

 

transaction type: <builtin: TPC-B (sort of)>

scaling factor: 500

query mode: simple

number of clients: 16

number of threads: 16

duration: 180 s

number of transactions actually processed: 313329

latency average = 9.193 ms

tps = 1740.403152 (including connections establishing)

tps = 1740.455620 (excluding connections establishing)

script statistics:

 - statement latencies in milliseconds:

         0.002  \set aid random(1, 100000 * :scale)

         0.001  \set bid random(1, 1 * :scale)

         0.001  \set tid random(1, 10 * :scale)

         0.000  \set delta random(-5000, 5000)

         0.073  BEGIN;

         0.195  UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid;

         0.155  SELECT abalance FROM pgbench_accounts WHERE aid = :aid;

         0.169  UPDATE pgbench_tellers SET tbalance = tbalance + :delta WHERE tid = :tid;

         0.273  UPDATE pgbench_branches SET bbalance = bbalance + :delta WHERE bid = :bid;

         0.118  INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP);

         8.208  END;

 

可以看到,经过参数优化,性能有了明显的提高,不过基于SSD的虚机性能还是远远好于基于HDD的虚机

 

第三步测试:Client/Server模式测试

之前的测试都是在虚拟机上,测试本机的性能。实际工作中,Client通常和数据库不在同一台服务器上,所以接下来就要测试下通过网络访问的性能。

上一篇说过,安装部署好的PostgreSQL默认只有本机可以访问,因此在开始测试前,先要配置允许对外服务,而且出于安全考虑,只有指定的IP地址可以访问数据库。

修改postgresql.conf, 设置监听地址为所有地址:listen_addresses = '0.0.0.0'

修改pg_hba.conf,按提示的格式设置允许访问的IP地址,注意要加上掩码。

设置完成后重启PostgreSQL服务,开始测试。

 

首先测试通过VNET内网地址互相访问的结果。

VM-SSD 作为Client访问VM-HDD private address

$ pgbench -h 10.3.0.5 -p 1999 -r -c 16 -j 16 -n -T 180 pgbench

 

transaction type: <builtin: TPC-B (sort of)>

scaling factor: 500

query mode: simple

number of clients: 16

number of threads: 16

duration: 180 s

number of transactions actually processed: 340623

latency average = 8.456 ms

tps = 1892.056710 (including connections establishing)

tps = 1892.119631 (excluding connections establishing)

script statistics:

 - statement latencies in milliseconds:

         0.002  \set aid random(1, 100000 * :scale)

         0.001  \set bid random(1, 1 * :scale)

         0.001  \set tid random(1, 10 * :scale)

         0.001  \set delta random(-5000, 5000)

         0.308  BEGIN;

         0.432  UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid;

         0.335  SELECT abalance FROM pgbench_accounts WHERE aid = :aid;

         0.348  UPDATE pgbench_tellers SET tbalance = tbalance + :delta WHERE tid = :tid;

         0.412  UPDATE pgbench_branches SET bbalance = bbalance + :delta WHERE bid = :bid;

         0.290  INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP);

         6.329  END;

 

此时从VM-SDD ping VM-HDD的时延为:

64 bytes from 10.3.0.5: icmp_seq=1 ttl=64 time=0.459 ms

64 bytes from 10.3.0.5: icmp_seq=2 ttl=64 time=0.447 ms

64 bytes from 10.3.0.5: icmp_seq=3 ttl=64 time=0.226 ms

64 bytes from 10.3.0.5: icmp_seq=4 ttl=64 time=0.231 ms

64 bytes from 10.3.0.5: icmp_seq=5 ttl=64 time=0.264 ms

64 bytes from 10.3.0.5: icmp_seq=6 ttl=64 time=0.300 ms

64 bytes from 10.3.0.5: icmp_seq=7 ttl=64 time=0.260 ms

64 bytes from 10.3.0.5: icmp_seq=8 ttl=64 time=0.302 ms

64 bytes from 10.3.0.5: icmp_seq=9 ttl=64 time=0.226 ms

 

 

VM-HDD 作为Client访问VM-SSD private address

$ pgbench -h 10.3.0.4 -p 1999 -r -c 16 -j 16 -n -T 180 pgbench

 

transaction type: <builtin: TPC-B (sort of)>

scaling factor: 500

query mode: simple

number of clients: 16

number of threads: 16

duration: 180 s

number of transactions actually processed: 429534

latency average = 6.708 ms

tps = 2385.353651 (including connections establishing)

tps = 2385.425889 (excluding connections establishing)

script statistics:

 - statement latencies in milliseconds:

         0.002  \set aid random(1, 100000 * :scale)

         0.001  \set bid random(1, 1 * :scale)

         0.001  \set tid random(1, 10 * :scale)

         0.001  \set delta random(-5000, 5000)

         0.294  BEGIN;

         0.442  UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid;

         0.336  SELECT abalance FROM pgbench_accounts WHERE aid = :aid;

         0.349  UPDATE pgbench_tellers SET tbalance = tbalance + :delta WHERE tid = :tid;

         0.391  UPDATE pgbench_branches SET bbalance = bbalance + :delta WHERE bid = :bid;

         0.289  INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP);

         4.599  END;

 

此时从VM-SDD ping VM-HDD的时延为:

64 bytes from 10.3.0.4: icmp_seq=1 ttl=64 time=0.228 ms

64 bytes from 10.3.0.4: icmp_seq=2 ttl=64 time=0.219 ms

64 bytes from 10.3.0.4: icmp_seq=3 ttl=64 time=0.240 ms

64 bytes from 10.3.0.4: icmp_seq=4 ttl=64 time=0.353 ms

64 bytes from 10.3.0.4: icmp_seq=5 ttl=64 time=0.445 ms

64 bytes from 10.3.0.4: icmp_seq=6 ttl=64 time=0.278 ms

64 bytes from 10.3.0.4: icmp_seq=7 ttl=64 time=0.407 ms

64 bytes from 10.3.0.4: icmp_seq=8 ttl=64 time=0.196 ms

64 bytes from 10.3.0.4: icmp_seq=9 ttl=64 time=0.271 ms

 

从VNET内部访问的性能已经知道了,那么如果用公网地址互访的结果会怎么样呢?

 

VM-SSD 访问 VM-HDD public address

$ pgbench -h 139.219.110.250 -p 1999 -r -c 16 -j 16 -n -T 180 pgbench

 

transaction type: <builtin: TPC-B (sort of)>

scaling factor: 500

query mode: simple

number of clients: 16

number of threads: 16

duration: 180 s

number of transactions actually processed: 353836

latency average = 8.141 ms

tps = 1965.306199 (including connections establishing)

tps = 1965.368417 (excluding connections establishing)

script statistics:

 - statement latencies in milliseconds:

         0.002  \set aid random(1, 100000 * :scale)

         0.001  \set bid random(1, 1 * :scale)

         0.001  \set tid random(1, 10 * :scale)

         0.001  \set delta random(-5000, 5000)

         0.312  BEGIN;

         0.446  UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid;

         0.340  SELECT abalance FROM pgbench_accounts WHERE aid = :aid;

         0.351  UPDATE pgbench_tellers SET tbalance = tbalance + :delta WHERE tid = :tid;

         0.413  UPDATE pgbench_branches SET bbalance = bbalance + :delta WHERE bid = :bid;

         0.292  INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP);

         5.985  END;

 

VM-HDD 访问 VM-SSD public address

$ pgbench -h 139.219.96.68 -p 1999 -r -c 16 -j 16 -n -T 180 pgbench

 

transaction type: <builtin: TPC-B (sort of)>

scaling factor: 500

query mode: simple

number of clients: 16

number of threads: 16

duration: 180 s

number of transactions actually processed: 433479

latency average = 6.646 ms

tps = 2407.470097 (including connections establishing)

tps = 2407.548375 (excluding connections establishing)

script statistics:

 - statement latencies in milliseconds:

         0.002  \set aid random(1, 100000 * :scale)

         0.001  \set bid random(1, 1 * :scale)

         0.001  \set tid random(1, 10 * :scale)

         0.001  \set delta random(-5000, 5000)

         0.291  BEGIN;

         0.431  UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid;

         0.331  SELECT abalance FROM pgbench_accounts WHERE aid = :aid;

         0.344  UPDATE pgbench_tellers SET tbalance = tbalance + :delta WHERE tid = :tid;

         0.385  UPDATE pgbench_branches SET bbalance = bbalance + :delta WHERE bid = :bid;

         0.287  INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP);

         4.570  END;

 

总结测试结果如下表:

 

VM-SSD未优化

VM-HDD未优化

VM-SSD优化

VM-HDD优化

SSD to HDD Private IP

HDD to SSD Private IP

SSD to HDD Public IP

HDD to SSD Private IP

latency average

8.636 ms

12.879 ms

6.300 ms

9.193 ms

8.456 ms

6.708 ms

8.141 ms

6.646 ms

tps

1852

1242

2539

1740

1892

2385

1965

2407

 

其实仔细阅读了postgresql的文档后,可以发现work_mem是十分重要的一个参数,系统提供的默认值是1M,在实际的生产环境中,需要对系统监控数据进行分析,作出最好的选择。推荐使用以下两种方式:估计方法与计算方法。

第一种是可以根据业务量的大小和类型,一般语句运行时间,来粗略的估计一下。第二种方式是通过对数据库的监控,数据采集,然后计算其大小。总之合适的大小对系统的性能至关重要。
在实际的维护中可以通过explain analyze分析语句的work_mem大小是否合适。在语句中设置work_mem参数的大小可以充分利用内存,提高语句的执行效率。

work_mem参数对系统的性能是如此的重要,让其实时的适应数据库的运行状况显的不太可能,但是可以通过对数据库运行周期的监控,总结相应的数据,然后定制一个专用的脚本,专门用来修改work_mem的大小,使其阶段性的更加适应系统的状况,不失为一种好的方法。

 

最后补充一点,如果禁用 synchronous_commit参数,性能会有惊人的提高,不过这样关闭了日志的实时同步,虽然对性能有极大的提高,但是可能会造成数据库在意外时无法保持数据一致性,因此并不建议修改这个参数。

$ pgbench -r -c 16 -j 16 -n -T 180 pgbench

 

transaction type: <builtin: TPC-B (sort of)>

scaling factor: 500

query mode: simple

number of clients: 16

number of threads: 16

duration: 180 s

number of transactions actually processed: 1667171

latency average = 1.728 ms

tps = 9260.473969 (including connections establishing)

tps = 9260.967802 (excluding connections establishing)

script statistics:

 - statement latencies in milliseconds:

         0.002  \set aid random(1, 100000 * :scale)

         0.001  \set bid random(1, 1 * :scale)

         0.001  \set tid random(1, 10 * :scale)

         0.001  \set delta random(-5000, 5000)

         0.064  BEGIN;

         0.209  UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid;

         0.252  SELECT abalance FROM pgbench_accounts WHERE aid = :aid;

         0.315  UPDATE pgbench_tellers SET tbalance = tbalance + :delta WHERE tid = :tid;

         0.411  UPDATE pgbench_branches SET bbalance = bbalance + :delta WHERE bid = :bid;

         0.317  INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP);

         0.148  END;

 

posted on 2017-10-03 21:15 johntoo 阅读(...) 评论(...) 编辑 收藏