文档中心MogDBMogDB StackUqbar

文档:v2.0

支持的版本:

其他版本:

写性能测试

1.概述

时序数据应用在传感器的典型场景中时,传感器指标数量往往很大,监控数据还是7*24小时不断的高频写入,因此时序数据库需要能持续支持高性能写入。本文使用基于TSBS(Times Series Benchmark Suite)增加支持Uqbar的Uqbar_benchmark作为性能基准测试平台,在不同的场景下,与同样基于关系模型的主流时序数据库TimescaleDB进行写性能对比。

1.1 Uqbar简介

Uqbar是在openGauss内核基础上开发的时序数据库,同时支持关系模型和时序模型,具备高性能、低成本、稳定可靠和开放易用等优点,是专为物联网场景设计的超融合时序数据库。Uqbar可以用于管理海量时序数据,也可以用于OLTP场景管理关系数据,还支持跨时序数据和关系数据的复杂关联查询,为物联网场景提供一站式数据解决方案。

1.2 TimescaleDB简介

TimescaleDB是一款基于PostgreSQL开发的时序数据库,其以PostgreSQL插件的形式存在,可通过安装插件的方式使PostgreSQL具备时序能力而无需重新安装数据库。TimescaleDB提供丰富的时序功能,优秀的压缩能力,能够使用PostgreSQL数据库丰富的生态,支持完整的SQL。


2. 时序数据库性能基准测评平台Uqbar_benchmark

Uqbar_benchmark是基于TSBS(Time Series Benchmark Suite)时序数据性能基准测评平台修改,增加了对Uqbar时序数据库的性能测试支持。TSBS是由Timescale开源的时序性能基准测评平台,包含DevOps和IoT两个典型应用场景。TSBS提供了丰富的参数用于测试不同指标下时序数据库的性能情况,包括采样时间范围,采样间隔,设备数,是否创建索引,连接数等,能完成从数据生成,数据写入,查询生成,查询执行的完整流程,并提供数据写入,查询执行过程的性能数据。因其开源,功能丰富的特点,跨系统跨架构能力以及完善的接口定义,被众多时序数据库厂商作为基准性能测评平台。

Uqbar_benchmark下载链接


3. 测试环境

3.1 硬件配置

Uqbar和TimescaleDB均部署在同一个服务器,而Uqbar_benchmark客户端部署到另外一台和服务端配置相当的机器上。具体硬件配置如下:

3.1.1 ARM+麒麟测试环境机器配置

ARM+KL(Server端) ARM+KL(Client端)
CPU Kunpeng-920 * 64 Kunpeng-920 * 64
内存 509GB 509GB
硬盘 NVME 1.8T * 4 NVME 1.8T * 4
OS Kylin Linux Advanced Server release V10 (Sword) ;Linux version 4.19.90-24.4.v2101.ky10.aarch64 Kylin Linux Advanced Server release V10 (Sword);Linux version 4.19.90-24.4.v2101.ky10.aarch64
文件系统 XFS XFS

3.1.2 x86+CentOS 测试环境机器配置

x86+CentOS 7.9(Server端) x86+CentOS 7.9(Client端)
CPU Intel(R) Xeon(R) Gold 5320 * 104 Intel(R) Xeon(R) Gold 5320 * 104
内存 503GB 503GB
硬盘 NVME 1.8T * 4 NVME 1.5T * 5
OS CentOS Linux release 7.9.2009 (Core) Linux version 3.10.0-1160.el7.x86_64 CentOS Linux release 7.9.2009 (Core) Linux version 3.10.0-1160.el7.x86_64
文件系统 XFS XFS

3.2 软件配置

Uqbar版本:Uqbar 2.0

TimescaleDB版本:PostgreSQL12.12+TimescaleDB1.7.0

Uqbar_benchmark版本:Uqbar_benchmark2.0


4. 测试场景

4.1 测试模型

本文采用Uqbar_benchmark的IoT和DevOps两个典型应用场景进行对比,IoT应用场景有2张表:readings、diagnostics;其中readings表记录7个测量值,diagnostics表记录3个测量值,类型均为double precision;DevOps应用场景有9张表:cpu、disk、diskio、kernel、mem、net、nginx、postgresl、redis。

具体的表结构可以参考附件

Uqbar在写入的时候提供了两种数据模型,写性能对比时需要和TimescaleDB的数据模型保持一致,因此在写数据时,需要将Uqbar_benchmak参数use-tags-id设置为true,即会单独建立一张tags表,用于记录设备信息,并在实际记录metrics的表中使用tags_id唯一确定设备信息。

此外,索引中有time-index和partition-index,测试时,需要保证Uqbar和TimescaleDB的索引数目一致,本次测试使用默认索引数目设置,会将Uqbar_benchmak参数time-index和partition-index均设置为true。

4.2 写性能测试指标

在数据库写入时,使用平均每秒中写入的metrics数(Metrics-per-second),作为时序数据库写性能的测试指标。比如针对IoT用例中的readings 表,表中有7个测量值,因此每上报一次数据,会写入一行数据,每行数据中包括7个测量指标(metrics)。

4.3 写性能测试场景

本测试使用如下三个不同场景,进行写性能对比,每个场景的数据规模见表1所示:

表1.场景数据说明

场景一 场景二 场景三
设备数目scale 1000 10000 100,000
持续时间 10 天 1 天 3 小时
数据间隔 10 秒 10 秒 10 秒
IoT metrics总数 864,000,000 864,000,000 1,080,000,000
DevOps metrics总数 8,726,400,000 8,726,400,000 10,908,000,000

场景中分别选取设备数为1千,1万,10万三个梯队作为对比,时间间隔均选择10s,对应的时间跨度分别为10天,1天以及3小时。由于IoT类型包括两张表,DevOps包括9张表,因此IoT和DevOps对应的总行数和总metrics数值存在较大差异。由表中记录可知,三个场景中的metrics数均超过了1亿,其中scale为10万的DevOps metrics总数达到了109亿。

各项数据的计算公式及关系如下:

  • IoT metrics总数=持续时间/数据间隔*设备数目*10(持续时间需换算成秒)

  • DevOps metrics总数=持续时间/数据间隔*设备数目*101

Uqbar和TimescaleDB均按照下表2设置Uqbar_benchmark的其他写入参数:

表2.写入参数设置

事项 取值
chunk-time 1天
batch-size 1000
workers x86 150, arm 70
索引 time-index & partition-index
写入方式 insert

注:本次测试中,麒麟arm环境的CPU核数为64,而X86环境的CPU核数为104,因此不同环境使用了不同的workers


5. 测试步骤

写性能测试步骤主要分成两大步骤:生成数据和写入数据。

5.1 生成数据

Uqbar和TimescaleDB生成数据命令如下(本文仅列出IoT用例的生成命令,DevOps用例可将参数--use-case的值iot替换成devops即可):

/Uqbar_benchmark/bin/tsbs_load_uqbar /tsbs_generate_data --use-case=iot --seed=123 --scale=1000 --timestamp-start=2023-08-01T00:00:00Z --timestamp-end=2023-08-11T00:00:00Z --log-interval=10s --format=uqbar | gzip > /data/tsbsdata/scale1000-logInterval10s-iot-data.gz

注:Uqbar_benchmark中,Uqbar和TimescaleDB写入时使用的数据格式是一致的,因此只需要生成一次数据,可以供Uqbar和TimescaleDB两者同时使用。

5.2 写入数据

Uqbar写入数据命令如下:

cat /data/tsbsdata/scale1000-logInterval10s-iot-data.gz | gunzip |  /Uqbar_benchmark/bin/tsbs_load_uqbar --host=127.0.0.1 --port=2626 --user=test002 --password=gauss@123 --db-name=uqbar_iot_10s_1000scale --workers=150 --use-insert=true --batch-size=1000 --partition-index=true   --time-index=true --no-flow-control --use-tags-id=true --chunkgroup-duration=1d

TimescaleDB写入数据命令如下:

cat /data/tsbsdata/scale1000-logInterval10s-iot-data.gz | gunzip |  /Uqbar_benchmark/bin/tsbs_load_uqbar --host=127.0.0.1 --port=2626 --user=test002 --password=gauss@123 --db-name=uqbar_iot_10s_1000scale --workers=150 --use-insert=true --batch-size=1000 --partition-index=true   --time-index=true --no-flow-control  --version=1 --chunk-time=24h

写入命令执行完成之后,在写入命令输出中会显示本次的写性能测试数值。


6. 写性能对比结果和分析

6.1 CentOS x86环境下的写性能对比

具体的对比数据如下:

表3. x86环境下写性能对比

表3.x86环境下写性能对比

注: Uqbar相对于TimescaleDB的增长率计算公式:(Uqbar的写性能数值-TimescaleDB的写性能数值)/ TimescaleDB的写性能数值

图1.x86环境下不同场景的写性能对比(metrics/sec.数值越大越好)

图 1. x86环境下不同场景的写性能对比(metrics/sec.数值越大越好)

由表3和图1可以看到,在x86环境上,IoT和DevOps两种典型应用场景中,Uqbar的写性能均优于TimescaleDB,且高于TimescaledB 22%以上,最大达到TimescaleDB的8.55倍。详细如下:

  • IoT应用场景,Uqbar写入性能相比TimescaleDB写入性能的增长率最低为48.6%,最高为 113.87%;

  • DevOps应用场景,Uqbar写入性能相比TimescaleDB写入性能的增长率最低为TimescaleDB 22%,最高为755.34%;

Uqbar在三种场景下的写速率在DevOps用例中最高达到了809万metrics/second,IoT用例中最高为511万metrics/second。

6.2 麒麟arm环境下的写性能对比

具体的对比数据如下:

表4. 麒麟arm环境下写性能对比数据

表4.麒麟arm环境下写性能对比数据

图 2.arm环境下不同场景的写性能对比(metrics/sec.数值越大越好)

图 2.arm环境下不同场景的写性能对比(metrics/sec.数值越大越好)

由表4和图3可以看到,在麒麟arm环境中,IoT和DevOps两种典型应用场景中,Uqbar的写性能也均优于TimescaleDB,且高于TimescaledB 4.61%以上,最大达到TimescaleDB的4.6倍。详细如下:

  • IoT应用场景,Uqbar写入性能相比TimescaleDB写入性能的增长率最低为4.61%,最高为 64.07%;

  • DevOps应用场景,Uqbar写入性能相比TimescaleDB写入性能的增长率最低为TimescaleDB 21.8%,最高为461.77%;

其中,Uqbar在三种场景下的写速率在DevOps用例中最高达到了812万metrics/second。

此外由6.1中表3和6.2中表4还可以得知,随着设备数目的增大,从1万增长到10万时,Uqbar和TimescaleDB写性能均有不同幅度的下降,但是TimescaleDB在DevOps场景中下降相对更明显。


7. 总结

和同样基于关系模型的主流时序数据库TimescaleDB相比,Uqbar的写性能在不同平台不同场景中,均有不同程度的领先优势。Uqbar的写性能在DevOps用例中最高能达到每秒写入800多万指标。随着scale的增大,DevOps场景下Uqbar相对于TimescaleDB的增长率最大达到了7.55倍。


附件

Uqbar_benchmark表结构

当数据模型一致,即use-tags-id为true时的表结构如下:

iot类型

perftest_copywrite004=# \d readings;
                   Table "public.readings"
      Column      |           Type           |   Modifiers
------------------+--------------------------+---------------
 time             | timestamp with time zone | default now()
 tags_id          | integer                  |
 latitude         | double precision         |
 longitude        | double precision         |
 elevation        | double precision         |
 velocity         | double precision         |
 heading          | double precision         |
 grade            | double precision         |
 fuel_consumption | double precision         |
 additional_tags  | text                     |
Indexes:
    "readings_tags_id_time_idx" btree (tags_id, "time" DESC) LOCAL TABLESPACE pg_default
    "readings_time_idx" btree ("time" DESC) LOCAL TABLESPACE pg_default
Partition By RANGE(time) Subpartition By HASH(tags_id)
Number of partitions: 3 (View pg_partition to check each partition range.)
Number of subpartitions: 9 (View pg_partition to check each subpartition range.)

perftest_copywrite004=# \d diagnostics
                 Table "public.diagnostics"
     Column      |           Type           |   Modifiers
-----------------+--------------------------+---------------
 time            | timestamp with time zone | default now()
 tags_id         | integer                  |
 fuel_state      | double precision         |
 current_load    | double precision         |
 status          | double precision         |
 additional_tags | text                     |
Indexes:
    "diagnostics_tags_id_time_idx" btree (tags_id, "time" DESC) LOCAL TABLESPACE pg_default
    "diagnostics_time_idx" btree ("time" DESC) LOCAL TABLESPACE pg_default
Partition By RANGE(time) Subpartition By HASH(tags_id)
Number of partitions: 3 (View pg_partition to check each partition range.)
Number of subpartitions: 9 (View pg_partition to check each subpartition range.)

uqbar_database=> \d tags
                     Table "public.tags"
       Column        |  Type   |                     Modifiers
---------------------+---------+---------------------------------------------------
 id                  | integer | not null default nextval('tags_id_seq'::regclass)
 hostname            | text    |
 region              | text    |
 datacenter          | text    |
 rack                | text    |
 os                  | text    |
 arch                | text    |
 team                | text    |
 service             | text    |
 service_version     | text    |
 service_environment | text    |
Indexes:
    "tags_pkey" PRIMARY KEY, btree (id) TABLESPACE pg_default
    "uniq1" UNIQUE, btree (hostname, region, datacenter, rack, os, arch, team, service, service_version, service_environment) TABLESPACE pg_default
"tags_hostname_idx" btree (hostname) TABLESPACE pg_default

devops类型

uqbar_database=> \d cpu;
                     Table "public.cpu"
      Column      |           Type           |   Modifiers
------------------+--------------------------+---------------
 time             | timestamp with time zone | default now()
 tags_id          | integer                  |
 usage_user       | double precision         |
 usage_system     | double precision         |
 usage_idle       | double precision         |
 usage_nice       | double precision         |
 usage_iowait     | double precision         |
 usage_irq        | double precision         |
 usage_softirq    | double precision         |
 usage_steal      | double precision         |
 usage_guest      | double precision         |
 usage_guest_nice | double precision         |
 additional_tags  | text                     |
Indexes:
    "cpu_tags_id_time_idx" btree (tags_id, "time" DESC) LOCAL TABLESPACE pg_default
    "cpu_time_idx" btree ("time" DESC) LOCAL TABLESPACE pg_default
Partition By RANGE(time) Subpartition By HASH(tags_id)
Number of partitions: 14 (View pg_partition to check each partition range.)
Number of subpartitions: 42 (View pg_partition to check each subpartition range.)

uqbar_database=> \d disk
                    Table "public.disk"
     Column      |           Type           |   Modifiers
-----------------+--------------------------+---------------
 time            | timestamp with time zone | default now()
 tags_id         | integer                  |
 total           | double precision         |
 free            | double precision         |
 used            | double precision         |
 used_percent    | double precision         |
 inodes_total    | double precision         |
 inodes_free     | double precision         |
 inodes_used     | double precision         |
 additional_tags | text                     |
Indexes:
    "disk_tags_id_time_idx" btree (tags_id, "time" DESC) LOCAL TABLESPACE pg_default
    "disk_time_idx" btree ("time" DESC) LOCAL TABLESPACE pg_default
Partition By RANGE(time) Subpartition By HASH(tags_id)
Number of partitions: 14 (View pg_partition to check each partition range.)
Number of subpartitions: 42 (View pg_partition to check each subpartition range.)

uqbar_database=> \d diskio
                   Table "public.diskio"
     Column      |           Type           |   Modifiers
-----------------+--------------------------+---------------
 time            | timestamp with time zone | default now()
 tags_id         | integer                  |
 reads           | double precision         |
 writes          | double precision         |
 read_bytes      | double precision         |
 write_bytes     | double precision         |
 read_time       | double precision         |
 write_time      | double precision         |
 io_time         | double precision         |
 additional_tags | text                     |
Indexes:
    "diskio_tags_id_time_idx" btree (tags_id, "time" DESC) LOCAL TABLESPACE pg_default
    "diskio_time_idx" btree ("time" DESC) LOCAL TABLESPACE pg_default
Partition By RANGE(time) Subpartition By HASH(tags_id)
Number of partitions: 14 (View pg_partition to check each partition range.)
Number of subpartitions: 42 (View pg_partition to check each subpartition range.)

uqbar_database=> \d mem
                      Table "public.mem"
      Column       |           Type           |   Modifiers
-------------------+--------------------------+---------------
 time              | timestamp with time zone | default now()
 tags_id           | integer                  |
 total             | double precision         |
 available         | double precision         |
 used              | double precision         |
 free              | double precision         |
 cached            | double precision         |
 buffered          | double precision         |
 used_percent      | double precision         |
 available_percent | double precision         |
 buffered_percent  | double precision         |
 additional_tags   | text                     |
Indexes:
    "mem_tags_id_time_idx" btree (tags_id, "time" DESC) LOCAL TABLESPACE pg_default
    "mem_time_idx" btree ("time" DESC) LOCAL TABLESPACE pg_default
Partition By RANGE(time) Subpartition By HASH(tags_id)
Number of partitions: 14 (View pg_partition to check each partition range.)
Number of subpartitions: 42 (View pg_partition to check each subpartition range.)
uqbar_database=> \d nginx
                    Table "public.nginx"
     Column      |           Type           |   Modifiers
-----------------+--------------------------+---------------
 time            | timestamp with time zone | default now()
 tags_id         | integer                  |
 accepts         | double precision         |
 active          | double precision         |
 handled         | double precision         |
 reading         | double precision         |
 requests        | double precision         |
 waiting         | double precision         |
 writing         | double precision         |
 additional_tags | text                     |
Indexes:
    "nginx_tags_id_time_idx" btree (tags_id, "time" DESC) LOCAL TABLESPACE pg_default
    "nginx_time_idx" btree ("time" DESC) LOCAL TABLESPACE pg_default
Partition By RANGE(time) Subpartition By HASH(tags_id)
Number of partitions: 14 (View pg_partition to check each partition range.)
Number of subpartitions: 42 (View pg_partition to check each subpartition range.)
uqbar_database=> \d kernel
                    Table "public.kernel"
      Column      |           Type           |   Modifiers
------------------+--------------------------+---------------
 time             | timestamp with time zone | default now()
 tags_id          | integer                  |
 boot_time        | double precision         |
 interrupts       | double precision         |
 context_switches | double precision         |
 processes_forked | double precision         |
 disk_pages_in    | double precision         |
 disk_pages_out   | double precision         |
 additional_tags  | text                     |
Indexes:
    "kernel_tags_id_time_idx" btree (tags_id, "time" DESC) LOCAL TABLESPACE pg_default
    "kernel_time_idx" btree ("time" DESC) LOCAL TABLESPACE pg_default
Partition By RANGE(time) Subpartition By HASH(tags_id)
Number of partitions: 14 (View pg_partition to check each partition range.)
Number of subpartitions: 42 (View pg_partition to check each subpartition range.)

uqbar_database=> \d net
                     Table "public.net"
     Column      |           Type           |   Modifiers
-----------------+--------------------------+---------------
 time            | timestamp with time zone | default now()
 tags_id         | integer                  |
 bytes_sent      | double precision         |
 bytes_recv      | double precision         |
 packets_sent    | double precision         |
 packets_recv    | double precision         |
 err_in          | double precision         |
 err_out         | double precision         |
 drop_in         | double precision         |
 drop_out        | double precision         |
 additional_tags | text                     |
Indexes:
    "net_tags_id_time_idx" btree (tags_id, "time" DESC) LOCAL TABLESPACE pg_default
    "net_time_idx" btree ("time" DESC) LOCAL TABLESPACE pg_default
Partition By RANGE(time) Subpartition By HASH(tags_id)
Number of partitions: 14 (View pg_partition to check each partition range.)
Number of subpartitions: 42 (View pg_partition to check each subpartition range.)

uqbar_database=> \d postgresl
                  Table "public.postgresl"
     Column      |           Type           |   Modifiers
-----------------+--------------------------+---------------
 time            | timestamp with time zone | default now()
 tags_id         | integer                  |
 numbackends     | double precision         |
 xact_commit     | double precision         |
 xact_rollback   | double precision         |
 blks_read       | double precision         |
 blks_hit        | double precision         |
 tup_returned    | double precision         |
 tup_fetched     | double precision         |
 tup_inserted    | double precision         |
 tup_updated     | double precision         |
 tup_deleted     | double precision         |
 conflicts       | double precision         |
 temp_files      | double precision         |
 temp_bytes      | double precision         |
 deadlocks       | double precision         |
 blk_read_time   | double precision         |
 blk_write_time  | double precision         |
 additional_tags | text                     |
Indexes:
    "postgresl_tags_id_time_idx" btree (tags_id, "time" DESC) LOCAL TABLESPACE pg_default
    "postgresl_time_idx" btree ("time" DESC) LOCAL TABLESPACE pg_default
Partition By RANGE(time) Subpartition By HASH(tags_id)
Number of partitions: 14 (View pg_partition to check each partition range.)
Number of subpartitions: 42 (View pg_partition to check each subpartition range.)

uqbar_database=> \d redis
                          Table "public.redis"
           Column            |           Type           |   Modifiers
-----------------------------+--------------------------+---------------
 time                        | timestamp with time zone | default now()
 tags_id                     | integer                  |
 uptime_in_seconds           | double precision         |
 total_connections_received  | double precision         |
 expired_keys                | double precision         |
 evicted_keys                | double precision         |
 keyspace_hits               | double precision         |
 keyspace_misses             | double precision         |
 instantaneous_ops_per_sec   | double precision         |
 instantaneous_input_kbps    | double precision         |
 instantaneous_output_kbps   | double precision         |
 connected_clients           | double precision         |
 used_memory                 | double precision         |
 used_memory_rss             | double precision         |
 used_memory_peak            | double precision         |
 used_memory_lua             | double precision         |
 rdb_changes_since_last_save | double precision         |
 sync_full                   | double precision         |
 sync_partial_ok             | double precision         |
 sync_partial_err            | double precision         |
 pubsub_channels             | double precision         |
 pubsub_patterns             | double precision         |
 latest_fork_usec            | double precision         |
 connected_slaves            | double precision         |
 master_repl_offset          | double precision         |
 repl_backlog_active         | double precision         |
 repl_backlog_size           | double precision         |
 repl_backlog_histlen        | double precision         |
 mem_fragmentation_ratio     | double precision         |
 used_cpu_sys                | double precision         |
 used_cpu_user               | double precision         |
 used_cpu_sys_children       | double precision         |
 used_cpu_user_children      | double precision         |
 additional_tags             | text                     |
Indexes:
    "redis_tags_id_time_idx" btree (tags_id, "time" DESC) LOCAL TABLESPACE pg_default
    "redis_time_idx" btree ("time" DESC) LOCAL TABLESPACE pg_default
Partition By RANGE(time) Subpartition By HASH(tags_id)
Number of partitions: 14 (View pg_partition to check each partition range.)
Number of subpartitions: 42 (View pg_partition to check each subpartition range.)
Copyright © 2011-2024 www.enmotech.com All rights reserved.