强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

Sysbench 完全指南 / 第十二章:最佳实践

第十二章:最佳实践

12.1 测试方法论

12.1.1 性能测试的基本原则

原则说明
可重复性相同条件下多次测试,结果应一致
可对比性只改变一个变量,其他条件保持一致
真实性测试场景应尽量接近真实业务
渐进性从低负载逐步增加,观察性能变化趋势
完整性测试应包括准备、预热、测试、清理四个阶段

12.1.2 标准测试流程

  ┌─────────────────────────────────────────────────────────────┐
  │                    性能测试标准流程                           │
  └─────────────────────────────────────────────────────────────┘

  ┌──────────┐     ┌──────────┐     ┌──────────┐     ┌──────────┐
  │  1. 规划  │────→│  2. 准备  │────→│  3. 预热  │────→│  4. 测试  │
  │          │     │          │     │          │     │          │
  │ • 明确目标│     │ • 环境配置│     │ • 短时间  │     │ • 正式运行│
  │ • 选择测试│     │ • 数据准备│     │ • 预热缓存│     │ • 收集数据│
  │ • 确定指标│     │ • 工具安装│     │ • 检查配置│     │ • 多次运行│
  └──────────┘     └──────────┘     └──────────┘     └──────────┘
                                                          │
                                                          ▼
  ┌──────────┐     ┌──────────┐     ┌──────────────────────────────┐
  │  7. 归档  │←────│  6. 报告  │←────│  5. 分析                      │
  │          │     │          │     │                              │
  │ • 保存结果│     │ • 总结结论│     │ • 汇总数据                    │
  │ • 记录配置│     │ • 提供建议│     │ • 对比基线                    │
  │ • 版本控制│     │ • 分享报告│     │ • 识别瓶颈                    │
  └──────────┘     └──────────┘     └──────────────────────────────┘

12.1.3 测试规划清单

在开始测试前,确保回答以下问题:

问题示例回答
测试的目的是什么?验证 MySQL 8.0 升级后的性能变化
测试什么指标?TPS、P95 延迟、QPS
测试什么场景?oltp_read_write,16 线程,16 张表
测试环境是什么?ECS 8C16G,MySQL 8.0,SSD 云盘
什么是基线?升级前的 MySQL 5.7 测试结果
多长时间?300 秒,运行 3 次取平均
如何判断成功/失败?TPS 不低于基线的 95%

12.2 环境准备

12.2.1 系统层面准备

#!/bin/bash
# env_prepare.sh - 测试环境准备

echo "=== 系统信息收集 ==="
echo "操作系统: $(cat /etc/os-release | grep PRETTY_NAME | cut -d= -f2)"
echo "内核版本: $(uname -r)"
echo "CPU 型号: $(lscpu | grep 'Model name' | cut -d: -f2 | xargs)"
echo "CPU 核心: $(nproc)"
echo "内存大小: $(free -h | grep Mem | awk '{print $2}')"
echo "磁盘类型: $(lsblk -d -o NAME,ROTA,SIZE,MODEL | head -5)"
echo ""

echo "=== 关闭不必要的服务 ==="
# 避免测试期间干扰
sudo systemctl stop cron 2>/dev/null || true
sudo systemctl stop unattended-upgrades 2>/dev/null || true
sudo systemctl stop snapd 2>/dev/null || true
echo "Done"
echo ""

echo "=== 清空文件缓存 ==="
sudo sh -c 'echo 3 > /proc/sys/vm/drop_caches'
echo "Done"
echo ""

echo "=== 设置 CPU 调度器为 performance ==="
sudo cpupower frequency-set -g performance 2>/dev/null || echo "cpupower not available"
echo ""

echo "=== 禁用 Transparent HugePages(推荐数据库测试时禁用) ==="
echo never | sudo tee /sys/kernel/mm/transparent_hugepage/enabled > /dev/null 2>&1 || echo "THP not available"
echo ""

echo "=== 检查并设置文件描述符限制 ==="
echo "当前限制: $(ulimit -n)"
ulimit -n 65535
echo "新限制: $(ulimit -n)"
echo ""

echo "=== 检查 Swap ==="
echo "Swap: $(free -h | grep Swap | awk '{print $2}')"
echo "Swappiness: $(cat /proc/sys/vm/swappiness)"
echo ""

echo "=== 网络信息 ==="
ip -4 addr show | grep inet | head -3
echo ""

echo "=== 环境准备完成 ==="

12.2.2 MySQL 测试环境准备

#!/bin/bash
# mysql_env_prepare.sh - MySQL 测试环境准备

MYSQL_HOST="127.0.0.1"
MYSQL_USER="root"
MYSQL_PASS="secret"

echo "=== MySQL 版本 ==="
mysql -h $MYSQL_HOST -u $MYSQL_USER -p$MYSQL_PASS -e "SELECT VERSION();"

echo ""
echo "=== 关键参数 ==="
mysql -h $MYSQL_HOST -u $MYSQL_USER -p$MYSQL_PASS -e "
  SHOW VARIABLES WHERE Variable_name IN (
    'innodb_buffer_pool_size',
    'innodb_buffer_pool_instances',
    'innodb_flush_log_at_trx_commit',
    'innodb_io_capacity',
    'innodb_io_capacity_max',
    'innodb_log_buffer_size',
    'innodb_redo_log_capacity',
    'max_connections',
    'table_open_cache',
    'table_open_cache_instances',
    'thread_cache_size',
    'sort_buffer_size',
    'join_buffer_size',
    'read_buffer_size',
    'innodb_flush_method',
    'sync_binlog'
  );
"

echo ""
echo "=== Buffer Pool 命中率 ==="
mysql -h $MYSQL_HOST -u $MYSQL_USER -p$MYSQL_PASS -e "
  SHOW STATUS LIKE 'Innodb_buffer_pool_read%';
"

echo ""
echo "=== 当前连接数 ==="
mysql -h $MYSQL_HOST -u $MYSQL_USER -p$MYSQL_PASS -e "
  SHOW STATUS LIKE 'Threads_connected';
  SHOW STATUS LIKE 'Max_used_connections';
"

12.2.3 PostgreSQL 测试环境准备

#!/bin/bash
# pgsql_env_prepare.sh

PG_HOST="127.0.0.1"
PG_USER="postgres"

echo "=== PostgreSQL 版本 ==="
psql -h $PG_HOST -U $PG_USER -c "SELECT version();"

echo ""
echo "=== 关键参数 ==="
psql -h $PG_HOST -U $PG_USER -c "
  SELECT name, setting, unit 
  FROM pg_settings 
  WHERE name IN (
    'shared_buffers', 'effective_cache_size', 'work_mem',
    'maintenance_work_mem', 'max_connections', 'wal_buffers',
    'checkpoint_completion_target', 'max_wal_size', 'random_page_cost',
    'effective_io_concurrency', 'max_parallel_workers_per_gather'
  ) ORDER BY name;
"

echo ""
echo "=== Buffer Cache 命中率 ==="
psql -h $PG_HOST -U $PG_USER -c "
  SELECT 
    sum(blks_hit) * 100.0 / NULLIF(sum(blks_hit) + sum(blks_read), 0) AS hit_ratio
  FROM pg_stat_database 
  WHERE datname = 'sbtest';
"

12.3 预热策略

12.3.1 为什么要预热

缓存类型冷启动表现预热后表现
OS 文件缓存频繁磁盘 I/O内存命中,I/O 减少
InnoDB Buffer Pool全磁盘读取缓存命中,性能提升
PostgreSQL Shared Buffers磁盘读取缓存命中
CPU 缓存缓存未命中缓存命中
连接池连接建立开销连接复用

12.3.2 预热脚本

#!/bin/bash
# warmup.sh - 预热脚本

DURATION=${1:-60}  # 默认 60 秒

echo "=== 开始预热(${DURATION}秒) ==="

# CPU 预热
echo ">>> CPU 预热..."
sysbench cpu --threads=$(nproc) --time=10 run > /dev/null 2>&1

# 内存预热
echo ">>> 内存预热..."
sysbench memory --memory-block-size=1M --threads=4 --time=10 run > /dev/null 2>&1

# 数据库预热(OLTP 测试)
if [ -n "$MYSQL_HOST" ]; then
  echo ">>> MySQL 预热..."
  sysbench oltp_read_write \
    --mysql-host=$MYSQL_HOST --mysql-user=$MYSQL_USER --mysql-password=$MYSQL_PASS \
    --tables=${TABLES:-16} --table-size=${TABLE_SIZE:-1000000} \
    --threads=16 --time=$DURATION \
    run > /dev/null 2>&1
fi

if [ -n "$PG_HOST" ]; then
  echo ">>> PostgreSQL 预热..."
  sysbench oltp_read_write \
    --db-driver=pgsql --pgsql-host=$PG_HOST --pgsql-user=$PG_USER --pgsql-password=$PG_PASS \
    --tables=${TABLES:-16} --table-size=${TABLE_SIZE:-1000000} \
    --threads=16 --time=$DURATION \
    run > /dev/null 2>&1
fi

echo "=== 预热完成 ==="

12.3.3 验证预热效果

-- MySQL: 检查 Buffer Pool 命中率
SHOW STATUS LIKE 'Innodb_buffer_pool_read%';
-- 命中率 = 1 - (Innodb_buffer_pool_reads / Innodb_buffer_pool_read_requests)
-- 理想值 > 99%

-- PostgreSQL: 检查 Buffer Cache 命中率
SELECT 
  sum(blks_hit) * 100.0 / NULLIF(sum(blks_hit) + sum(blks_read), 0) AS hit_ratio
FROM pg_stat_database WHERE datname = 'sbtest';
-- 理想值 > 99%

12.4 结果收集与分析

12.4.1 自动化结果收集

#!/bin/bash
# collect_results.sh - 自动化结果收集

RESULT_DIR="./benchmark_$(date +%Y%m%d_%H%M%S)"
mkdir -p "$RESULT_DIR"

echo "=== 结果目录: $RESULT_DIR ==="

# 记录系统信息
cat > "$RESULT_DIR/system_info.txt" << EOF
日期: $(date)
主机名: $(hostname)
内核: $(uname -r)
CPU: $(lscpu | grep 'Model name' | cut -d: -f2 | xargs)
核心数: $(nproc)
内存: $(free -h | grep Mem | awk '{print $2}')
磁盘: $(lsblk -d -o NAME,SIZE,ROTA,MODEL | grep -v NAME)
EOF

# 记录数据库信息
if command -v mysql &> /dev/null; then
  mysql -h 127.0.0.1 -u root -psecret -e "SELECT VERSION();" > "$RESULT_DIR/mysql_info.txt" 2>/dev/null
fi

# 运行测试并收集 JSON 结果
run_test() {
  local test_name=$1
  shift
  
  echo ">>> 运行: $test_name"
  sysbench "$@" --json="$RESULT_DIR/${test_name}.json" run
  
  # 提取关键指标
  local tps=$(jq '.transactions.per_second' "$RESULT_DIR/${test_name}.json")
  local avg_latency=$(jq '.latency.avg' "$RESULT_DIR/${test_name}.json")
  local p95=$(jq '.latency.percentile_95' "$RESULT_DIR/${test_name}.json")
  
  echo "  TPS: $tps, Avg Latency: ${avg_latency}ms, P95: ${p95}ms"
}

# 运行各种测试
run_test "cpu_t1" cpu --threads=1 --time=60
run_test "cpu_t8" cpu --threads=8 --time=60
run_test "memory_t4" memory --memory-block-size=1M --threads=4 --time=60

# 数据库测试
if [ -n "$MYSQL_HOST" ]; then
  run_test "oltp_rw_t8" oltp_read_write \
    --mysql-host=$MYSQL_HOST --mysql-user=$MYSQL_USER --mysql-password=$MYSQL_PASS \
    --tables=16 --table-size=1000000 --threads=8 --time=300
  
  run_test "oltp_rw_t16" oltp_read_write \
    --mysql-host=$MYSQL_HOST --mysql-user=$MYSQL_USER --mysql-password=$MYSQL_PASS \
    --tables=16 --table-size=1000000 --threads=16 --time=300
fi

# 生成摘要
echo ""
echo "=== 测试摘要 ==="
echo "结果保存在: $RESULT_DIR"
ls -la "$RESULT_DIR"/*.json

12.4.2 结果解析脚本

#!/bin/bash
# parse_results.sh - 解析 JSON 结果

RESULT_DIR=$1

if [ -z "$RESULT_DIR" ]; then
  echo "Usage: $0 <result_dir>"
  exit 1
fi

echo "========================================="
echo "  Sysbench 测试结果摘要"
echo "========================================="
echo ""
printf "%-20s %10s %10s %10s %10s\n" "测试项" "TPS" "QPS" "Avg(ms)" "P95(ms)"
printf "%-20s %10s %10s %10s %10s\n" "-----" "---" "---" "-------" "-------"

for json_file in "$RESULT_DIR"/*.json; do
  [ -f "$json_file" ] || continue
  
  test_name=$(basename "$json_file" .json)
  tps=$(jq '.transactions.per_second // 0' "$json_file" 2>/dev/null || echo "N/A")
  qps=$(jq '.queries.per_second // 0' "$json_file" 2>/dev/null || echo "N/A")
  avg=$(jq '.latency.avg // 0' "$json_file" 2>/dev/null || echo "N/A")
  p95=$(jq '.latency.percentile_95 // 0' "$json_file" 2>/dev/null || echo "N/A")
  
  printf "%-20s %10.2f %10.2f %10.2f %10.2f\n" "$test_name" "$tps" "$qps" "$avg" "$p95"
done

echo ""
echo "========================================="

12.5 结果解读

12.5.1 关键指标解读指南

指标中等说明
TPS越高越好取决于场景低于基线 10%每秒事务数
P95 延迟< 10ms10-50ms> 100ms95% 请求的响应时间
P99 延迟< 50ms50-200ms> 500ms99% 请求的响应时间
平均延迟< 5ms5-20ms> 50ms所有请求的平均响应时间
最大延迟< 100ms100-500ms> 1000ms单个请求的最长响应时间
标准差< 平均值 10%平均值 10-50%> 平均值 50%性能波动程度

12.5.2 性能瓶颈识别

  ┌─────────────────────────────────────────────────────────────┐
  │                    性能瓶颈诊断流程                           │
  └─────────────────────────────────────────────────────────────┘
  
  TPS 低 + CPU 高
  ├── CPU 密集型瓶颈
  │   ├── 优化 SQL 查询
  │   ├── 增加索引
  │   └── 升级 CPU
  └── 检查: top, mpstat

  TPS 低 + 磁盘 I/O 高
  ├── I/O 密集型瓶颈
  │   ├── 增加 Buffer Pool
  │   ├── 优化查询(减少 I/O)
  │   ├── 升级存储(SSD)
  │   └── 增加内存(减少磁盘访问)
  └── 检查: iostat, iotop

  TPS 低 + 延迟高
  ├── 锁/等待瓶颈
  │   ├── 检查锁等待
  │   ├── 优化事务大小
  │   ├── 减少锁冲突
  │   └── 检查网络延迟
  └── 检查: SHOW PROCESSLIST, SHOW ENGINE INNODB STATUS

  TPS 低 + 资源空闲
  ├── 并发/连接瓶颈
  │   ├── 增加 max_connections
  │   ├── 使用连接池
  │   ├── 调整 thread_cache_size
  │   └── 检查应用端瓶颈
  └── 检查: SHOW STATUS LIKE 'Threads%'

12.5.3 MySQL 性能诊断

-- 查看当前运行的查询
SELECT * FROM information_schema.processlist 
WHERE command != 'Sleep' AND time > 1 
ORDER BY time DESC;

-- 查看 InnoDB 状态
SHOW ENGINE INNODB STATUS\G

-- 查看锁等待
SELECT * FROM information_schema.innodb_lock_waits;

-- 查看索引使用情况
SELECT * FROM sys.schema_unused_indexes;
SELECT * FROM sys.schema_redundant_indexes;

-- 查看表统计
SELECT table_name, table_rows, data_length, index_length
FROM information_schema.tables
WHERE table_schema = 'sbtest'
ORDER BY data_length DESC;

12.6 测试报告生成

12.6.1 Markdown 报告模板

#!/bin/bash
# generate_report.sh - 生成 Markdown 测试报告

RESULT_DIR=$1
REPORT_FILE="$RESULT_DIR/report.md"

cat > "$REPORT_FILE" << 'HEADER'
# Sysbench 性能测试报告

## 测试环境

| 项目 | 详情 |
|------|------|
HEADER

echo "| 测试日期 | $(date '+%Y-%m-%d %H:%M:%S') |" >> "$REPORT_FILE"
echo "| 操作系统 | $(cat /etc/os-release | grep PRETTY_NAME | cut -d= -f2 | tr -d '"') |" >> "$REPORT_FILE"
echo "| 内核版本 | $(uname -r) |" >> "$REPORT_FILE"
echo "| CPU | $(lscpu | grep 'Model name' | cut -d: -f2 | xargs) |" >> "$REPORT_FILE"
echo "| CPU 核心 | $(nproc) |" >> "$REPORT_FILE"
echo "| 内存 | $(free -h | grep Mem | awk '{print $2}') |" >> "$REPORT_FILE"
echo "| Sysbench 版本 | $(sysbench --version 2>&1 | head -1) |" >> "$REPORT_FILE"

cat >> "$REPORT_FILE" << 'TABLE_HEADER'

## 测试结果

| 测试项 | TPS | QPS | 平均延迟(ms) | P95延迟(ms) | P99延迟(ms) |
|--------|-----|-----|-------------|------------|------------|
TABLE_HEADER

for json_file in "$RESULT_DIR"/*.json; do
  [ -f "$json_file" ] || continue
  
  test_name=$(basename "$json_file" .json)
  tps=$(jq '.transactions.per_second // 0' "$json_file")
  qps=$(jq '.queries.per_second // 0' "$json_file")
  avg=$(jq '.latency.avg // 0' "$json_file")
  p95=$(jq '.latency.percentile_95 // 0' "$json_file")
  p99=$(jq '.latency.percentile_99 // 0' "$json_file")
  
  echo "| $test_name | $tps | $qps | $avg | $p95 | $p99 |" >> "$REPORT_FILE"
done

cat >> "$REPORT_FILE" << 'FOOTER'

## 结论

1. (在此填写测试结论)
2. (在此填写性能建议)
3. (在此填写后续优化方向)

## 附录

### 测试命令

```bash
# CPU 测试
sysbench cpu --threads=8 --time=60 run

# OLTP 测试
sysbench oltp_read_write --tables=16 --table-size=1000000 --threads=16 --time=300 run

注意事项

  • 测试期间无其他负载
  • 数据库缓存已预热
  • 每项测试运行 3 次取平均值 FOOTER

echo "" echo “报告已生成: $REPORT_FILE”


### 12.6.2 HTML 报告生成

```bash
#!/bin/bash
# generate_html_report.sh

RESULT_DIR=$1
HTML_FILE="$RESULT_DIR/report.html"

cat > "$HTML_FILE" << 'EOF'
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Sysbench 性能测试报告</title>
  <style>
    body { font-family: Arial, sans-serif; margin: 20px; }
    table { border-collapse: collapse; width: 100%; margin: 20px 0; }
    th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
    th { background-color: #4CAF50; color: white; }
    tr:nth-child(even) { background-color: #f2f2f2; }
    .good { color: green; font-weight: bold; }
    .warning { color: orange; font-weight: bold; }
    .bad { color: red; font-weight: bold; }
    h1 { color: #333; }
    h2 { color: #666; border-bottom: 2px solid #4CAF50; padding-bottom: 5px; }
  </style>
</head>
<body>
  <h1>Sysbench 性能测试报告</h1>
  
  <h2>测试环境</h2>
  <table>
    <tr><th>项目</th><th>详情</th></tr>
    <tr><td>测试日期</td><td>DATE_PLACEHOLDER</td></tr>
    <tr><td>操作系统</td><td>OS_PLACEHOLDER</td></tr>
    <tr><td>CPU</td><td>CPU_PLACEHOLDER</td></tr>
    <tr><td>内存</td><td>MEM_PLACEHOLDER</td></tr>
  </table>
  
  <h2>测试结果</h2>
  <table>
    <tr>
      <th>测试项</th>
      <th>TPS</th>
      <th>QPS</th>
      <th>平均延迟(ms)</th>
      <th>P95延迟(ms)</th>
      <th>P99延迟(ms)</th>
    </tr>
    RESULT_ROWS
  </table>
  
  <h2>结论</h2>
  <ul>
    <li>(在此填写测试结论)</li>
  </ul>
</body>
</html>
EOF

# 替换占位符
sed -i "s|DATE_PLACEHOLDER|$(date '+%Y-%m-%d %H:%M:%S')|" "$HTML_FILE"
sed -i "s|OS_PLACEHOLDER|$(cat /etc/os-release | grep PRETTY_NAME | cut -d= -f2 | tr -d '\"')|" "$HTML_FILE"
sed -i "s|CPU_PLACEHOLDER|$(lscpu | grep 'Model name' | cut -d: -f2 | xargs)|" "$HTML_FILE"
sed -i "s|MEM_PLACEHOLDER|$(free -h | grep Mem | awk '{print $2}')|" "$HTML_FILE"

# 生成结果行
ROWS=""
for json_file in "$RESULT_DIR"/*.json; do
  [ -f "$json_file" ] || continue
  
  test_name=$(basename "$json_file" .json)
  tps=$(jq '.transactions.per_second // 0' "$json_file")
  qps=$(jq '.queries.per_second // 0' "$json_file")
  avg=$(jq '.latency.avg // 0' "$json_file")
  p95=$(jq '.latency.percentile_95 // 0' "$json_file")
  p99=$(jq '.latency.percentile_99 // 0' "$json_file")
  
  ROWS="$ROWS<tr><td>$test_name</td><td>$tps</td><td>$qps</td><td>$avg</td><td>$p95</td><td>$p99</td></tr>\n"
done

sed -i "s|RESULT_ROWS|$ROWS|" "$HTML_FILE"

echo "HTML 报告已生成: $HTML_FILE"

12.7 常见陷阱与避坑指南

12.7.1 测试环境陷阱

陷阱表现解决方案
测试数据量太小Buffer Pool 100% 命中,结果偏高数据集 > Buffer Pool
测试时间太短结果波动大至少 5 分钟
只运行一次偶然因素影响至少运行 3 次
未预热第一次测试结果偏低先短时间预热
有其他负载结果不稳定关闭无关服务
使用 root 用户安全风险创建专用测试用户
未清理缓存文件 I/O 测试不准使用 O_DIRECT 或 drop_caches

12.7.2 结果解读陷阱

陷阱表现正确做法
只看 TPS忽略延迟问题同时关注 P95/P99 延迟
跨版本对比不同 Sysbench 版本不可比使用相同版本
忽略标准差平均值掩盖了波动关注 stddev
绝对化数字不同硬件结果不同关注相对变化
忽略业务差异标准测试 ≠ 真实业务结合业务场景测试

12.7.3 数据库测试陷阱

陷阱表现解决方案
prepare 后不预热前几次测试结果偏低prepare 后先预热
多测试不重新 prepare数据分布变化重要测试前重新 prepare
忽略 autovacuum (PG)测试期间 VACUUM 干扰监控或禁用
忽略 binlog (MySQL)写入测试受影响评估是否需要 binlog
连接数不足报错或性能低检查 max_connections
隔离级别不同PG 和 MySQL 默认不同统一隔离级别

12.8 性能基线管理

12.8.1 建立性能基线

#!/bin/bash
# establish_baseline.sh - 建立性能基线

BASELINE_DIR="./baseline/$(date +%Y%m%d)"
mkdir -p "$BASELINE_DIR"

echo "=== 建立性能基线 ==="

# 记录环境信息
cat > "$BASELINE_DIR/env.txt" << EOF
日期: $(date)
主机: $(hostname)
内核: $(uname -r)
CPU: $(lscpu | grep 'Model name' | cut -d: -f2 | xargs)
内存: $(free -h | grep Mem | awk '{print $2}')
EOF

# 运行基线测试
for i in 1 2 3; do
  echo "--- 第 $i 次运行 ---"
  sysbench cpu --threads=$(nproc) --time=60 \
    --json="$BASELINE_DIR/cpu_run${i}.json" run
  
  sysbench memory --memory-block-size=1M --threads=$(nproc) --time=60 \
    --json="$BASELINE_DIR/mem_run${i}.json" run
done

# 计算平均值
echo ""
echo "=== 基线结果(3 次平均) ==="
cpu_avg=$(jq -s 'map(.cpu_speed.events_per_second) | add / length' "$BASELINE_DIR"/cpu_run*.json)
echo "CPU events/sec: $cpu_avg"

mem_avg=$(jq -s 'map(.total_number_of_events) | add / length' "$BASELINE_DIR"/mem_run*.json)
echo "Memory operations: $mem_avg"

# 保存基线
echo "$cpu_avg" > "$BASELINE_DIR/cpu_baseline.txt"
echo "$mem_avg" > "$BASELINE_DIR/mem_baseline.txt"

12.8.2 基线对比

#!/bin/bash
# compare_with_baseline.sh - 与基线对比

BASELINE_DIR=$1
CURRENT_RESULT=$2
THRESHOLD=${3:-5}  # 默认阈值 5%

# 对比 CPU
cpu_baseline=$(cat "$BASELINE_DIR/cpu_baseline.txt")
cpu_current=$(jq '.cpu_speed.events_per_second' "$CURRENT_RESULT/cpu_run1.json")
cpu_diff=$(echo "scale=2; ($cpu_current - $cpu_baseline) / $cpu_baseline * 100" | bc)

echo "=== CPU 性能对比 ==="
echo "基线: $cpu_baseline"
echo "当前: $cpu_current"
echo "变化: ${cpu_diff}%"

if (( $(echo "$cpu_diff < -$THRESHOLD" | bc -l) )); then
  echo "⚠️  警告: CPU 性能下降超过 ${THRESHOLD}%!"
fi

12.9 持续性能监控

12.9.1 定期性能测试脚本

#!/bin/bash
# periodic_benchmark.sh - 定期性能测试

LOG_DIR="./benchmark_logs"
mkdir -p "$LOG_DIR"

LOG_FILE="$LOG_DIR/benchmark_$(date +%Y%m%d_%H%M%S).log"

{
  echo "=== 性能测试开始: $(date) ==="
  
  sysbench cpu --threads=$(nproc) --time=60 run 2>&1
  echo ""
  
  sysbench memory --memory-block-size=1M --threads=$(nproc) --time=60 run 2>&1
  echo ""
  
  if [ -n "$MYSQL_HOST" ]; then
    sysbench oltp_read_write \
      --mysql-host=$MYSQL_HOST --mysql-user=$MYSQL_USER --mysql-password=$MYSQL_PASS \
      --tables=16 --table-size=1000000 --threads=16 --time=300 run 2>&1
  fi
  
  echo "=== 性能测试结束: $(date) ==="
} | tee "$LOG_FILE"

12.9.2 cron 定时任务

# 编辑 crontab
# crontab -e

# 每天凌晨 3 点运行性能测试
0 3 * * * /opt/scripts/periodic_benchmark.sh >> /var/log/benchmark.log 2>&1

# 每周一生成报告
0 4 * * 1 /opt/scripts/generate_report.sh /opt/results >> /var/log/benchmark_report.log 2>&1

12.10 总结与建议

12.10.1 性能测试检查清单

序号检查项状态
1明确测试目标和指标
2记录测试环境信息
3关闭不必要的服务和进程
4清空文件缓存(文件 I/O 测试)
5设置 CPU 调度器为 performance
6创建测试数据库和用户
7准备足够的测试数据
8执行预热
9运行测试至少 3 次
10收集 JSON/CSV 结果
11检查结果一致性(标准差)
12生成测试报告
13清理测试数据
14归档结果和配置

12.10.2 性能优化路线图

  ┌─────────────────────────────────────────────────────────────┐
  │                    性能优化路线图                             │
  └─────────────────────────────────────────────────────────────┘
  
  Level 1: 快速优化(低成本,高收益)
  ├── 调整 innodb_buffer_pool_size
  ├── 添加缺失索引
  ├── 优化慢查询 SQL
  └── 预期提升: 50-200%
  
  Level 2: 中等优化(中等成本,中等收益)
  ├── 升级存储到 SSD
  ├── 增加内存
  ├── 调整 Redo Log 大小
  └── 预期提升: 30-100%
  
  Level 3: 深度优化(高成本,较高收益)
  ├── 架构优化(读写分离、分库分表)
  ├── 缓存层引入(Redis/Memcached)
  ├── 硬件升级(CPU/内存/存储)
  └── 预期提升: 100-500%
  
  Level 4: 架构重构(极高成本,极高收益)
  ├── 数据库迁移(MySQL → 分布式数据库)
  ├── 微服务化改造
  ├── 全链路优化
  └── 预期提升: 500-1000%+

扩展阅读