前言

在数据库运维和开发过程中,性能测试是必不可少的环节。sysbench作为一款开源、多线程的基准测试工具,已经成为业界数据库性能评估的标准工具之一。本文将详细介绍如何使用sysbench对MySQL数据库进行压力测试,包括环境搭建、参数配置、测试执行以及结果分析,并提供完整的测试脚本和结果解读方法。

一、sysbench简介

sysbench是一个模块化、跨平台的多线程基准测试工具,主要用于评估系统性能,特别适用于数据库性能测试。它的主要特性包括:

  • 多用途:可用于测试CPU、内存、文件I/O、线程和数据库性能
  • 跨平台:支持Linux、Windows、macOS等操作系统
  • 模块化设计:不同测试项目通过不同模块实现
  • Lua脚本支持:可灵活自定义测试逻辑
  • 支持多种数据库:MySQL、PostgreSQL、达梦等

常用测试模型

sysbench通过Lua脚本定义了多种压测模型:

测试模型 描述
oltp_read_write.lua 混合读写测试,模拟真实OLTP场景
oltp_read_only.lua 只读测试
oltp_write_only.lua 只写测试
insert.lua 单值插入测试
delete.lua 删除测试
bulk_insert.lua 批量插入测试

二、环境准备

2.1 测试环境说明

本文的测试环境如下:

配置项 参数
压测机OS CentOS 7.5
压测机规格 4核8G
数据库 MySQL 8.0.25
数据库规格 4核16G
sysbench版本 1.0.20

注意:不同服务器配置会导致测试结果差异很大,本文结果仅供参考。

2.2 安装sysbench

方法一:YUM安装(推荐)
# 下载官方仓库脚本
curl -s https://packagecloud.io/install/repositories/akopytov/sysbench/script.rpm.sh | sudo bash

# 安装sysbench
sudo yum -y install sysbench

# 查看版本
sysbench --version
方法二:源码编译安装

如果需要最新版本或特定功能,可以选择源码编译:

# 下载源码
git clone https://github.com/akopytov/sysbench.git
cd sysbench
git checkout 1.0.20

# 安装依赖
yum install -y gcc gcc-c++ autoconf automake make libtool mysql-devel

# 编译安装
./autogen.sh
./configure
make -j
make install

# 验证安装
sysbench --version

2.3 准备测试数据库

在MySQL中创建用于压测的数据库和用户:

-- 创建测试数据库
CREATE DATABASE IF NOT EXISTS sbtest;

-- 创建压测用户
CREATE USER 'sbtest'@'%' IDENTIFIED WITH mysql_native_password BY 'sbtest123';

-- 授予权限
GRANT ALL PRIVILEGES ON sbtest.* TO 'sbtest'@'%';
FLUSH PRIVILEGES;

三、压测脚本详解

3.1 基础参数说明

sysbench压测命令的核心参数分类如下:

数据库连接参数
参数 说明 示例
--db-driver 数据库驱动类型 mysql
--mysql-host MySQL服务器地址 192.168.1.100
--mysql-port MySQL端口 3306
--mysql-user 数据库用户名 sbtest
--mysql-password 数据库密码 sbtest123
--mysql-db 测试数据库名 sbtest
测试负载参数
参数 说明 示例
--tables 测试表数量 10
--table_size 每张表的行数 1000000
--threads 并发线程数 16
--time 测试持续时间(秒) 300
--report-interval 报告输出间隔(秒) 1
--percentile 百分位数 95
测试类型与阶段
阶段 说明
prepare 准备测试数据
run 执行压测
cleanup 清理测试数据

3.2 准备测试数据

在执行压测前,需要先准备测试数据:

sysbench \
  --db-driver=mysql \
  --mysql-host=192.168.1.100 \
  --mysql-port=3306 \
  --mysql-user=sbtest \
  --mysql-password='sbtest123' \
  --mysql-db=sbtest \
  --tables=10 \
  --table_size=1000000 \
  --threads=16 \
  --time=0 \
  oltp_read_write \
  prepare

执行成功后,会在数据库中创建10张以sbtest开头的表,每张表包含100万条测试数据。

3.3 执行压测

数据准备完成后,执行压测命令:

sysbench \
  --db-driver=mysql \
  --mysql-host=192.168.1.100 \
  --mysql-port=3306 \
  --mysql-user=sbtest \
  --mysql-password='sbtest123' \
  --mysql-db=sbtest \
  --tables=10 \
  --table_size=1000000 \
  --threads=16 \
  --time=300 \
  --report-interval=10 \
  --percentile=95 \
  oltp_read_write \
  run

3.4 清理测试数据

测试完成后,可以清理数据:

sysbench \
  --db-driver=mysql \
  --mysql-host=192.168.1.100 \
  --mysql-port=3306 \
  --mysql-user=sbtest \
  --mysql-password='sbtest123' \
  --mysql-db=sbtest \
  --tables=10 \
  oltp_read_write \
  cleanup

四、压测结果解读

4.1 实时输出解读

压测过程中,每10秒会输出一次实时结果:

[ 10s ] thds: 16 tps: 412.35 qps: 8247.00 (r/w/o: 5772.90/1649.40/824.70) lat (ms,95%): 45.23 err/s: 0.00 reconn/s: 0.00

各字段含义:

字段 说明
thds: 16 当前并发线程数
tps: 412.35 每秒处理事务数
qps: 8247.00 每秒处理请求数
r/w/o 读/写/其他请求数
lat (ms,95%) 95%请求的延迟
err/s 每秒错误数
reconn/s 每秒重连次数

4.2 最终结果解读

压测结束后,sysbench会输出完整的统计报告:

SQL statistics:
    queries performed:
        read:                            115864  # 读请求总数
        write:                           33104   # 写请求总数
        other:                           16552   # 其他请求数
        total:                           165520  # 总请求数
    transactions:                        8276    (823.13 per sec.)  # 事务数及TPS
    queries:                             165520  (16462.75 per sec.) # 查询数及QPS
    ignored errors:                      0       (0.00 per sec.)
    reconnects:                          0       (0.00 per sec.)

General statistics:
    total time:                          10.0543s        # 总耗时
    total number of events:              8276            # 总事件数

Latency (ms):
         min:                            4.22            # 最小延迟
         avg:                            12.10           # 平均延迟
         max:                            172.82          # 最大延迟
         95th percentile:                18.28           # 95分位延迟
         sum:                            100141.94

Threads fairness:
    events (avg/stddev):                 827.6000/87.15  # 线程事件分布
    execution time (avg/stddev):         10.0142/0.02    # 线程执行时间分布

4.3 关键指标说明

指标 含义 重要性
TPS 每秒事务数 ⭐⭐⭐⭐⭐ 核心指标
QPS 每秒查询数 ⭐⭐⭐⭐⭐ 核心指标
平均延迟 所有请求的平均响应时间 ⭐⭐⭐⭐
95分位延迟 95%的请求都在此时间内完成 ⭐⭐⭐⭐⭐ 最重要
错误率 出错请求占比 ⭐⭐⭐⭐⭐
线程公平性 各线程负载是否均衡 ⭐⭐⭐

五、完整压测脚本

5.1 单次测试脚本

#!/bin/bash
# single_test.sh - 单次sysbench压测脚本

# 数据库连接配置
DB_HOST="192.168.1.100"
DB_PORT="3306"
DB_USER="sbtest"
DB_PASS="sbtest123"
DB_NAME="sbtest"

# 测试配置
TABLES=10
TABLE_SIZE=1000000
THREADS=16
TEST_TIME=300
REPORT_INTERVAL=10

# 测试类型
TEST_TYPE="oltp_read_write"

echo "========== 开始准备测试数据 =========="
sysbench --db-driver=mysql \
  --mysql-host=${DB_HOST} \
  --mysql-port=${DB_PORT} \
  --mysql-user=${DB_USER} \
  --mysql-password="${DB_PASS}" \
  --mysql-db=${DB_NAME} \
  --tables=${TABLES} \
  --table_size=${TABLE_SIZE} \
  --threads=${THREADS} \
  ${TEST_TYPE} prepare

if [ $? -eq 0 ]; then
    echo "========== 数据准备完成,开始压测 =========="
    sysbench --db-driver=mysql \
      --mysql-host=${DB_HOST} \
      --mysql-port=${DB_PORT} \
      --mysql-user=${DB_USER} \
      --mysql-password="${DB_PASS}" \
      --mysql-db=${DB_NAME} \
      --tables=${TABLES} \
      --table_size=${TABLE_SIZE} \
      --threads=${THREADS} \
      --time=${TEST_TIME} \
      --report-interval=${REPORT_INTERVAL} \
      --percentile=95 \
      ${TEST_TYPE} run
else
    echo "数据准备失败,请检查配置"
    exit 1
fi

echo "========== 压测完成,清理数据 =========="
sysbench --db-driver=mysql \
  --mysql-host=${DB_HOST} \
  --mysql-port=${DB_PORT} \
  --mysql-user=${DB_USER} \
  --mysql-password="${DB_PASS}" \
  --mysql-db=${DB_NAME} \
  --tables=${TABLES} \
  ${TEST_TYPE} cleanup

5.2 多线程并发测试脚本

为了全面评估数据库性能,建议测试不同并发数下的表现:

#!/bin/bash
# multi_thread_test.sh - 多线程梯度压测脚本

DB_HOST="192.168.1.100"
DB_PORT="3306"
DB_USER="sbtest"
DB_PASS="sbtest123"
DB_NAME="sbtest"

TABLES=10
TABLE_SIZE=1000000
TEST_TIME=180
REPORT_INTERVAL=10

# 测试线程数梯度
THREADS_LIST=(4 8 16 32 64 128)

# 结果文件
RESULT_FILE="test_results_$(date +%Y%m%d_%H%M%S).txt"

echo "========== Sysbench 压测结果报告 ==========" > ${RESULT_FILE}
echo "测试时间: $(date)" >> ${RESULT_FILE}
echo "数据库: ${DB_HOST}:${DB_PORT}" >> ${RESULT_FILE}
echo "测试配置: ${TABLES}张表 x ${TABLE_SIZE}行数据" >> ${RESULT_FILE}
echo "测试时长: ${TEST_TIME}秒" >> ${RESULT_FILE}
echo "=========================================" >> ${RESULT_FILE}
printf "%-8s %-12s %-12s %-12s %-12s\n" "Threads" "TPS" "QPS" "Avg Lat(ms)" "95% Lat(ms)" >> ${RESULT_FILE}

# 准备数据(仅执行一次)
echo "准备测试数据..."
sysbench --db-driver=mysql \
  --mysql-host=${DB_HOST} \
  --mysql-port=${DB_PORT} \
  --mysql-user=${DB_USER} \
  --mysql-password="${DB_PASS}" \
  --mysql-db=${DB_NAME} \
  --tables=${TABLES} \
  --table_size=${TABLE_SIZE} \
  --threads=16 \
  oltp_read_write prepare

# 循环测试不同线程数
for THREADS in ${THREADS_LIST[@]}; do
    echo "正在测试 ${THREADS} 线程..."
    
    # 执行压测并提取关键指标
    RESULT=$(sysbench --db-driver=mysql \
      --mysql-host=${DB_HOST} \
      --mysql-port=${DB_PORT} \
      --mysql-user=${DB_USER} \
      --mysql-password="${DB_PASS}" \
      --mysql-db=${DB_NAME} \
      --tables=${TABLES} \
      --table_size=${TABLE_SIZE} \
      --threads=${THREADS} \
      --time=${TEST_TIME} \
      --report-interval=10 \
      --percentile=95 \
      oltp_read_write run 2>&1)
    
    # 提取TPS
    TPS=$(echo "$RESULT" | grep "transactions:" | awk -F'(' '{print $2}' | awk '{print $1}')
    # 提取QPS
    QPS=$(echo "$RESULT" | grep "queries:" | awk -F'(' '{print $2}' | awk '{print $1}')
    # 提取平均延迟
    AVG_LAT=$(echo "$RESULT" | grep "avg:" | awk '{print $2}')
    # 提取95分位延迟
    P95_LAT=$(echo "$RESULT" | grep "95th percentile:" | awk '{print $3}')
    
    printf "%-8s %-12s %-12s %-12s %-12s\n" \
      "${THREADS}" "${TPS}" "${QPS}" "${AVG_LAT}" "${P95_LAT}" >> ${RESULT_FILE}
    
    echo "  ${THREADS} 线程测试完成: TPS=${TPS}, QPS=${QPS}"
    
    # 每个线程数测试后等待30秒,让数据库恢复
    sleep 30
done

# 清理数据
echo "清理测试数据..."
sysbench --db-driver=mysql \
  --mysql-host=${DB_HOST} \
  --mysql-port=${DB_PORT} \
  --mysql-user=${DB_USER} \
  --mysql-password="${DB_PASS}" \
  --mysql-db=${DB_NAME} \
  --tables=${TABLES} \
  oltp_read_write cleanup

echo "测试完成!结果已保存至 ${RESULT_FILE}"
cat ${RESULT_FILE}

5.3 不同测试类型脚本

#!/bin/bash
# multi_test_type.sh - 不同测试类型对比脚本

DB_HOST="192.168.1.100"
DB_PORT="3306"
DB_USER="sbtest"
DB_PASS="sbtest123"
DB_NAME="sbtest"

TABLES=10
TABLE_SIZE=500000
THREADS=32
TEST_TIME=120

# 测试类型列表
TEST_TYPES=("oltp_read_only" "oltp_write_only" "oltp_read_write")

echo "========== 不同测试类型性能对比 =========="
printf "%-20s %-12s %-12s %-12s\n" "测试类型" "TPS" "QPS" "95% Lat(ms)"
echo "----------------------------------------"

for TEST_TYPE in ${TEST_TYPES[@]}; do
    echo "准备 ${TEST_TYPE} 测试数据..."
    sysbench --db-driver=mysql \
      --mysql-host=${DB_HOST} \
      --mysql-port=${DB_PORT} \
      --mysql-user=${DB_USER} \
      --mysql-password="${DB_PASS}" \
      --mysql-db=${DB_NAME} \
      --tables=${TABLES} \
      --table_size=${TABLE_SIZE} \
      --threads=${THREADS} \
      ${TEST_TYPE} prepare > /dev/null 2>&1
    
    echo "执行 ${TEST_TYPE} 压测..."
    RESULT=$(sysbench --db-driver=mysql \
      --mysql-host=${DB_HOST} \
      --mysql-port=${DB_PORT} \
      --mysql-user=${DB_USER} \
      --mysql-password="${DB_PASS}" \
      --mysql-db=${DB_NAME} \
      --tables=${TABLES} \
      --table_size=${TABLE_SIZE} \
      --threads=${THREADS} \
      --time=${TEST_TIME} \
      --percentile=95 \
      ${TEST_TYPE} run 2>&1)
    
    TPS=$(echo "$RESULT" | grep "transactions:" | awk -F'(' '{print $2}' | awk '{print $1}')
    QPS=$(echo "$RESULT" | grep "queries:" | awk -F'(' '{print $2}' | awk '{print $1}')
    P95_LAT=$(echo "$RESULT" | grep "95th percentile:" | awk '{print $3}')
    
    printf "%-20s %-12s %-12s %-12s\n" "${TEST_TYPE}" "${TPS}" "${QPS}" "${P95_LAT}"
    
    # 清理数据
    sysbench --db-driver=mysql \
      --mysql-host=${DB_HOST} \
      --mysql-port=${DB_PORT} \
      --mysql-user=${DB_USER} \
      --mysql-password="${DB_PASS}" \
      --mysql-db=${DB_NAME} \
      --tables=${TABLES} \
      ${TEST_TYPE} cleanup > /dev/null 2>&1
    
    sleep 30
done

六、压测结果示例

6.1 不同并发数测试结果

以下是在4核16G MySQL、4核8G压测机环境下的测试结果:

线程数 TPS QPS 平均延迟(ms) 95%延迟(ms)
4 215 4300 18.5 32.1
8 380 7600 21.0 45.2
16 412 8247 23.5 52.8
32 385 7700 83.0 142.5
64 338 6760 189.0 324.6

从结果可以看出:

  • 在16线程时达到性能峰值(TPS约412)
  • 超过最优并发数后,TPS开始下降,延迟显著增加
  • 数据库的瓶颈大约在16-32并发之间

6.2 不同规格数据库对比

参考云厂商的基准测试数据,不同规格数据库的性能表现:

数据库规格 线程数 QPS TPS 95%延迟(ms)
4核8G 32 35917 1795 17.82
8核32G 64 67719 3385 18.90
16核128G 128 127955 6397 20.00

七、压测注意事项

7.1 环境要求

  1. 压测机配置:压测机配置应不低于数据库配置,避免压测机成为瓶颈
  2. 网络延迟:确保压测机与数据库在同一可用区,网络延迟影响测试准确性
  3. 数据量设置:测试数据量应至少为内存的1.2倍,确保数据不能完全缓存在内存中

7.2 测试建议

  1. 预热数据库:正式压测前先进行1-2分钟预热,让数据库缓存预热
  2. 多次测试取平均:每个参数组合建议测试3次取平均值
  3. 监控系统资源:压测时同时监控CPU、内存、磁盘IO、网络等指标
  4. 逐步增加压力:从低并发开始逐步增加,找到性能拐点

7.3 常见问题

Q: 压测时出现连接错误?
A: 检查MySQL的max_connections参数,适当调大该值。

Q: 延迟突然飙升?
A: 可能是达到数据库瓶颈,检查CPU、内存、磁盘IO使用率。

Q: TPS/QPS不稳定?
A: 检查是否有其他进程占用资源,或网络波动。

八、总结

sysbench作为业界标准的数据库压测工具,能够有效评估数据库在不同负载下的性能表现。通过本文的详细指南,你可以:

  1. 快速部署:使用YUM或源码方式安装sysbench
  2. 灵活配置:根据不同测试需求调整参数
  3. 自动化测试:使用提供的脚本进行梯度压测
  4. 科学分析:理解各项指标含义,准确评估数据库性能

压测是数据库性能优化的基础,建议在以下场景进行压测:

  • 新上线系统评估容量
  • 数据库版本升级前验证
  • 参数调优效果验证
  • 架构改造前后对比

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐