來源:Using MySQL as a NoSQL - A story for exceeding 750,000 qps on a commodity server
DeNA 團隊為何放棄 Memcached+MySQL 架構,轉而單靠 MySQL 達到 75 萬 QPS?本文深度剖析 SQL 層開銷、HandlerSocket 原理、安裝部署、基準測試與生產落地經驗。
基準測試環境:Dell PowerEdge R710,Nehalem 8 核 2.53GHz,32GB 內存,MySQL 5.1.50 InnoDB,全內存數據。
| 方案 | QPS | %us | %sy | 瓶頸分析 |
|---|---|---|---|---|
| MySQL via SQL | 105,000 | 60% | 28% | SQL 解析、優化器、表鎖、互斥鎖 |
| Memcached | 420,000 | 8% | 88% | 網絡 I/O、系統調用 |
| MySQL via HandlerSocket | 750,000+ | 45% | 53% | 網絡驅動、InnoDB 核心邏輯 |
OProfile 火焰圖顯示:MYSQLparse()、JOIN::optimize()、my_pthread_fastmutex_lock() 佔據大量 CPU。MySQL 每次 PK 查詢都要經歷 解析 → 開表/鎖表 → 優化器 → 解鎖/關表,且全局互斥鎖(LOCK_open、LOCK_thread_count)導致嚴重併發爭搶。
fsync()、複製延遲。innodb_flush_log_at_trx_commit=1 保證 <1s 數據零丟失。SHOW GLOBAL STATUS、SHOW ENGINE INNODB STATUS)完全復用。# 1. 下載源碼
git clone https://github.com/ahiguti/HandlerSocket-Plugin-for-MySQL.git
cd HandlerSocket-Plugin-for-MySQL
# 2. 編譯(需 MySQL 源碼與安裝路徑)
./configure --with-mysql-source=/path/to/mysql-source --with-mysql-bindir=/path/to/mysql/bin
make && make install
# 3. 安裝插件
mysql> INSTALL PLUGIN handlersocket SONAME 'handlersocket.so';
# 4. 配置 my.cnf [mysqld] 區段
loose_handlersocket_port = 9998 # 讀寫端口
loose_handlersocket_port_wr = 9999 # 僅寫端口(可選)
loose_handlersocket_threads = 16 # Worker 線程數,建議 CPU 核心數 x 2
loose_handlersocket_threads_wr = 8
use Net::HandlerSocket;
my $hs = Net::HandlerSocket->new({ host => '127.0.0.1', port => 9998 });
# open_index(index_id, db, table, index_name, columns)
$hs->open_index(0, 'test', 'user', 'PRIMARY', 'user_name,user_email,created');
# execute_single(index_id, op, values, limit, offset)
my $res = $hs->execute_single(0, '=', ['101'], 1, 0);
die $hs->get_error() if $res->[0] != 0;
shift @$res;
print "$res->[0]\t$res->[1]\t$res->[2]\n"; # user_name, email, created
$hs->close();
$ telnet 127.0.0.1 9998
P 0 test user PRIMARY user_name,user_email,created
0 1 0 = 1 101
0 3 Yukari Takeba yukari.takeba@dena.jp 2010-02-03 11:22:33
綠色行為請求封包,字段以 Tab 分隔。
LIMIT / OFFSETINSERT / UPDATE / DELETE(單行)multi_get:單次網絡往返獲取多鍵值(類似 IN (1,2,3))不支援:無索引全表掃描、JOIN、聚合、子查詢、事務(自動提交模式)。
Innodb_rows_read 直接反映 HandlerSocket 吞吐,SHOW GLOBAL STATUS 即可觀測。| 限制 | 應對 |
|---|---|
| 無內建認證/授權 | 防火牆限制來源 IP;應用層做租戶隔離 |
| Worker 線程數固定 | 根據 CPU 核心數設定,避免過多線程上下文切換 |
| 不支援事務 | 單行寫入自動提交;多行一致性需應用層補償 |
| DDL 期間表會關閉 | 低峰期變更結構,或使用 pt-online-schema-change |
HandlerSocket 證明:MySQL 存儲引擎層極其高效,瓶頸在 SQL 層。通過 Plugin 形式直連 InnoDB,無需遷移數據、修改內核、引入新組件,即可獲得媲美甚至超越專業 NoSQL 的極致性能。對於「核心業務用 InnoDB,熱點讀寫用 HandlerSocket」的混合架構,是極具性價比的演進路徑。