使用SysBench测试PostgreSQL并发访问性能

本文使用SysBench测试PostgreSQL服务在不同并发线程数下的性能表现。

一、环境信息

被测服务器(192.168.132.167):

  • 4核8线程,32GB,1TB 7200转机械硬盘
  • CentOS 7.9
  • PostgreSQL 9.6.2

测试客户端(192.168.130.152):

  • 4核8线程,32GB,2TB 7200转机械硬盘
  • CentOS 7.9
  • SysBench 1.0.17

网络:

  • 千兆以太局域网

二、测试综合性能

为了测试不同参数下数据库的性能表现,我们通常会将测试过程写成shell脚本循环执行。由于性能测试的时间可能很长,我们用tee命令将每次测试的结果保存到文件以免丢失数据。

我们用下面的脚本测试在不同线程数下的综合性能(oltp_read_write)。

#!/bin/sh
pg_host=192.168.132.167
pg_port=5432
pg_user=sbtest
pg_password=password
pg_db=sbtest

for ((threads=5; threads<=160; threads=threads+5));do
    sysbench oltp_read_write \
    --pgsql-host=$pg_host --pgsql-port=$pg_port \
    --pgsql-user=$pg_user --pgsql-password=$pg_password \
    --pgsql-db=$pg_db \
    --table_size=100000 --tables=12 \
    prepare

    sysbench oltp_read_write \
    --pgsql-host=$pg_host --pgsql-port=$pg_port \
    --pgsql-user=$pg_user --pgsql-password=$pg_password \
    --pgsql-db=$pg_db \
    --report-interval=5 \
    --table_size=100000 --tables=12 \
    --threads=$threads \
    --time=30 \
    run | tee -a result.txt 2>&1

    sysbench oltp_read_write \
    --pgsql-host=$pg_host --pgsql-port=$pg_port \
    --pgsql-user=$pg_user --pgsql-password=$pg_password \
    --pgsql-db=$pg_db \
    --tables=12 \
    cleanup
done

上面测试脚本的结果保存在result.txt文件里,使用下面的命令可以获取到所需的数据项,方便粘贴到excel表格里画图:

获取平均QPS值(考虑到超过100000的情况因此用两个cut实现):
cat result.txt |grep queries:|cut -c 40-57|cut -d '(' -f 2
获取平均Latency值:
cat result_read.txt |grep avg:|cut -c 48-65

为减小误差,我们把测试脚本执行了2次,将每次得到的各线程数下的QPS数值画成一条曲线并叠加,得到下面的统计图,其中横轴是并发线程数,纵轴是QPS均值:

file

测试结果里各个线程数下TPS数值与QPS都十分接近20:1的关系,所以这里不单独画图展示TPS了。

从图中可以看出,两次测试结果比较接近,随着线程数增加QPS指标也同步增加,在120线程左右达到峰值。

两次测试的平均请求延迟(latency,毫秒)统计如下图所示,其中横轴仍然是并发线程数,纵轴是延迟时间:

file

延迟基本与线程数正相关,并且在140线程以上斜率有所增加。

三、测试只读性能

我们使用sysbench oltp_read_only命令测试纯读取场景下,不同线程数的QPS表现:

#!/bin/sh
pg_host=192.168.132.167
pg_port=5432
pg_user=sbtest
pg_password=password
pg_db=sbtest

sysbench oltp_read_only \
--db-driver=pgsql \
--pgsql-host=$pg_host --pgsql-port=$pg_port \
--pgsql-user=$pg_user --pgsql-password=$pg_password \
--pgsql-db=$pg_db \
--table_size=100000 \
--tables=12 \
prepare

for ((threads=5; threads<=120; threads=threads+5));do
    sysbench oltp_read_only \
    --db-driver=pgsql \
    --report-interval=5 \
    --table-size=100000 \
    --tables=12 \
    --threads=$threads \
    --time=30 \
    --pgsql-host=$pg_host --pgsql-port=$pg_port \
    --pgsql-user=$pg_user --pgsql-password=$pg_password \
    --pgsql-db=$pg_db \
    run | tee -a result.txt 2>&1
done

sysbench oltp_read_only \
--db-driver=pgsql \
--pgsql-host=$pg_host --pgsql-port=$pg_port \
--pgsql-user=$pg_user --pgsql-password=$pg_password \
--pgsql-db=$pg_db \
--tables=12 \
cleanup

为减小误差,我们把测试脚本执行了2次,将每次得到的各线程数下的QPS数值画成一条曲线并叠加,得到下面的统计图,其中横轴是并发线程数,纵轴是QPS均值:

file

测试结果里各个线程数下,TPS数值与QPS都十分接近16:1的关系,所以这里不单独画图展示TPS了。

从图中可以看出,两次测试结果比较接近,都是在50个并发线程时达到QPS峰值(大约35000请求/秒)。

两次测试的平均请求延迟(latency,毫秒)统计如下图所示,其中横轴仍然是并发线程数,纵轴是延迟时间:

file

从图中可以看出,两次测试结果比较接近,随着线程数量的增加,平均延迟是单调上升的,即使在并发50个线程QPS已经达到峰值后,平均延迟也是上涨的。因此从这两项测试结果来看,在50线程以上继续增加线程数量是没有意义的。

使用Docker部署PostgreSql高可用集群(RepMgr方案)

本文记录了某项目中使用docker部署PostgreSQL集群的步骤和注意事项,使用的镜像是bitnami/postgresql-repmgr,其中与用户身份有关的内容在其他bitnami打包的镜像中也适用。

一、环境信息

CentOS 7.9
PostgreSQL 16

二、部署方案

PostgreSQL集群有多种方案,这里我们使用在项目中多次使用比较稳定的repmgr方案,repmgr能够在集群环境管理每个PostgreSQL节点的主从状态,官网介绍如下:

repmgr是一个开源的工具套件,用于管理PostgreSQL服务器集群中的复制和故障转移。它通过提供设置备用服务器、监控复制和执行故障转移或手动切换操作等管理任务的工具,增强了PostgreSQL内置的热备功能。
repmgr自从PostgreSQL 9.0引入内置的复制机制后,就提供了高级的支持。当前的repmgr系列,repmgr 5,支持了PostgreSQL 9.3引入的最新的复制功能,如级联复制、时间线切换和通过复制协议进行基础备份。

bitnami提供的postgresql-repmgr镜像是将PostgreSQL与repmgr打包在一起,形成一个集成的解决方案,以便用户能够快速搭建PostgreSQL集群服务,用户可以从dockerhub获取到这个镜像。

这个PostgreSQL集群解决方案包括PostgreSQL复制管理器,一个用于管理PostgreSQL集群上的复制和故障转移的开源工具。

三、部署步骤

首先确认集群环境各个服务器节点的状态:

关闭防火墙(如果docker已启动需要重启docker服务,否则关闭防火墙后启动容器会报iptables命令错):

systemctl stop firewalld 
systemctl disable firewalld

确保服务器时钟准确:

ntpdate cn.ntp.org.cn

安装和启动docker服务和docker-compose工具:

yum install -y epel-release
yum install -y docker
yum install -y docker-compose
systemctl enable docker
systemctl start docker

安装postgresql-repmgr镜像:

docker pull bitnami/postgresql-repmgr

将各个服务器名称写入hosts文件,vi /etc/hosts添加下面内容:

10.102.9.80 pg-0
10.102.9.81 pg-1
10.102.9.82 pg-2

四、配置

数据目录

bitnami的镜像使用非root用户身份,即容器里的root用户映射到宿主机的非root用户,此用户是ID为1001的无名称用户。要让容器的数据能够持久化到宿主机,需要准备一个数据目录(此例中为/mnt/sda/bitnami/postgresql)并映射到容器内,此目录的owner是1001:

mkdir /mnt/sda/bitnami
mkdir /mnt/sda/bitnami/postgresql
chown 1001:root /mnt/sda/bitnami -R

网络

创建docker网络以便节点间能够通信:

docker network create --subnet=172.25.0.0/24 --gateway=172.25.0.1 pg-network

配置文件

在任意目录创建pg.yml文件,内容如下:

version: '2'
networks:
  default:
    external:
      name: pg-network
services:
  pg:
    container_name: "pg"
    image: bitnami/postgresql-repmgr:latest
    networks:
      default:
        ipv4_address: 172.25.0.110
    ports:
      - "5432:5432"
    restart: always
    volumes:
      - /mnt/sda/bitnami/postgresql:/bitnami/postgresql
      - /etc/hosts:/etc/hosts
    environment:
      - POSTGRESQL_POSTGRES_PASSWORD=adminpassword
      - POSTGRESQL_USERNAME=myuser
      - POSTGRESQL_PASSWORD=mypassword
      - POSTGRESQL_DATABASE=mydatabase
      - REPMGR_PASSWORD=adminpassword
      - REPMGR_PRIMARY_HOST=pg-0
      - REPMGR_PRIMARY_PORT=5432
      - REPMGR_PARTNER_NODES=pg-0,pg-1,pg-2:5432
      - REPMGR_NODE_NAME=pg-0
      - REPMGR_NODE_NETWORK_NAME=pg-0
      - REPMGR_PORT_NUMBER=5432

在第二个节点类似创建pg.yml文件,修改其中的部分内容(ip地址、以及2处节点名称,见代码中的标注)如下所示:

version: '2'
networks:
  default:
    external:
      name: pg-network
services:
  pg:
    container_name: "pg"
    image: bitnami/postgresql-repmgr:latest
    networks:
      default:
        ipv4_address: 172.25.0.111    <-- 修改了这里
    ports:
      - "5432:5432"
    restart: always
    volumes:
      - /mnt/sda/bitnami/postgresql:/bitnami/postgresql
      - /etc/hosts:/etc/hosts
    environment:
      - POSTGRESQL_POSTGRES_PASSWORD=adminpassword
      - POSTGRESQL_USERNAME=myuser
      - POSTGRESQL_PASSWORD=mypassword
      - POSTGRESQL_DATABASE=mydatabase
      - REPMGR_PASSWORD=adminpassword
      - REPMGR_PRIMARY_HOST=pg-0
      - REPMGR_PRIMARY_PORT=5432
      - REPMGR_PARTNER_NODES=pg-0,pg-1,pg-2:5432
      - REPMGR_NODE_NAME=pg-1    <-- 修改了这里
      - REPMGR_NODE_NETWORK_NAME=pg-1    <-- 修改了这里
      - REPMGR_PORT_NUMBER=5432

第三个节点的情况类似,为节约篇幅这里不再贴配置文件内容。

启动服务

在每个节点分别使用docker-compose命令启动服务:

docker-compose -f /root/pg-ha/pg.yml up -d

查看repmgr状态,例如当前primary节点是哪一个:

docker exec -ti pg /opt/bitnami/scripts/postgresql-repmgr/entrypoint.sh repmgr -f /opt/bitnami/repmgr/conf/repmgr.conf service status

 ID | Name | Role    | Status    | Upstream | repmgrd | PID | Paused? | Upstream last seen
----+------+---------+-----------+----------+---------+-----+---------+--------------------
 1000 | pg-0 | standby |   running | pg-1     | running | 1   | no      | 1 second(s) ago
 1001 | pg-1 | primary | * running |          | running | 1   | no      | n/a
 1002 | pg-2 | standby |   running | pg-1     | running | 1   | no      | 0 second(s) ago

尝试连接数据库,验证服务是否正常(-U参数很重要):

docker exec -ti pg psql -U myuser -d mydatabase

若需要手工切换standby节点为primary执行下面的命令,需要节点之间配置过免密:

docker exec -it pg /opt/bitnami/scripts/postgresql-repmgr/entrypoint.sh repmgr -f /opt/bitnami/repmgr/conf/repmgr.conf standby switchover

使用SysBench进行数据库性能测试

SysBench是一个基于LuaJIT的可脚本化多线程基准测试工具。它最常用于数据库基准测试,但也可用于创建不涉及数据库服务器的任意复杂工作负载。本文以一个典型测试为例,介绍SysBench的安装和使用。

一、环境信息

被测服务器(192.168.132.167):

  • 4核8线程,32GB,1TB 7200转机械硬盘
  • CentOS 7.9
  • PostgreSQL 9.6.2

测试客户端(192.168.130.152):

  • 4核8线程,32GB,2TB 7200转机械硬盘
  • CentOS 7.9
  • SysBench 1.0.17

网络:

  • 千兆以太局域网

二、准备工作

安装SysBench

不同发行版的Linux按照官网上的说明安装即可:

Debian/Ubuntu

curl -s https://packagecloud.io/install/repositories/akopytov/sysbench/script.deb.sh | sudo bash
sudo apt -y install sysbench

RHEL/CentOS:

curl -s https://packagecloud.io/install/repositories/akopytov/sysbench/script.rpm.sh | sudo bash
sudo yum -y install sysbench

Fedora:

curl -s https://packagecloud.io/install/repositories/akopytov/sysbench/script.rpm.sh | sudo bash
sudo dnf -y install sysbench

验证安装成功:

sysbench --version
sysbench 1.0.17

创建测试用DB

在被测服务器上,创建一个空的专门用于性能测试的库(sbtest),以及相应的用户:

psql -h 192.168.132.167 -U postgres -W
> CREATE USER sbtest WITH PASSWORD 'password';
> CREATE DATABASE sbtest;
> GRANT ALL PRIVILEGES ON DATABASE sbtest TO sbtest;

验证从客户端能够访问到此数据库:

psql -h 192.168.132.167 -U sbtest -W -d sbtest

三、开始测试

SysBench基本用法

SysBench自带了多种数据库性能测试的场景,这些测试场景的名称(testname)列表可以在/usr/share/sysbench/目录下找到,包括bulk_insert, oltp_delete, oltp_insert, oltp_point_select, oltp_read_only, oltp_read_write, oltp_update_index, oltp_update_non_index, oltp_write_only, select_random_pointsselect_random_ranges,从名字可以大致猜测出所代表的场景,例如oltp_read_write代表综合读写的场景,oltp_write_only代表只读的场景。

SysBench执行命令的统一格式是:

sysbench [options]... [testname] [command]

其中testname就是上面列出的测试名称,每个不同的testname有自己的command,但大多数支持的command都是prepareruncleanup。当然我们一般还需要填写options来指定如数据库地址、数据库密码等信息。

下面以oltp_read_write场景为例,介绍最经常使用的几个命令。

准备测试数据(prepare)

prepare的作用是向目标数据库里插入一些随机数据,作为后面真正的测试的数据环境。下面的命令在目标数据库里创建12张表,每张表里添加10万行随机数据:

sysbench oltp_read_write \
    --db-driver=pgsql --pgsql-host=192.168.132.167 --pgsql-port=5432 \
    --pgsql-user=sbtest --pgsql-password=password --pgsql-db=sbtest \
    --table_size=100000 --tables=12 \
    prepare

执行测试(run)

下面的命令执行实际的测试:

sysbench oltp_read_write \
    --db-driver=pgsql --pgsql-host=192.168.132.167 --pgsql-port=5432 \
    --pgsql-user=sbtest --pgsql-password=password --pgsql-db=sbtest \
    --report-interval=5 \
    --table_size=100000 --tables=12 \
    --threads=32 \
    --time=30 --warmup-time=10 \
    run

其中time参数规定了测试执行的时长(30秒),warmup-time参数规定了测试前预热阶段的时长(10秒),threads参数规定了客户端并发请求的线程数量(32线程)。

测试启动后,屏幕上会按指定时间间隔输出当前性能指标:

[ 5s ] thds: 32 tps: 217.41 qps: 4476.39 (r/w/o: 3138.93/895.24/442.22) lat (ms,95%): 467.30 err/s: 0.40 reconn/s: 0.00
[ 10s ] thds: 32 tps: 221.21 qps: 4380.99 (r/w/o: 3076.74/861.64/442.62) lat (ms,95%): 530.08 err/s: 0.00 reconn/s: 0.00
[ 15s ] thds: 32 tps: 301.40 qps: 6071.88 (r/w/o: 4239.86/1229.02/603.01) lat (ms,95%): 297.92 err/s: 0.00 reconn/s: 0.00
[ 20s ] thds: 32 tps: 262.78 qps: 5180.49 (r/w/o: 3626.58/1027.94/525.97) lat (ms,95%): 344.08 err/s: 0.20 reconn/s: 0.00
[ 25s ] thds: 32 tps: 186.81 qps: 3813.27 (r/w/o: 2673.39/765.05/374.83) lat (ms,95%): 590.56 err/s: 0.40 reconn/s: 0.00
[ 30s ] thds: 32 tps: 318.79 qps: 6382.66 (r/w/o: 4466.10/1278.17/638.39) lat (ms,95%): 227.40 err/s: 0.20 reconn/s: 0.00

测试结束后,会输出汇总指标报告:

SQL statistics:
    queries performed:
        read:                            106134
        write:                           30305
        other:                           15169
        total:                           151608
    transactions:                        7575   (252.30 per sec.)
    queries:                             151608 (5049.62 per sec.)
    ignored errors:                      6      (0.20 per sec.)
    reconnects:                          0      (0.00 per sec.)

General statistics:
    total time:                          30.0216s
    total number of events:              7575

Latency (ms):
         min:                                    9.55
         avg:                                  126.79
         max:                                 1051.62
         95th percentile:                      369.77
         sum:                               960450.42

Threads fairness:
    events (avg/stddev):           236.7188/3.16
    execution time (avg/stddev):   30.0141/0.00

清除测试数据

要清除前面执行测试产生的数据,执行下面的命令:

sysbench oltp_read_write \
    --db-driver=pgsql --pgsql-host=192.168.132.167 --pgsql-port=5432 \
    --pgsql-user=sbtest --pgsql-password=password --pgsql-db=sbtest \
    --tables=12 \

注意tables参数需要手工指定并且与prepare时一致,否则下次prepare可能会报错table已存在。

四、参考资料

TDengine、InfluxDB与PostgreSQL单机版性能对比测试

本文记录单机环境下TDengine、InfluxDB和PostgreSQL三种数据库,处理时序数据的性能对比,主要考察数据的写入和读取速度。

一、测试环境

服务器

CPU 内存 硬盘 网络
Intel i7 4核8线程 32G 2T 7200转机械 千兆网络
操作系统 TDengine Influxdb PostgreSQL
CentOS 7.9 2.6 2.0 beta 9.0

客户端

CPU 内存 硬盘 网络
Intel i7 4核8线程 32G 256G SSD固态 千兆网络
操作系统 JDK JMeter
Windows10 OpenJDK 11 v4

二、测试数据

测试数据为10个csv文件,每个文件大小约为10GB,包含下面的内容:

  • 每个文件包含100个设备的数据
  • 数据频率为1秒
  • 每行数据包含1000列
  • 所有数据均为double类型

三、测试结果

数据写入

同时向数据库写入10个csv文件,多次执行取结果平均值:

数据库 数据行导入速率(record/s) 数据点导入速率(points/s)
InfluxDB 235 235000
TDengine 750 750208
PostgreSQL 213 213000

file

数据读取

数据读取性能与读取的列数相关,因此分别测试了不同列数情况下三种数据库的读取速度(单并发):

file

四、测试结论

以上初步测试结果显示,在单并发大多数场景下,TDengine的性能相比InfluxDB和PostgreSQL具有较大优势。由于项目时间所限,此次未能对多并发情况下各个数据库的性能进行对比略显遗憾。作为补充,可参考集群环境多并发条件下TDengine与Cassandra的性能对比(链接)。