Mysql - 基准测试和压力测试


👀 基准测试和压力测试


特点/测试类型🎯 基准测试 (Benchmarking)🚀 压力测试 (Stress Testing)
目标测量系统在特定工作负载下的性能。确定系统的极限性能及在超负荷时的行为。
工作负载使用标准化或预定义的工作负载。超出预期的工作负载,推至极限。
结果提供性能指标,如每秒事务数、响应时间等。揭示系统的弱点、瓶颈和可能的崩溃点。
应用场景评估硬件配置、软件版本或优化策略。确定系统最大容量,保证极端条件下稳定性。
测试时长在固定的、预定义的时间段内进行。直到系统达到其断点或崩溃。
后续行动基于结果进行系统优化或调整。解决找到的问题或瓶颈,确保稳定性。

👀 MySQL 基准测试 (Benchmarking)


📌 为什么要基准测试?


  • 基准测试是评估和测量系统在特定负载下的性能的一种方法。通过这种方式,可以得知系统在给定工作负载下的表现,这有助于进行性能调优、资源规划和系统配置的决策。
  • 基准测试提供了一个系统性能的快照,使得在相同的条件下,对某项疑点进行验证。虽然有诸多限制,但只要清楚其原理并知道如何解析结果,基准测试仍然是一个非常有用的工具。

🌟 基准测试的重要性:


  • 验证假设 🧪: 对系统的一些假设进行验证,确认这些假设是否符合实际情况。
  • 重现异常行为 ⚠️: 帮助开发和运维团队重现并定位系统中的某些异常行为,以便解决。
  • 测试当前运行情况 📊: 如果不清楚系统当前的性能,就无法确认某些优化的效果。基准测试提供了一个明确的性能参考点。
  • 模拟未来压力 💥: 基准测试可以模拟比当前系统更高的负载,帮助识别系统的扩展性瓶颈。
  • 规划未来的业务增长 🚀: 评估未来业务增长对资源的需求,如何硬件、网络和其他资源。
  • 测试应用适应性 🔄: 例如,观察系统在随机的并发峰值下的性能表现。
  • 测试不同的配置 🔧: 如 RAID 5 vs RAID 10, Linux 2.4 vs 2.6, MySQL版本升级等。
  • 验证新设备配置 ✅: 证明新采购的设备是否按预期工作。

🚫 基准测试的局限性:


  • 虽然基准测试非常有用,但它不是真实的压力测试。它施加给系统的压力相对真实压力来说,通常比较简单。真实压力是不可预期的,而基准测试的结果可能受到测试工具自身的局限性影响。

📊 MySQL 基准测试策略深入探讨


  • 基准测试应针对那些对用户最为关心的指标。根据用户的需求来设计基准测试,并避免过于狭隘地关注某些指标而忽视其他重要指标。
  • 但是,应用的整体基准测试可能复杂且耗时,尤其是当需要模拟大量的数据和压力时。

🔍 基准测试策略


MySQL 基准测试有两种主要策略:

  1. 集成式 (Full-stack) 🌐: 这种策略针对整个系统的整体进行测试。
  2. 单组件式 (Single-component) 🛠: 专注于单独测试 MySQL。

为什么选择集成式测试?

  • 关注应用整体性能 ⚡: 用户更关心的是整个应用的性能,而不仅仅是数据库。
  • 揭示真实瓶颈 🚫: MySQL 并不总是性能瓶颈,全栈测试可以揭示这一点。
  • 缓存的影响 🔄: 整体应用的测试更能揭示缓存在各个部分之间的影响。

为何选择单组件式测试?

  • 针对性测试 🔍: 有时只需了解 MySQL 的性能。
  • 快速“周期循环” ⏱: 通过短期的基准测试快速检测某些调整的效果。
  • 真实数据集测试 📈: 如果可能, 使用生产环境的数据快照进行测试。

🎖 测试何种指标?


1. 吞吐量 (Throughput) 🚀

  • 描述: 表示单位时间内的事务处理数量。
  • 单位: TPS (每秒事务数) 或 TPM (每分钟事务数)

2. 响应时间/延迟 (Response Time/Latency)

  • 描述: 任务所需的整体时间。
  • 单位: 微秒、毫秒、秒或分钟。
  • 特点: 使用百分比响应时间来表示系统的表现,如95%的请求在5ms内完成。

3. 并发性 (Concurrency) 🧑‍🤝‍🧑

  • 描述: 任意时间点上同时发生的并发请求数量。
  • 注意点: 不要将创建数据库连接和并发性混淆。

4. 可扩展性 (Scalability) 📈

  • 描述: 系统在增加工作量或资源时的性能表现。
  • 重要性: 对于容量规划非常重要,可以揭示应用瓶颈。

📊 基准测试方法


在我们深入讨论如何设计和执行基准测试之前,先来看一下如何避免一些常见的错误。以下是可能导致基准测试结果无效或不精确的一些常见错误:

  • 使用不完整的数据:例如,只使用了数据的一个小子集。
  • 使用错误的数据分布:不考虑真实系统中的数据热点。
  • 使用不真实的用户行为:不模拟真实用户的行为模式。
  • 在多用户场景中只做单用户的测试
  • 在单服务器上测试分布式应用
  • 反复执行相同的查询:可能会导致不真实的缓存命中率。
  • 未检查错误日志:可能会忽略某些关键问题。
  • 忽略系统预热的过程
  • 使用默认的服务器配置:而不是优化过的配置。
  • 测试时间太短:可能无法捕捉到所有的性能问题。

📐 设计和规划基准测试


🎯 规划基准测试流程

1️⃣ 标准测试 vs 专用测试
  • 📋 选择标准测试:确保选择合适的测试方案。
    • 示例:选择已经公认的数据库性能测试工具,如 TPC-C。
  • 🛠 设计专用测试:通常更为复杂,需要多次迭代。
    • 示例:为特定的应用或业务流程设计一个性能测试。
2️⃣ 获取和准备测试数据
  • 🗃 获取生产数据:捕获生产数据集的快照。
    • 示例:从生产数据库中导出最近一个月的订单数据。
  • 🔄 数据还原:确保数据快照能轻松还原。
    • 示例:使用备份工具将数据导入到测试数据库中。
3️⃣ 运行查询
  • 📊 建立单元测试:建立测试集并运行。
    • 示例:编写针对特定功能(如订单查询)的查询语句。
  • 🔁 重播查询:记录生产系统中的所有查询并进行重播。
    • 示例:使用日志工具捕获生产环境中的实际查询,然后在测试环境中重放。
4️⃣ 记录查询
  • 📏 多级记录:在不同级别(如 HTTP 请求或 MySQL 查询日志)记录查询。
    • 示例:捕获用户在Web界面发起的HTTP请求,同时记录后端数据库的查询日志。
  • 多线程执行:确保查询能在多线程中并行执行。
    • 示例:使用并发测试工具模拟多个用户同时执行查询。
5️⃣ 测试规范
  • 📜 文档化规范:详细记录测试规范。
    • 示例:创建一个文档,详细描述测试环境、测试目的、预期结果等。
  • 📌 关键信息:记录如测试数据、系统配置和预热方案等信息。
    • 示例:记录测试使用的具体数据集、数据库版本、硬件配置和预热方法等。

📌 基准测试的时长


🔹 预热
确保系统已经从初始状态转移到稳定状态。
🔸 示例: 在开始正式的MySQL性能测试前,可以执行一些高压力的查询,如SELECT * FROM large_table,来预热数据库的缓存并填充InnoDB的buffer pool。

🔹 持续时间
测试时间应足够长,使系统从初始状态转移到稳定状态。
🔸 示例: 如果测试一个电商网站的性能,可以考虑模拟一个日常的24小时销售周期,包括低流量的深夜时段和高流量的促销活动时段。


📊 获取系统性能和状态


🔸 系统状态和性能指标
如CPU使用率、磁盘I/O等。
🔹 示例: 使用top命令可以实时查看系统的状态,包括CPU使用率、内存使用情况等;使用iostat -x 1命令可以查看磁盘I/O性能。

🔸 MySQL性能数据
使用特定的shell脚本定期收集。
🔹 示例: 可以设置一个cron任务,每分钟执行一次SHOW GLOBAL STATUS命令,并将结果追加到一个日志文件中。

🔸 数据组织
数据应组织到不同的文件中,每个文件对应一个特定的时间点。
🔹 示例: 可以使用时间戳命名文件,例如在每小时的开始创建一个新的文件,如2023-05-01_10-00-status.log,并在此文件中记录这一小时的所有数据。


📈 获得准确的测试结果


选择正确的基准测试
根据系统的特点进行选择。
🔹 示例: 对于一个在线视频流平台,可以考虑使用类似于Netflix的Chaos Monkey的工具,来模拟真实环境中的故障并观察系统的表现。

确保测试的重复性
重复运行以确保结果的一致性。
🔹 示例: 运行基准测试三次,每次都重置测试环境,并确保每次的测试参数都是一致的。

考虑所有的影响因素
例如外部的干扰、定时任务等。
🔹 示例: 在进行基准测试时,确保关闭所有不必要的后台进程和应用,如自动更新、定时备份等。


🖥️ 运行基准测试并分析结果


🔍 自动化
避免人为错误,确保一致性。
🔸 示例: 使用Jenkins设置一个持续集成流水线,每当代码更新时自动执行基准测试。

🔍 多次运行
确保结果的稳定性。
🔸 示例: 设置一个定时任务,每天的固定时间自动运行基准测试,并将结果保存到数据库中。

🔍 数据分析
从原始数据中提取有意义的信息。
🔸 示例: 使用Python的pandas库对测试数据进行分析,如计算平均响应时间、95%的响应时间等,并将这些指标绘制成图表。


🎨 绘图的重要性


📉 周期性性能下降
图形化展示可以帮助快速发现这类问题。
🔸 示例: 使用Grafana或Kibana等可视化工具,连接到性能监控的数据源,实时绘制系统的吞吐量、响应时间等指标的图表。

📉 数据可视化
通过图形表示,可以更好地理解和分析数据。
🔸 示例: 使用Python的matplotlib或seaborn库,根据收集到的性能数据绘制时序图或箱线图,从而直观地看到性能的变化趋势或异常值。


🛠️ 基准测试工具


📊 集成式测试工具


🌐 Apache Benchmark (ab)

  • 简介: ab 是 Apache HTTP 服务器的基准测试工具。它用于测试 HTTP 服务器每秒能够处理多少请求。对于 Web 应用程序服务,此结果可以转化为整个应用程序每秒可满足的请求数量。

  • 特点: 简单易用,主要用于对单个 URL 进行压力测试。

🌐 http_load

  • 简介: http_load 的概念与 ab 类似,旨在对 Web 服务器进行测试。相对于 ab,它更加灵活,可以通过输入文件提供多个 URL,并随机选择进行测试。还可以按时间比例进行测试,而不仅仅是测试最大请求处理能力。

🌐 Apache JMeter

  • 简介: JMeter 是一个用 Java 编写的应用程序,可用于加载其他应用程序并测试其性能。虽然最初设计用于测试 Web 应用程序,但也可用于测试诸如 FTP 服务器或通过 JDBC 进行数据库查询的性能。

  • 特点: 复杂而强大,支持模拟真实用户访问,具有图形界面,可记录和重放测试结果。


📊 单组件测试工具


📊 mysqlslap

  • 简介: mysqlslap 可以模拟服务器负载并输出计时信息。它包含在 MySQL 5.1 的发行包中。可以测试并发连接数,并指定 SQL 语句,如果未指定 SQL 语句,它将自动生成查询 schema 的 SELECT 语句。

📋 MySQL Benchmark Suite (sql-bench)

  • 简介: MySQL 发行包中提供了自己的基准测试套件,用于比较不同数据库服务器的性能。它是单线程的,主要用于测试服务器执行查询的速度。

  • 特点: 包含大量预定义的测试,易于使用,可用于比较不同存储引擎或配置的性能。

💥 Super Smack

  • 简介: Super Smack 是一款用于 MySQL 和 PostgreSQL 的基准测试工具,可提供压力测试和负载生成。它支持模拟多用户访问,加载测试数据到数据库,并支持使用随机数据填充测试表。

🗃️ Database Test Suite

  • 简介: Database Test Suite 是一组测试工具,可用于评估数据库性能。其中的 dbt2 工具用于执行 TPC-C OLTP 测试,是一个免费的替代工具。它可以用于比较不同数据库服务器的性能。

🔄 Percona’s TPCC-MySQL Tool

  • 简介: Percona 的 TPCC-MySQL Tool 是一个类似 TPC-C 的基准测试工具集,专门为 MySQL 测试开发。它可用于评估数据库服务器性能。

🔄 sysbench

  • 简介: sysbench 是一个多线程系统压测工具,可以评估系统性能对各种因素的影响。它支持测试文件 I/O、操作系统调度器、内存分配和传输速度、POSIX 线程以及数据库服务器等。

  • 特点: 灵活且功能强大,可用于测试 MySQL、操作系统和硬件性能。


⏱️ MySQL 的 BENCHMARK() 函数


MySQL 内置了 BENCHMARK() 函数,可用于测试特定操作的执行速度。该函数接受执行次数和表达式作为参数,可用于评估某些操作的性能。

示例:

SET @input := 'hello world';
-- 输出始终为 0。
SELECT BENCHMARK(1000000, MD5(@input));
SELECT BENCHMARK(1000000, SHA1(@input));

请注意,BENCHMARK() 函数只返回服务器执行表达式的时间,不涉及分析和优化开销。它适用于简单性能测试,但不适合用于真正的基准测试,因为它只测试执行周期的一部分。


📈 MySQL 压力测试

虽然我们在虚拟机上进行练习,无法真正地测试 MySQL 的实际性能,但只要掌握了测试方法,我们就可以在任何平台上测试数据库的性能。


🎯 什么是压力测试

压力测试是一种对系统的性能测试。与业务逻辑无关,更注重直接测试读写性能。

📊 压力测试的指标

在这里插入图片描述

🛠 压力测试工具

  • Mysqlslap:MySQL 的官方工具,适用于短期并发测试。
  • Sysbench:适用于长时间高并发测试。
  • Jmeter:在数据库测试方面功能较弱,不推荐。

📘 Sysbench 简介

Sysbench 可以测试以下内容:

  • 线程测试: sysbench --test=threads --num-threads=64 --thread-yields=100 --thread-locks=2 run
  • CPU 测试: sysbench --test=cpu --cpu-max-prime=20000 run
  • 内存测试: sysbench --test=memory --memory-block-size=8k --memory-total-size=4G run
  • 数据库测试: sysbench --test=oltp --mysql-table-engine=myisam --oltp-table-size=1000000
  • 磁盘测试: sysbench --test=fileio --num-threads=16 --file-total-size=3G --file-test-mode=rndrw run

  • 📦 I. 安装 Sysbench

    • 请确保不要在安装了 MySQL 8 的机器上安装 Sysbench,因为可能会有版本冲突。
    # 清理并创建缓存
    yum clean all
    yum makecache
    
    # 安装 sysbench
    curl -s https://packagecloud.io/install/repositories/akopytov/sysbench/script.rpm.sh | sudo bash
    sudo yum -y install sysbench
    # 验证安装,请检查版本号:
    sysbench --version
    
    • 🎉 如果显示了版本号,表示Sysbench已成功安装。
  • 🛠️ II. 准备测试表和数据:

    • 首先,在MySQL中创建名为 test_db 的测试数据库。
    • 使用以下命令准备测试数据环境:
      sysbench --db-driver=mysql --time=300 --threads=10 --report-interval=1 --mysql-host=127.0.0.1 --mysql-port=3306 --mysql-user=test_user --mysql-password=test_user --mysql-db=test_db --tables=20 --table_size=1000000 oltp_read_write --db-ps-mode=disable prepare
      
    • 📝 参数说明:
      • --db-driver=mysql: 指定数据库驱动。
      • --time=300: 测试将运行300秒。
      • --threads=10: 使用10个线程模拟并发。
      • --report-interval=1: 每秒报告一次测试状态。
      • --tables=20: 创建20个测试表。
      • --table_size=1000000: 每个测试表将有100万行数据。
      • oltp_read_write: 进行OLTP读写测试。
      • --db-ps-mode=disable: 禁用预处理语句模式。
      • prepare: 根据上述设置准备测试数据。
  • 🏃 III. 测试:

    • 要测试数据库的综合读写性能,请使用:
      sysbench --db-driver=mysql --mysql-db=test_db ... oltp_read_write --db-ps-mode=disable run
      
    • 对于只读性能测试,将模式更改为 oltp_read_only
    • 对于删除性能测试,使用 oltp_delete
    • 要测试索引列的更新性能,请切换到 oltp_update_index
    • 对于非索引列,使用 oltp_update_non_index
    • 要测试插入性能,使用 oltp_insert
    • 对于仅写性能,模式是 oltp_write_only
  • 🧹 IV. 清理数据:

    • 测试结束后,使用以下命令清理测试数据:
      sysbench --db-driver=mysql --mysql-db=test_db ... oltp_read_write --db-ps-mode=disable cleanup
      
  • 📊 V. 分析测试结果:

    • 测试将输出性能指标,如:

      • tps: 每秒事务数。
      • qps: 每秒查询数。
      • 延迟信息、错误和重新连接。
    • 最终报告将提供总事务数、查询数和延迟分布的概要。

    • 📈 示例输出:

      [ 22s ] thds: 10 tps: 380.99 qps: 7312.66 (r/w/o: 5132.99/1155.86/1321.35) lat (ms, 95%): 21.33 err/s: 0.00 reconn/s: 0.00
      
      • thds: 10: 表示使用了10个线程。
      • tps: 380.99: 表示每秒事务数。
      • qps: 7312.66: 表示每秒查询数。
      • lat (ms, 95%): 21.33: 表示95%的请求的延迟。
    • 📝 总结将显示总事务数、查询数和延迟分布。


📖 Sysbench 基本语法

sysbench script [options] [command]

其中,script 可在 /usr/share/sysbench/tests/include/ 下找到。常见的链接信息参数包括:

  • --mysql-host:IP 地址
  • --mysql-port:端口号
  • --mysql-user:用户名
  • --mysql-password:密码
  • …… 更多参数

命令参数如下:

  • prepare:准备测试数据
  • run:执行测试
  • cleanup:清除测试数据

🔧 Sysbench 实践

  1. 生成测试数据:

    sysbench /usr/share/sysbench/tests/include/oltp_legacy/oltp.lua --mysql-host=192.168.56.101 --mysql-port=3306 --mysql-user=root --mysql-password=123456 --oltp-tables-count=10 --oltp-table-size=100000 prepare
    
  2. 执行测试:

    sysbench /usr/share/sysbench/tests/include/oltp_legacy/oltp.lua --mysql-host=192.168.56.101 --mysql-port=3306 --mysql-user=root --mysql-password=123456 --oltp-test-mode=complex --threads=10 --time=600 --report-interval=10 run >> /home/report.log
    
-- 运行之前,需要先手动创建一个数据库,数据库的名称是固定的:sbtest
-- 生成测试数据
[root@study ~]# sysbench /usr/share/sysbench/tests/include/oltp_legacy/oltp.lua --mysql-host=192.168.56.101 --mysql-port=3306 --mysql-user=root --mysql-password=123456 --oltp-tables-count=10 --oltp-table-size=100000 prepare

sysbench 1.0.20 (using bundled LuaJIT 2.1.0-beta2)

Creating table 'sbtest1'...
Inserting 100000 records into 'sbtest1'
Creating secondary indexes on 'sbtest1'...
Creating table 'sbtest2'...
Inserting 100000 records into 'sbtest2'
Creating secondary indexes on 'sbtest2'...
Creating table 'sbtest3'...
Inserting 100000 records into 'sbtest3'
Creating secondary indexes on 'sbtest3'...
...
-- 可以看到在创建一些表数据

-- 执行测试
-- 这里选择了:事务测试、10 个线程、执行 10 分钟、间隔 10 秒生成一次报告、把测试信息存储在 /home/report.log 中
[root@study ~]#  sysbench /usr/share/sysbench/tests/include/oltp_legacy/oltp.lua --mysql-host=192.168.56.101 --mysql-port=3306 --mysql-user=root --mysql-password=123456 --oltp-test-mode=complex --threads=10 --time=600 --report-interval=10 run >> /home/report.log

sysbench 1.0.20 (using bundled LuaJIT 2.1.0-beta2)

Running the test with following options:
Number of threads: 10
Report intermediate results every 10 second(s)
Initializing random number generator from current time


Initializing worker threads...

Threads started!

[ 10s ] thds: 10 tps: 145.46 qps: 2956.28 (r/w/o: 2077.72/584.44/294.12) lat (ms,95%): 97.55 err/s: 2.20 reconn/s: 0.00
....
[ 590s ] thds: 10 tps: 169.00 qps: 3408.96 (r/w/o: 2391.17/677.89/339.90) lat (ms,95%): 74.46 err/s: 1.90 reconn/s: 0.00
[ 600s ] thds: 10 tps: 170.00 qps: 3446.17 (r/w/o: 2419.98/683.59/342.60) lat (ms,95%): 75.82 err/s: 2.60 reconn/s: 0.00
SQL statistics:
    queries performed: # 执行查询次数
        read:                            1447810
        write:                           408935
        other:                           205172
        total:                           2061917	# 读写、其他总计
    transactions:                        101757 (169.57 per sec.)		# 事务,平均每秒钟执行 169 次
    queries:                             2061917 (3436.11 per sec.)	# 查询,每秒钟执行 3436 次
    ignored errors:                      1658   (2.76 per sec.)	# 错误:数据库节点在慢负荷运行时,新的请求进来,得不到处理,就超时了
    reconnects:                          0      (0.00 per sec.)

General statistics:
    total time:                          600.0713s
    total number of events:              101757

Latency (ms):
         min:                                   10.51
         avg:                                   58.97
         max:                                  233.36
         95th percentile:                       75.82
         sum:                              6000151.10

Threads fairness:
    events (avg/stddev):           10175.7000/100.18
    execution time (avg/stddev):   600.0151/0.02

🖥️ CPU 负载监控

  • 命令: top
top - 10:18:34 up 16 days, 23:21,  3 users,  load average: 0.42, 0.25, 0.17
  • 输出解释:
    • 10:18:34: 当前时间。
    • 16 days, 23:21: 系统运行时间。
    • 3 users: 当前登录用户数。
    • load average: 0.42, 0.25, 0.17: 分别表示过去1分钟、5分钟、15分钟的平均负载。

在这里插入图片描述

🧠 内存负载监控

  • 命令: top
Mem :  3880188 total,   164828 free,  2579352 used,  1136008 buff/cache
  • 输出解释:
    • 3880188 total: 总内存(单位KB)。
    • 164828 free: 剩余内存。
    • 2579352 used: 已使用内存。
    • 1136008 buff/cache: 缓冲/缓存内存。

💾 磁盘 IO 监控

  • 命令: dstat -d

  • 输出解释:

    • 显示每秒从磁盘读取和写入的数据量。意思是每秒钟读取6677B的数据,每秒钟写入28K的数据
      在这里插入图片描述
  • 命令: dstat -r

  • 输出解释:

    • 显示磁盘的IOPS(每秒输入/输出操作数)。
      在这里插入图片描述

🌐 网络流量监控

  • 命令: dstat -n
  • 输出解释:
    • 显示每秒接收和发送的网络流量。
      在这里插入图片描述

👀 监测系统

  • 我们可以基于PrometheusGrafana搭建一个可视化监控平台,来实时监控机器和数据库的运行情况。

在这里插入图片描述
在这里插入图片描述在这里插入图片描述


  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yueerba126

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值