-
Notifications
You must be signed in to change notification settings - Fork 4
MyTopling Sysbench With Other MySQL
MyTopling 是基于 ToplingDB 的 MySQL,分叉自 MyRocks,ToplingDB 则分叉自 RocksDB,兼容 RocksDB 接口,从而 MyTopling 可以复用 MyRocks 的大部分成果。
目前 MyTopling 通过云原生的 DBaaS 向用户提供,我们为此制作了一个 视频教程 帮助用户快速上手,用户也可以自己从源码 编译、安装、部署。
sysbench 是一个模块化的、跨平台、多线程基准测试工具,主要用于评估测试各种不同系统参数下的数据库负载情况。它主要包括以下几种方式的测试:
- CPU 性能,磁盘 IO 性能
- 调度程序性能,POSIX 线程性能
- 内存分配及传输速度
- 数据库性能(OLTP 基准测试)
sysbench 的数据库 OLTP 测试支持 MySQL、PostgreSQL、Oracle,目前主要用于 Linux 操作系统,开源社区已经将 sysbench 移植到了Windows,并支持 SQL Server 的基准测试。 所以,我们用 sysbench 对 MyTopling 进行基准测试,并与主流的 MySQL 变体(原版 MySQL,MyRocks,PolarDB)进行对比。因为原版 sysbench 有一些不足之处,所以我们自己将其 fork 过来做了一个修改版,修改主要有以下几点:
对于非索引的字符串列,原版 sysbench 使用随机生成的数据进行填充,这对于快速摸底 SQL 性能非常方便,但是随机生成的数据无法模拟业务中的真实场景。所以,我们给 sysbench 增加了从文件加载真实数据的功能(新增了 --use-file 和 --filename 命令行选项),从而可以使用真实的业务数据来测试。
随机数据与真实数据针对的是非索引的字符串字段。 针对索引字段,sysbench 使用的是整数,并通过 --randtype=XXXX 指定其随机数分布,默认情况下,随机数分布是 special,测试的是有大量热数据的场景,要测试均匀分布的场景,需要显式指定随机数分布 --randtype=uniform。我们在测试中均使用了 --randtype=uniform 选项(真实数据测试也需要该选项)。
通过二级索引搜索时,如果仅获取二级索引的字段和主键字段,就只需要访问二级索引本身,而不需要访问其它字段的内容,这叫做 Covering Index。
sysbench 的 select_random_ranges 测试就命中了 Covering Index:
SELECT count(k) FROM sbtest1 WHERE k BETWEEN ? AND ? OR ...
这就导致 select_random_ranges 的结果没有太大的参考价值,所以,我们增加了一个 --secondary_ranges 命令行选项,表示通过二级索引搜索时是否回表,默认为1,对原 SQL 语句进行一个很小的修改,通过访问非索引字段 c,让 MySQL 执行回表操作:
SELECT sum(length(c)) FROM sbtest1 WHERE k BETWEEN ? AND ? OR ...
在 oltp_read_only 和 oltp_read_write 中,--secondary_ranges=1 时,会增加一项新的测试:
SELECT length(c) FROM sbtest{idx} WHERE k >= {rand} LIMIT {range_size}
-- 该测试通过二级索引搜索非索引字段 c,从而引发强制回表。
对于 MySQL/MyTopling/PolarDB,从二级索引回表时,会使用 MRR(Multi-Range Read),MyTopling 对此进行了深度优化。 对于 select_random_ranges,如果不回表(secondary_ranges=0),就会命中 Covering Index,测试出来的结果比回表要高几十倍。
对于回表查询,返回字符串列的内容,需要消耗很大的网络带宽,例如对 wikipedia 数据,单条数据平均长度 2.8K,很容易就会把网络带宽打满。我们在测试中就遇到了这个问题:在 select_random_points 测试中,MyTopling 远远超出了网络基础带宽,突发带宽持续一会儿,就被云平台限速了。 所以,我们需要修改 sysbench 的 select 语句,既让它访问字符串列引发回表,但又避免消耗巨大的网络带宽,将以下语句:
SELECT id, k, c, pad FROM sbtest1 WHERE k IN (...)
修改为(详情可参见此提交记录):
SELECT id, k, length(c), length(pad) FROM sbtest1 WHERE k IN (...)
PolarDB 我们使用 8c32g 的规格(MySQL 8.0),CPU 具体型号、频率未知,MySQL 客户端只连主结点。 MyTopling 和其它 MySQL 发行版使用 ECS 云服务器,也是 8c32g,数据库存储使用性能型 NAS 或 本地 SSD。NAS 的好处是容量几乎无限,并且带宽可以在基础带宽之上随容量线性扩展。
存储 | ECS 规格(8c32g) | CPU 型号 | CPU 基频 | CPU 睿频 | 网络 PPS | 网络带宽 | 综合性能 |
---|---|---|---|---|---|---|---|
性能型 NAS | ecs.g7.2xlarge | Xeon 8369B | 2.7G | 3.5G | 160万 | 5G~10G | 稍强 |
本地 SSD | ecs.i3g.2xlarge | Xeon 8269CY | 2.5G | 3.2G | 175万 | 3G~10G | 稍弱 |
因为 PolarDB 没有 binlog,所以其它 MySQL 也一律关闭 binlog,但 InnoDB 的 Redo Log 和 ToplingDB/RocksDB 的 WAL Log 都是打开的,innodb_flush_log_at_trx_commit 和 rocksdb_flush_log_at_trx_commit 均为 2(每秒刷盘)。
测试中使用的 MyTopling 版本为 topling-8.0.28,fork 自该测试中使用的 myrocks-8.0.28。
原版 MySQL 使用 yum 安装的版本:8.0.26。关键配置项:
关键配置 | MyTopling | MyRocks | PolarDB | 原版 MySQL |
---|---|---|---|---|
发行方式 | 自己编译 | 自己编译 | 云 DB 服务 | yum 安装 |
MySQL 版本 | 8.0.28 | 8.0.28 | 8.0.1.1.29.1 | 8.0.26 |
binlog | off | off | off | off |
flush_log_at_trx_commit | 2 | 2 | 1 | 2 |
block cache size buffer_pool_size |
NA | 24G | 24G | 24G |
MemTable | Topling CSPP | SkipList | NA | NA |
SST | Topling Table | BlockBasedTable | NA | NA |
Compact | 分布式 | 本机 | NA | NA |
部分 sysbench 测试,要求 table 数量必须为 1,为统一起见,对所有测试我们都将 table 数量设为 1。 对随机数据和文件数据,我们分别测试了:
数据来源 | table 数量 | 行数(row) | 数据尺寸 | 平均每行 |
---|---|---|---|---|
随机生成数据 | 1 | 2 亿 | 40 G | 约 200 字节 |
wikipedia 文件 | 1 | 3800 万 | 109 G | 约 2.8 KB |
可以看到,PolarDB 确实名不虚传,综合性能比原版 MySQL 和 MyRocks 高很多。
MyTopling 得益于分布式 Compact 和可检索内存压缩等一系列先进技术,同时在性能和存储空间上远远领先原版 MySQL 和 MyRocks。 相比 PolarDB,MyTopling 仍然有很多优势:
- 节省了 4~5 倍的存储空间
- 写性能大幅领先 PolarDB
- 读性能
- MyTopling 的覆盖索引查询落后于 PolarDB
- 使用 NAS 时,因为存储的带宽和延迟相比 PolarDB 差太多,MyTopling 只有部分指标领先
- 使用本地 SSD 时,除覆盖索引之外,MyTopling 的所有指标均领先 PolarDB
在 wikipdia 的测试中,我们增加了一个 PolarDB-C ,指 PolarDB 开启 ROW_FORMAT=COMPRESSED
,其它参数完全一样。
我们将整个测试分成了多个阶段:prepare,read,compact,read,write,read。
uncompacted | prepare 之后,compact 之前的空间占用 |
---|---|
compacted | compact 之后,write 之前的空间占用 |
注1: 图中未显示 write 测试之后的空间占用,因为各个 DB write 速度不同,但测试时间相同,导致 write 的数据量不同,总的空间占用没有可比性。 注2: PolarDB 和原版 MySQL(InnoDB) 无 Compact(实践中也不推荐 optimize table),图中表现为 uncompacted 和 compacted 尺寸相同。
我们使用 auto_increment 主键,并将 prepare 分成两个阶段:插入数据 和 创建索引 。这样我们可以分别衡量各个阶段的耗时。
可以看到,insert 阶段,跑在在 NAS 上的 MyTopling 最快,比跑在本地 SSD 上更快,因为 NAS 对分布式 Compact 更友好,MyTopling 只比 MyRocks 快一点点,这是因为 sysbench insert 时每个表只有一个线程,无法发挥 MyTopling 的多线程优势。
create index 时,跑在本地 SSD 上的 MyTopling 更快,因为 create index 要从头至尾扫描全表,而 prepare 之后数据量超出了内存大小,重新(单线程)从头至尾扫描,刚好每次都会缓存不命中,从而瓶颈在(单线程)存储带宽上,本地 SSD 就占优了。MyTopling SSD 的性能只有 MyRocks 的两倍多一点,这是因为尽管 MyTopling 中 create index 的关键步骤性能提高了二三十倍,但综合耗时被其它步骤拖累了。
sysbench 中的测试包含单项测试与混合测试,我们的 read 测试仅对比单项测试,测试中线程数是 32。
write 分为 oltp_write_only 和 oltp_insert 两个测试项,oltp_write_only 是个混合测试,oltp_insert 是单项测试,就单纯的插入。
-- oltp_write_only 混合测试有四种语句:
UPDATE sbtest1 SET k=k+1 WHERE id=? -- 1: index_updates 更新的列上有二级索引
UPDATE sbtest1 SET c=? WHERE id=? -- 2: non_index_updates 更新的列上无二级索引
DELETE FROM sbtest1 WHERE id=? -- 3: 删除
INSERT INTO sbtest1 (id, k, c, pad) -- 4: 插入, oltp_insert 单项测试仅包含该语句
VALUES (?, ?, ?, ?)
因为是多线程写,MyTopling 的多线程事务处理能力就充分地表现出来了(对比 prepare 阶段单线程写),oltp_write_only 因为包含 update,而 update 需要读(并且会命中某条数据),所以 MyTopling NAS 因为 IO 原因,性能指标低了很多。oltp_insert 也要读(unique_check),但不会命中任何数据。 每个数据库的写性能不同,但测试项执行的时间一样,所以新写入的数据量差异巨大:
实际上更新的数据量也有很大差异,但在此图中体现不出来,因为用的是 select max(id) - {prepared_row}
。
oltp_point_select 是最简单的测试:SELECT length(c) FROM sbtest1 WHERE id = ?
三组柱状图分别表示三个阶段中的 read。
MyTopling 得益于可检索内存压缩算法,空间占用小,缓存命中率高,所以性能跟 PolarDB(不压缩)不相上下,特别是 MyTopling NAS compact 之后的性能,比 PolarDB 高很多,也比 MyTopling SSD 更高,因为此时数据可以全部放进内存,而 MyTopling NAS 的 CPU 比 MyTopling SSD 的要更强。 PolarDB-C 相比 PolarDB 虽然节省了大约一半的存储空间(仍然比 MyTopling 要大很多,参考前面的空间占用对比),但性能下降很多。
这个查询语句是:SELECT id, k, length(c), length(pad) FROM sbtest1 WHERE k IN (...)
,
该语句既通过次级索引执行了回表操作,还通过 length 函数,避免了消耗太大的网络带宽。这个查询语句会使用 MySQL 的 MRR(Multi Range Read),MyTopling 对此通过 MultiGet 使用 io_uring 进行了深度优化,性能最好。
MyTopling NAS 在 write 之后的性能不够好,是因为达到了 NAS 的 IOPS 上限(3万),因为平均每条语句访问 100 条数据,所以这个 TPS 要乘以 100,才是等效的 QPS。
查询语句是:
SELECT count(*), sum(length(c)) FROM sbtest1 WHERE id IN
(SELECT * FROM (SELECT id FROM sbtest1 WHERE k BETWEEN ? AND ? [OR ...] LIMIT 100) as t)
这个语句比较复杂,但拆解开来还是很简单的,就是通过 secondary index k 按多个范围选取一些 id,再通过这些 id 回表,这个查询同样会用到 MRR。
整体的指标结果跟 select_random_points=100 类似,原因也类似。
查询语句是:SELECT count(k) FROM sbtest1 WHERE k BETWEEN ? AND ? OR [ ... ]
原版 sysbench 的 select_random_ranges 仅支持这个语句,该查询会使用 Covering Index,不回表,从而全部在内存中操作,体现的是 CPU 的性能和代码的优化,该项测试 PolarDB 优势明显,比 MyTopling 还快不少。
after write MyTopling 性能降低明显,是因为 MyTopling 写得最快,从而写的数据也最多,LSM 读放大的负面影响就充分体现出来了。
MyTopling 通过拥抱云原生,同时优化了性能与成本(存储+计算),达到了弹性伸缩、降本增效的目的。
对随机生成数据的测试,无 PolarDB-C(ROW_FORMAT=COMPRESSED)及以下差异:
MyTopling NAS | acceptCompressionRatio=0.55 |
---|---|
MyTopling SSD | acceptCompressionRatio=0.80 |
压缩后的数据大于未压缩的 XX 倍时,放弃压缩,这是因为越是难以压缩的数据,压缩解压需要消耗的 CPU 越多,同时存储空间上的收益也越少,这是一个双重劣势。而随机生成的数据难以压缩(真实的业务数据也有一些难以压缩),这是一种巨大的浪费,所以 acceptCompressionRatio 是一个阈值,来划定“容易压缩”与“难以压缩”的界线。
sysbench 随机生成的数据,压缩率在 0.6~0.7 之间。这样,读测试中 MyTopling NAS 需要解压,MyTopling SSD 读的是原始数据,无需解压。
其它指标特征和背后的原理,与 wikipedia 测试结果类似:
对于 MyTopling NAS 和 MyTopling SSD,create index 阶段的差异,部分在于数据是否压缩了,部分在于网络带宽。
由此图可见,即便在压缩率较差的情况下,Topling 可检索内存压缩算法仍然保持很高的读取(解压)性能,于是显得 acceptCompressionRatio 这个配置项似乎无关紧要了(设为 1.0)。
这个图表趋势与上图很相似,因为同是回表查询。
不回表的这个测试,相比 wikipedia 真实数据,PolarDB 比 MyTopling 的优势更大了。
您可以按照该测试流程复现以上测试结果,注意:连接 MyTopling 的客户端 ECS 服务器至少需要4核8G,并且与 MyTopling 在同一个可用区(在 topling 控制台查看),VPC 需要选择 for-topling-XXX。
MyTopling 是云原生数据库,运行在公有云平台上,目前仅支持阿里云(将来我们会支持所有主流公有云),并且只有 NAS 版(本地 SSD 版稍后推出),所以,您需要使用自己的阿里云账号来访问 MyTopling 数据库服务。同时,因为阿里云的第三方应用市场的局限性,不支持第三方应用作为服务通过内网与用户连接,所以您还需要创建一个 topling 账号,为了让您能快速开始体验,我们制作了一个视频教程,看完该视频教程,您就可以按照以下步骤开始测试了:
sudo yum -y install git make automake libtool pkgconfig libaio-devel mysql-devel
sudo yum -y remove sysbench # 删除系统现有的 sysbench (如果有的话)
git clone https://github.com/topling/sysbench.git
cd sysbench
./autogen.sh
./configure --prefix=/usr
make -j`nproc`
sudo make install
我们将重现以上测试结果的脚本放在 github 上,方便您快速重现。
git clone https://github.com/topling/sysbench-test
wget https://topling.cn/downloads/mount-test.sh && chmod +x ./mount-test.sh && ./mount-test.sh /mnt
解压数据(需要在阿里云购买 400G 数据盘用于存放解压后的数据)
zstd -d /mnt/wikipedia-flat-rand.zst -o /wikidata/wikipedia-flat-rand.txt
更快捷方便的方法是不用把解压后的数据存盘,而是直接使用 shell 语法:
--filename=<(while true; do zstd -d -c -q /mnt/wikipedia-flat-rand.zst; done)
<(...)
会被 bash 替换成一个文件名,这个文件名是个管道,解压后的数据被发送到这个管道中,程序(sysbench)就从这个管道中读取解压后的数据。
shell> mysql -h {MyToplingServer} -P 3306 -uadmin -p{Password}
mysql> create database wikipedia; -- for wikipedia file data
mysql> create database randdata; -- for sysbench auto generated random data
在命令行上添加 --use-file=on --filename=/path/to/wikipedia.txt
,就是文件测试,否则就是默认的随机数据测试。
sysbench --report-interval=1 --db-driver=mysql --mysql-port=3306 \
--mysql-user=root --mysql-db=sysbench --mysql-host={MyToplingServer} \
--tables=1 --mysql_storage_engine='rocksdb default charset latin1' \
--table-size=38508221 --rand-type=uniform --create_secondary=on \
oltp_insert prepare
如果该语句可以正常执行,说明您的软硬件环境已经配置好了,接下来就可以执行全套测试脚本了。