MariaDB 5.5 在 Windows 上的性能

我们有一段时间没有发布任何 Windows 基准测试了,并且 MariaDB for Windows 包含一些特定的改进,这些改进可能尚未广为人知,因为我们还没有太多地谈论它们。这篇文章试图解决这个问题。我们还将分享当前的 MySQL 5.5 数据。

我的设置是一台 8 核 2 插槽服务器(是的,对于现在来说有点过时,但这是我手头最好的机器),配备 RAID1 的 10K SAS 磁盘。我运行了 sysbench 0.4 单表 / 1,000,000 条记录。我在网络上运行了基准测试,并发客户端数量从 4 到 4096。

以下是 OLTP-readonly 吞吐量的情况

  • 在大多数测试中,MariaDB 的吞吐量比 MySQL 高约 10%
  • 对于 4096 个并发客户端,MariaDB 的吞吐量比 MySQL 5.5 高出 476%(2382 TPS 对比 413 TPS)。

许多人正确地指出,吞吐量不一定代表整体性能,并且在 OLTP 基准测试中,公平性也很重要。实际上,它通常比吞吐量更重要。我同意,因此下面是 95% 响应时间的结果,这意味着 95% 的事务在给定时间内完成。

OLTP Readonly 响应时间,第 95 百分位数

并发客户端 4 8 16 32 64 128 256 512 1024 2048 4096
MariaDB 4.87 6.81 8.83 12.35 22.12 43.56 90.35 180.57 619.05 1003.88 1965.77
MySQL 4.86 7.14 9.96 16.21 37.39 101.33 238.89 499.63 971.07 2241.83 25215.29

如上表所示,MariaDB 5.5 在行吞吐量和公平性方面都优于 MySQL 5.5。实际上,公平性(响应时间)的结果比行吞吐量更令人印象深刻。

但是,为什么 MariaDB 在 Windows 上的只读测试中表现优于 MySQL 5.5?为什么它会比 5.5 更好?毕竟,它是基于相同的代码库,所以性能应该大致相等。答案不是我们的优化器增强功能,也不是 XtraDB 在 MariaDB 中充当 InnoDB。答案是MariaDB 线程池。这是我在 5.5 版本中加入的功能,我很高兴它表现得如此出色,并且我很高兴它在 Windows 上默认是“开启”的(所以,Windows 用户,您无需做任何事情来开启它)。

那么,为什么使用线程池会带来如此好的性能呢?答案是其实现将池大小调整和回调运行的所有责任委托给了 Windows 原生线程池,因此它就像是操作系统内部的一个黑匣子,只负责提供好的结果。如果您想知道,Windows 原生线程池的核心是久负盛名的 IO 完成端口(IO completion port),这是 Windows 自 NT 3.5 时代以来就有的功能。它是 Windows 的独特功能,也是任何运行在该平台上的服务器应用程序正在使用或应该使用的东西。使其运行良好的技巧有:

  • 它不允许太多线程同时在“CPU 上”运行(这减少了上下文切换)。根据我的经验,减少上下文切换是提高吞吐量的最重要因素。
  • 它以 LIFO(后进先出)顺序激活等待完成的线程——“热”线程保持“热”,从而减少缓存未命中
  • IO 完成以 FIFO(先进先出)顺序处理——这就是为什么公平性表现如此之好
  • 是的,它自然减少了对热点锁的争用。

只读性能和线程池就说到这里吧。

下一个有趣的问题是 MariaDB 在写入工作负载上表现如何。因此,让我们在最终的“只写”模式下运行 sysbench,这也称为 update_non_index(每个查询仅增加一个非索引的 int 列)。为了最大化写入吞吐量,我将 innodb_flush_log_at_trx_commit 参数设置为 0,这样日志每秒刷新一次,而不是在每次事务提交时刷新。

以下是结果

OLTP 只写 (update_non_index/flush_log=0) 吞吐量:

这看起来相当不错。这种差异可能是许多因素的组合。XtraDB 的写入性能、组提交和线程池都可能对结果产生积极影响(对 MariaDB 有利)。然而,我认为 MariaDB 在 Windows 上的异步 IO 优化(它同样使用了完成端口)是造成巨大差异的主要原因。实际上,我在实现该功能时就第一次看到了这种差异。

上述测试中所有与 IO 相关的参数和 Innodb 参数都是默认值。结果好得几乎令人难以置信,所以我真的想通过改变 innodb_io_capacity 和/或 innodb_write_io_threads 来让 MySQL 达到更好的 IO 吞吐量,但没有成功。有人知道这里的窍门吗?

OLTP 只写 (update_non_index/flush_log=0) 响应时间,第 95 百分位数

并发客户端 4 8 16 32 64 128 256 512 1024 2048
MariaDB 0.33 0.63 0.75 1.06 1.94 3.85 8.25 21.38 129.79 274.40
MySQL 0.32 0.61 0.73 1.61 7.62 26.82 96.45 219.29 661.19 2723.36

为了完整性,以下是我使用的数据库参数。

[mysqld]
sql-mode="NO_ENGINE_SUBSTITUTION"
back_log=500
user=root
port=3306
max_connections=4096
max_connect_errors=5000
max_prepared_stmt_count=50000
table_cache=2048
transaction_isolation=REPEATABLE-READ
loose-skip-external-locking
innodb_status_file=0
innodb_data_file_path=ibdata1:200M:autoextend
innodb_buffer_pool_size=1G
innodb_additional_mem_pool_size=20M
innodb_log_file_size=650M
innodb_log_buffer_size=100M
innodb_support_xa=0
innodb_doublewrite=0
innodb_flush_log_at_trx_commit=0
query-cache-size=0
query-cache-type=0
symbolic-links=0
skip-grant-tables