He3DB 是由移动云数据库团队研发的一款计算/存储分离的云原生数据库,He3DB通过计算/存储分离、数据冷热分层和压缩、智能中间件等技术,来保证高性能和低成本完美兼得,在获得高性能的同时,最大化的帮助客户节省数据库使用成本。
本文继续介绍下He3DB与PostgreSQL在CPU受限情况下的性能对比,以及对测试结果进行分析。
CPU受限
He3DB和PostgreSQL以容器的方式运行,并且限制CPU的使用最多为8C,内存的资源不限制,计算层的databuffer可以覆盖测试数据。
数据准备:使用sysbench导入8张表,每张表500万条记录。
插入场景
使用以下命令对insert场景进行测试:
sysbench --db-driver=pgsql --pgsql-user=postgres --pgsql-password='xxx' --pgsql-db=postgres --events=0 --report-interval=5 --pgsql-host=xxx --pgsql-port=xxx --table-size=5000000 --tables=8 oltp_insert.lua run --time=120 --threads=xxx --rand-type='uniform'
insert场景下的TPS值:
| 并发数 | He3DB | PostgreSQL(主+半同步备) | PostgreSQL(主+异步备) |
|---|---|---|---|
| 16 | 2782.50 | 46784.93 | 72723.78 |
| 32 | 10564.42 | 68812.11 | 90076.44 |
| 64 | 26230.82 | 71298.54 | 76869.33 |
| 128 | 50379.08 | 61002.71 | 45504.18 |
| 256 | 56665.19 | 47990.38 | 33818.18 |
| 512 | 30971.91 | 38757.81 | 30690.72 |
从上面的测试结果可以看出:
1、随着并发数的逐渐增加,He3DB的TPS值持续增加,且增幅很大,但是CPU达到瓶颈后(256并发),再增加并发数,性能下降很多。而PostgreSQL在小并发的情况下,性能较He3DB高很多,而随着并发数的增加性能很快达到峰值,再增加并发数,性能会逐渐下降。
2、在并发数小的情况下,He3DB的TPS值比PostgreSQL相差较大,而随着并发的增加,在256并发下,He3DB的TPS值明显高于PostgreSQL。
造成以上现象的原因,主要是在并发数小的情况下,wal写入的并发数比较小,而单次写入到TiKV的时延比写入到高性能磁盘的时延高很多,从而导致在小并发的情况下,He3DB与PostgreSQL的性能差距很大。随着并发数的增加,wal写入的并发数也在增加,单位时间内写入的wal也变多了,并且由于He3DB优化了wal写入的一些锁机制,以及去掉了FPW等操作,因此在大并发的情况(并发数为256,这时He3DB的cpu还未达到瓶颈),He3DB的性能会明显高于PostgreSQL。由于对cpu做了限额,在512并发的情况下,He3DB的cpu达到瓶颈,会造成资源争抢比较严重,性能下降的很明显。
测试分析
以下是在不同的并发下,写入wal到kv层的各耗时段的次数:
| 持久化wal耗时 | 16并发 | 32并发 | 64并发 | 128并发 | 256并发 | 512并发 |
|---|---|---|---|---|---|---|
| <1ms | 276873 | 5395 | 13406 | 18636 | 9805 | 2928 |
| 1~2ms | 11734 | 60763 | 143765 | 267088 | 262508 | 131229 |
| 2~3ms | 370 | 1119 | 4893 | 21886 | 61637 | 35725 |
| 3~4ms | 88 | 232 | 938 | 3122 | 8003 | 6050 |
| 4~5ms | 28 | 144 | 711 | 1986 | 5659 | 7064 |
| 5~6ms | 20 | 19 | 68 | 243 | 693 | 1780 |
| 6~7ms | 14 | 11 | 14 | 43 | 120 | 263 |
| 7~8ms | 5 | 15 | 23 | 16 | 44 | 57 |
| 8~9ms | 1 | 16 | 28 | 60 | 95 | 144 |
| >9ms | 23 | 41 | 80 | 207 | 1159 | 1672 |
| 总计 | 289156 | 67755 | 163926 | 313287 | 349723 | 186912 |



从上面的表格和饼图可以看出:
1、在不同的并发数情况下,wal写入耗时绝大数处于1~2ms或者更低的范围内。
2、随着压测程序并发的增加(除了16并发),写入wal的次数也增加了,同时较高耗时的写入比例也有所增加。
3、写入wal的耗时最长时间超过了9ms,而且随着压测程序并发数的增加,超过9ms的写入次数基本呈倍数增加。
下面表格是关于insert场景下TPS与WAL写入的一些统计信息:
| 并发数 | TPS | 写入WAL次数 | 平均每秒写入的WAL次数 | 写入WAL总耗时(us) | 平均每次写入WAL的耗时(us) | WAL写入的平均并发数 | 写入WAL字节数 | 平均每次写入WAL的字节数 |
|---|---|---|---|---|---|---|---|---|
| 16 | 2782.5 | 289156 | 2409.63 | 161778583 | 559.49 | 1.35 | 161964641 | 560 |
| 32 | 10564.42 | 67755 | 564.63 | 89131310 | 1315.49 | 0.74 | 575831380 | 8498 |
| 64 | 26230.82 | 163926 | 1366.05 | 221179937 | 1349.27 | 1.84 | 1400081017 | 8540 |
| 128 | 50379.08 | 313287 | 2610.73 | 462196288 | 1475.31 | 3.85 | 2688938060 | 8582 |
| 256 | 56665.19 | 349723 | 2914.36 | 861831677 | 2464.33 | 7.18 | 3035374281 | 8679 |
| 512 | 30971.91 | 186912 | 1557.60 | 1178414858 | 6304.65 | 9.82 | 1654374778 | 8851 |
从上面表格上面,可以看出:
1、随着并发数的增加(除了16并发和512并发),写入WAL的次数、TPS都是处于增加的状态。
2、在不同并发的情况下,平均每次写入WAL的字节数相差不大(除了16并发外)。
3、在16并发下,虽然写入WAL次数很多,但是由于平均每次写入WAL的字节数比较少,只有450Bytes,所以在16并发下写入WAL的总字节数并不高。
4、随着并发数的增加(除了512并发),虽然平均每次写入WAL的时延逐渐增加,但是由于WAL写入的平均并发数也逐渐增加,因此单位时间内写入的wal总量也是逐渐增加的。
5、在512并发时,资源争抢比较严重,导致平均每次写入WAL的耗时非常高,造成性能下降比较厉害。

上图是TPS值与WAL写入的相关性,从上图可以看出,TPS值与写入WAL总字节数的相关性更高。
纯读场景
使用以下命令对point_select场景进行测试:
sysbench --db-driver=pgsql --pgsql-user=postgres --pgsql-password='xxx' --pgsql-db=postgres --events=0 --report-interval=5 --pgsql-host=xxx --pgsql-port=15432 --table-size=5000000 --tables=8 oltp_point_select.lua run --time=120 --threads=xxx --rand-type='uniform'
point_select场景下的TPS值:
| 并发数 | He3DB | PostgreSQL |
|---|---|---|
| 16 | 186071.94 | 186899.11 |
| 32 | 321010.67 | 302824.01 |
| 64 | 304616.30 | 264051.55 |
| 128 | 272872.09 | 227140.23 |
| 256 | 254737.00 | 187309.68 |
| 512 | 210694.44 | 151027.42 |
从上面的测试结果可以看出,针对point_select场景,He3DB与PostgreSQL在小并发情况的TPS值相差不大,而在大并发的情况下,He3DB的性能比PostgreSQL高出20%~40%。
纯写场景
使用以下命令对update_non_index场景进行测试:
sysbench --db-driver=pgsql --pgsql-user=postgres --pgsql-password='xxx' --pgsql-db=postgres --events=0 --report-interval=5 --pgsql-host=xxx --pgsql-port=xxx --table-size=5000000 --tables=8 oltp_update_non_index.lua run --time=120 --threads=xxx --rand-type='uniform'
update_non_index场景下的TPS值:
| 并发数 | He3DB | PostgreSQL(主+半同步备) | PostgreSQL(主+异步备) |
|---|---|---|---|
| 16 | 4713.12 | 20320.54 | 41817.56 |
| 32 | 10521.40 | 30629.98 | 50980.50 |
| 64 | 24234.12 | 30693.83 | 49902.14 |
| 128 | 51467.30 | 32491.44 | 43286.30 |
| 256 | 76118.12 | 35891.06 | 28759.10 |
| 512 | 25038.29 | 30794.41 | 18506.31 |
从上面的测试结果可以看出:
1、随着并发数的逐渐增加,He3DB的TPS值持续增加,在256并发时达到最大值,之后再增加并发数到512时,导致性能下降的比较明显。这是因为在256并发时,cpu已经达到瓶颈了,再增加并发数,导致资源争夺比较厉害,从而性能会下降。
2、在并发数小的情况下,He3DB的TPS值比PostgreSQL相差较大,而随着并发的增加,两者之间的TPS逐渐缩小并反超,在256并发时He3DB的TPS是PostgreSQL的两倍还多。
3、在小并发时,PostgreSQL(主+异步备)会比PostgreSQL(主+半同步备)的性能要好,但是在大并发的时候(256和512),前者的性能要低于后者。
4、小并发的时候,He3DB的性能会明显低于PostgreSQL,但是随着并发的增加,两者之间的差距逐渐缩小并反超。
5、随着并发的增加,PostgreSQL很快能达到性能峰值,而He3DB在256并发才会达到峰值。
造成以上现象的原因,主要是在并发数小的情况下,wal写入的并发数比较小,而单次写入到TiKV的时延比写入到高性能磁盘的时延高很多,从而导致在小并发的情况下,He3DB与PostgreSQL的性能差距很大。随着并发数的增加,wal写入的并发数也在增加,单位时间内写入的wal也变多了,并且由于He3DB优化了wal写入的一些锁机制,以及去掉了FPW等操作,因此在大并发的情况,He3DB的性能会比PostgreSQL高很多。
测试分析
以下是在不同的并发下,写入wal到kv层的各耗时段的次数:
| 持久化wal耗时 | 16并发 | 32并发 | 64并发 | 128并发 | 256并发 | 512并发 |
|---|---|---|---|---|---|---|
| <1ms | 84515 | 3813 | 8622 | 14436 | 10751 | 1544 |
| 1~2ms | 41786 | 59073 | 107546 | 232212 | 297852 | 72927 |
| 2~3ms | 1217 | 1334 | 3375 | 14763 | 49188 | 24589 |
| 3~4ms | 195 | 270 | 783 | 2134 | 5707 | 3803 |
| 4~5ms | 57 | 226 | 664 | 1752 | 5389 | 6167 |
| 5~6ms | 21 | 23 | 60 | 192 | 675 | 1819 |
| 6~7ms | 14 | 4 | 16 | 48 | 114 | 187 |
| 7~8ms | 18 | 17 | 23 | 44 | 47 | 61 |
| 8~9ms | 9 | 2 | 19 | 70 | 114 | 109 |
| >9ms | 37 | 115 | 143 | 184 | 1036 | 1465 |
| 总计 | 127869 | 64877 | 121251 | 265835 | 370873 | 112671 |



从上面的表格和饼图可以看出:
1、在不同的并发数情况下,wal写入耗时绝大数不高于2ms。
2、随着压测程序并发的增加,写入wal的次数也增加了,同时较高耗时的写入比例也有所增加。
3、写入wal的耗时最长时间超过了9ms,而且随着压测程序并发数的增加,超过9ms的写入次数也增加了很多。
下面表格是关于update_non_index场景下TPS与WAL写入的一些统计信息:
| 并发数 | TPS | 写入WAL次数 | 平均每秒写入的WAL次数 | 写入WAL总耗时(us) | 平均每次写入WAL的耗时(us) | WAL写入的平均并发数 | 写入WAL字节数 | 平均每次写入WAL的字节数 |
|---|---|---|---|---|---|---|---|---|
| 16 | 4713.12 | 127869 | 1065.58 | 113105803 | 884.54 | 0.94 | 316560615 | 2475 |
| 32 | 10521.4 | 64877 | 540.64 | 88645280 | 1366.36 | 0.74 | 547204503 | 8434 |
| 64 | 24234.12 | 121251 | 1010.43 | 165789477 | 1367.32 | 1.38 | 1018637502 | 8401 |
| 128 | 51467.3 | 265835 | 2215.29 | 386964902 | 1455.66 | 3.22 | 2255616345 | 8485 |
| 256 | 76118.12 | 370873 | 3090.61 | 732366706 | 1974.71 | 6.10 | 3158802807 | 8517 |
| 512 | 25038.29 | 112671 | 938.93 | 927738898 | 8234.05 | 7.73 | 995953293 | 8839 |
从上面表格上面,可以看出:
1、在并发数不高于256时,随着并发数的增加,TPS都是处于增加的状态。
2、在不同并发的情况下(除了16并发以外),平均每次写入WAL的字节数相差不大。
3、随着并发数的增加(除了512并发),虽然平均每次写入WAL的时延逐渐增加,但是由于WAL写入的平均并发数也逐渐增加,因此单位时间内写入的wal总量也是逐渐增加的。
4、在16并发时,虽然写入WAL次数比较高,但是因为压测程序的并发数太低,导致单次写入的WAL量比较少,所以性能比较低。
5、在512并发时,资源争抢比较严重,导致平均每次写入WAL的耗时非常高,造成性能下降比较厉害。

上图是TPS值与WAL写入时一些指标的相关性,从上图可以看出,TPS值与写入WAL的总字节数的相关性更高。
读写混合场景
使用以下命令对read_write场景进行测试:
sysbench --db-driver=pgsql --pgsql-user=postgres --pgsql-password='xxx' --pgsql-db=sysbench --events=0 --report-interval=5 --pgsql-host=xxx --pgsql-port=xxx --table-size=5000000 --tables=8 oltp_read_write.lua run --time=120 --threads=xxx --rand-type='uniform'
read_write场景下的TPS值:
| 并发数 | He3DB | PostgreSQL(主+半同步备) | PostgreSQL(主+异步备) |
|---|---|---|---|
| 16 | 2730.95 | 4636.53 | 5559.18 |
| 32 | 6467.52 | 5761.44 | 7088.46 |
| 64 | 7903.57 | 5531.55 | 5832.17 |
| 128 | 6778.68 | 4601.42 | 4956.43 |
| 256 | 5722.02 | 3717.64 | 4084.03 |
| 512 | 4825.33 | 3045.18 | 3315.92 |
从上面的测试结果可以看出:
1、随着并发数的增加,He3DB的TPS值也逐渐增加;PostgreSQL的TPS值也逐渐增多,在一定并发时达到峰值,并发数再增加,反而TPS值在逐渐下降。
2、相较于PostgreSQL(异步备),随着并发数的变化,He3DB的TPS值变化幅度很大。He3DB的最小TPS值明显小于PostgreSQL,最大TPS也明显高于PostgreSQL。
测试分析
以下是在不同的并发下,写入wal到kv层的各耗时段的次数:
| 持久化wal耗时 | 16并发 | 32并发 | 64并发 | 128并发 | 256并发 | 512并发 |
|---|---|---|---|---|---|---|
| <1ms | 578 | 1820 | 1742 | 1586 | 359 | 101 |
| 1~2ms | 41466 | 91932 | 109542 | 89029 | 67703 | 46514 |
| 2~3ms | 3114 | 3941 | 9631 | 14943 | 14853 | 16225 |
| 3~4ms | 237 | 391 | 918 | 1521 | 1575 | 2049 |
| 4~5ms | 80 | 281 | 703 | 1093 | 1738 | 2558 |
| 5~6ms | 29 | 41 | 130 | 244 | 651 | 1326 |
| 6~7ms | 10 | 5 | 31 | 45 | 92 | 212 |
| 7~8ms | 12 | 10 | 18 | 9 | 13 | 46 |
| 8~9ms | 12 | 17 | 21 | 31 | 30 | 17 |
| >9ms | 30 | 44 | 591 | 992 | 1594 | 1928 |
| 总计 | 45568 | 98482 | 123327 | 109493 | 88608 | 70976 |



从上面的表格和饼图可以看出,针对read_write场景,He3DB的WAL写入的情况与update_non_index场景相似:
1、在不同的并发数情况下,wal写入耗时绝大数处于1~2ms的范围内。
2、随着压测程序并发的增加,写入wal的次数也增加了,同时较高耗时的写入比例也有所增加。
3、写入wal的耗时最长时间超过了9ms,而且随着压测程序并发数的增加,超过9ms的写入次数也增加了很多。
下面表格是关于read_write场景下TPS与WAL写入的一些统计信息:
| 并发数 | TPS | 写入WAL次数 | 平均每秒写入的WAL次数 | 写入WAL总耗时(us) | 平均每次写入WAL的耗时(us) | WAL写入的平均并发数 | 写入WAL字节数 | 平均每次写入WAL的字节数 |
|---|---|---|---|---|---|---|---|---|
| 16 | 2730.95 | 45568 | 379.73 | 70707306 | 1551.69 | 0.59 | 448620782 | 9845 |
| 32 | 6467.52 | 98482 | 820.68 | 144588775 | 1468.17 | 1.20 | 925331227 | 9395 |
| 64 | 7903.57 | 123327 | 1027.73 | 374019185 | 3032.74 | 3.12 | 1188444016 | 9636 |
| 128 | 6778.68 | 109493 | 912.44 | 742519798 | 6781.44 | 6.19 | 1108798358 | 10126 |
| 256 | 5722.02 | 88608 | 738.40 | 1154016834 | 13023.84 | 9.62 | 867716655 | 9792 |
| 512 | 4825.33 | 70976 | 591.47 | 1262415358 | 17786.51 | 10.52 | 680758729 | 9591 |
从上面表格上面,可以看出:
1、在并发数不超过64时,随着并发数的增加,写入WAL的次数、TPS都是处于增加的状态。
2、在不同并发的情况下,平均每次写入WAL的字节数相差不大。
3、在并发数不超过64时,随着并发数的增加,虽然平均每次写入WAL的时延逐渐增加,但是由于WAL写入的平均并发数也逐渐增加,因此单位时间内写入的wal总量也是逐渐增加的。
4、在并发数高于64时,随着并发数的增加,TPS、写入WAL次数和写入WAL字节数都是逐渐下降。
5、随着并发数的增加,平均每次写入WAL的耗时和平均并发数都是逐渐增加。

上图是TPS值与WAL写入的相关性,从上图可以看出,TPS值与写入WAL的总字节数的相关性更高。
小结
在CPU受限的情况下,通过以上几个场景对He3DB和PostgreSQL的性能进行对比,可以发现:
- 随着并发的逐渐增加,所有测试场景下He3DB的TPS值都是逐渐增加的。
- 在16并发时,由于并发比较小,所以平均每次写入WAL的字节数比较少。
- 对于写场景来说,TPS值与写入WAL总字节数的相关性比较高。
- 对于写场景来说,当CPU达到瓶颈后再增加并发数,He3DB的TPS值会下降很多。
- 对于读场景,在小并发情况下,He3DB的TPS值和PostgreSQL接近,而在大并发情况下,He3DB的性能比PostgreSQL高出20%~40%。
本文主要介绍了在CPU受限的情况下,He3DB与PostgreSQL在不同场景下的性能对比。




