本文通過多組對照實驗,測試 Docker 容器化開銷、網絡連接方式、數據庫版本、MySQL 與 PostgreSQL 性能差異,揭示影響數據庫性能的真正因素。
測試背景
網上關於數據庫性能的説法眾説紛紜:
- "Docker 部署數據庫有性能損耗"
- "PostgreSQL 比 MySQL 快"
- "Unix socket 比 TCP 快"
為了搞清楚真相,我在阿里雲 ECS 上進行了一系列對照實驗。
測試環境:
- 服務器:阿里雲 ECS 2核2G
- 系統:Alibaba Cloud Linux 8 (kernel 5.10.134)
- MySQL:8.0.27 / 8.0.44
- PostgreSQL:13.22
- 測試工具:sysbench 1.0.20 / pgbench
一、Docker 橋接網絡:性能殺手
初始測試
第一次測試時,我用最簡單的方式啓動 Docker MySQL:
docker run -d -p 3307:3306 mysql:8.0
結果讓我大吃一驚:
| 併發數 | 裸機(Unix socket) | Docker(橋接網絡) | 差距 |
|---|---|---|---|
| 50 | 625 QPS | 63 QPS | 10倍 |
| 100 | 667 QPS | 64 QPS | 10倍 |
| 500+ | 正常 | 崩潰 | - |
問題分析
這個對比極不公平:
- 裸機用 Unix socket,Docker 用 TCP
- Docker 使用橋接網絡 + NAT 端口轉發
- Docker 默認 max_connections=151
橋接網絡的 NAT 轉發是性能殺手,不是 Docker 本身。
二、Unix Socket vs TCP:23% 的差距
同一台裸機 MySQL,測試不同連接方式:
# Unix socket
sysbench --mysql-socket=/var/lib/mysql/mysql.sock ...
# TCP
sysbench --mysql-host=127.0.0.1 --mysql-port=3306 ...
| 連接方式 | QPS | 差異 |
|---|---|---|
| Unix Socket | 3,476 | 基準 |
| TCP 127.0.0.1 | 2,662 | -23% |
Unix socket 直接通過內核通信,省去 TCP 協議棧開銷。
三、Docker vs 裸機:幾乎無差異
公平測試條件
- 同版本:MySQL 8.0.44
- 同數據:Docker 掛載裸機數據目錄
- 同連接:都用 Unix socket
- 清緩存:
echo 3 > /proc/sys/vm/drop_caches
docker run -d \
-v /var/lib/mysql:/var/lib/mysql \
-v /root/mysql-docker/socket:/var/run/mysqld \
mysql:8.0.44
測試結果
| 線程數 | Docker QPS | 裸機 QPS | 差異 |
|---|---|---|---|
| 50 | 3,567 | 3,454 | +3% |
| 100 | 3,347 | 3,362 | -0.4% |
結論:同等條件下,Docker 和裸機性能幾乎完全一致!
四、MySQL 版本:新版不一定更快
| 版本 | 50線程 TPS |
|---|---|
| 8.0.27 | 5,366 |
| 8.0.44 | 5,016 |
8.0.27 比 8.0.44 快約 7%,升級需謹慎。
五、MySQL vs PostgreSQL:MySQL 更快
這是最有爭議的話題。為保證公平:
- 相同數據量:10 萬行
- 相同測試類型:單點查詢(point select)
- 相同併發數
注意 TPS vs QPS:
pgbench -S:每事務 = 1 個 SELECT → TPS = QPSsysbench oltp_point_select:每事務 = 1 個 SELECT → TPS = QPSsysbench oltp_read_only:每事務 = 16 個查詢 → QPS = TPS × 16
測試結果
| 線程 | MySQL TPS | PostgreSQL TPS | MySQL 優勢 |
|---|---|---|---|
| 10 | 6,410 | 5,373 | +19% |
| 50 | 6,502 | 5,267 | +23% |
| 100 | 6,590 | 4,753 | +39% |
關鍵發現
- MySQL 吞吐量更高:各併發級別都領先 20-40%
- MySQL 高併發更穩定:併發增加,性能略有提升
- PostgreSQL 高併發下降:100 線程比 10 線程降了 12%
六、踩坑記錄:sysbench table-size 參數
現象
早期測試看到 5000+ QPS 的"好成績",後來發現是假象。
原因
table-size 參數告訴 sysbench 表有多少行,但實際數據可能不匹配:
| table-size 參數 | 實際行數 | 空查詢比例 | QPS |
|---|---|---|---|
| 10,000 | 10,000 | 0% | 3,550 |
| 31,898 | 10,000 | 68% | 5,016 |
| 500,000 | 10,000 | 98% | 5,008 |
空查詢返回更快,造成虛假高性能。
正確做法
# 先檢查實際行數
mysql -e "SELECT COUNT(*) FROM sxsz_db.sbtest1;"
# table-size 必須與實際行數一致
sysbench --table-size=10000 ...
七、性能影響因素排序
| 因素 | 性能影響 | 説明 |
|---|---|---|
| 橋接網絡 vs Host/Socket | ~10倍 | NAT 轉發開銷巨大 |
| MySQL vs PostgreSQL | ~20-40% | MySQL 單點查詢更快 |
| Unix socket vs TCP | ~23% | 內核直接通信更快 |
| MySQL 版本 | ~7% | 新版不一定更快 |
| Docker 容器開銷 | <5% | 幾乎可忽略 |
八、最佳實踐
Docker MySQL 高性能配置
docker run -d \
--name mysql \
--network=host \
-v /data/mysql:/var/lib/mysql \
mysql:8.0 \
--max_connections=2000
或使用 Unix socket 掛載:
docker run -d \
--name mysql \
-v /data/mysql:/var/lib/mysql \
-v /var/run/mysqld:/var/run/mysqld \
mysql:8.0
應用連接字符串
// Unix socket(最快)
dsn := "user:pass@unix(/var/run/mysqld/mysqld.sock)/dbname"
// TCP(稍慢,但更通用)
dsn := "user:pass@tcp(127.0.0.1:3306)/dbname"
MySQL vs PostgreSQL 選型建議
| 場景 | 推薦 |
|---|---|
| 高併發簡單查詢 | MySQL |
| 複雜查詢/分析 | PostgreSQL |
| 需要高級特性(JSON、全文搜索) | 各有千秋,需具體評估 |
總結
- Docker 本身開銷可忽略(<5%),橋接網絡才是性能殺手
- Unix socket 比 TCP 快 23%,優先使用
- MySQL 單點查詢比 PostgreSQL 快 20-40%,高併發下差距更大
- 測試方法很重要,參數錯誤會得出錯誤結論
測試日期:2025年12月
測試環境:阿里雲 ECS 2核2G,Alibaba Cloud Linux 8
測試工具:sysbench 1.0.20,pgbench (PostgreSQL 13.22)