嘗試在 MySQL 觸發器中透過 mysql-udf-http 呼叫遠端 HTTP 介面同步 Memcached,實測發現**效能極差**,本文記錄完整測試環境、代碼、數據與瓶頸定位過程。
測試環境
| 項目 | 配置 |
| OS | Linux 2.6.18 (虛擬機), 376MB RAM, 233MB Used |
| MySQL | 5.1.26-rc-log |
| 測試表 | mytable(id, addtime, title) MyISAM |
| Memcached | 192.168.0.134:11211 |
基準測試:直連效能
| 操作 | 耗時 (1000筆) | 說明 |
| PHP → MySQL INSERT | 0.9 秒 | 單連線循環插入 |
| PHP → Memcached SET | 0.8 秒 | 單連線循環寫入 |
觸發器 + HTTP 同步架構
觸發器定義
DELIMITER $$
CREATE TRIGGER `mytable_insert` AFTER INSERT ON `mytable`
FOR EACH ROW BEGIN
SET @result = http_put(CONCAT('https://192.168.0.134/mem_ss.php?type=post&id=', NEW.id, '&data=', NEW.addtime), 11);
END$$
DELIMITER ;
遠端 PHP 同步腳本 (mem_ss.php)
connect('192.168.0.134', 11211);
switch ($type) {
case 'post': $mem->set($id, $data, 0, 3600); break;
case 'put': $mem->replace($id, $data, 0, 3600); break;
case 'get': echo $mem->get($id); break;
case 'delete': $mem->delete($id); break;
}
$mem->close();
實測結果
| 場景 | 1000 筆耗時 | 單筆平均 | 對比基準 |
| PHP 直連 MySQL INSERT | 0.9 秒 | 0.9 ms | 基準 |
| 觸發器 INSERT → tmp_mytable (本地表) | 0.7 秒 | 0.7 ms | 觸發器本身極輕量 |
| 觸發器 INSERT → http_put → Memcached | 9 秒 | 9 ms | 慢 10-13 倍 |
瓶頸定位:http_put UDF 是罪魁禍首
- 觸發器本體僅增加 0.7ms/筆 (本地表寫入)。
http_put 執行:建立 TCP 連線 → HTTP 請求 → PHP 解析 → Memcached 協議 → 回應 → 關閉連線。
- **單次 HTTP 往返 ~8ms**,佔總耗時 90%+。
- 虛擬機網路延遲、PHP CGI 啟動開銷、無連線池放大問題。
為何此架構不適合生產?
- 同步阻塞: 觸發器同步等待 HTTP 回應,嚴重拖慢主庫寫入延遲。
- 無重試/熔斷: 遠端不可用時,主庫寫入直接失敗/卡死。
- 單點故障: HTTP 介面掛掉 = 同步中斷,資料不一致。
- 效能不可控: 網路抖動直接反映到資料庫回應時間。
可行替代方案
| 方案 | 原理 | 優點 | 缺點 |
| memcached_functions_mysql UDF | 資料庫層直接呼叫 Memcached 二進制協議 | 無 HTTP 開銷、延遲 < 1ms | 版本相容性極難搞 |
| Binlog 解析同步 (Canal/Maxwell) | 異步讀取 Binlog → 更新 Memcached | 零侵入、高效能、可重試 | 需部署額外組件 |
| 應用層雙寫/事務性發件箱 | 應用代碼寫 DB + 發送 MQ → Worker 更新快取 | 可控、成熟模式 | 需修改應用代碼 |
| 觸發器寫本地佇列表 + 獨立 Worker | 觸發器 INSERT queue_table → Worker 輪詢同步 | 解耦、可批次、可重試 | 有秒級延遲 |
結論
mysql-udf-http 觸發器同步 Memcached 方案在效能、穩定性、可維護性上均不達標。 核心教訓:**資料庫觸發器嚴禁進行同步網路 I/O 操作**。若需資料庫層同步,請採用 Binlog 異步解析或原生 UDF;架構層面優先考慮應用層事務性發件箱模式。