首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫

MySQL Proxy 讀寫分離 Lua 腳本遷坑指南:rwsplitting 升級、Prepare 模式、Keepalive 高可用

     編輯:MySQL 資料庫相關知識

MySQL Proxy 0.7+ 讀寫分離實戰:Lua 腳本版本陷阱、PDO Prepare 兼容、高可用部署

MySQL Proxy 透過 Lua 腳本實現讀寫分離,但 0.6→0.7 版本 API 破壞性變更導致舊腳本失效,且 PHP PDO Prepare 模式與 Proxy 兼容性差。本文記錄遷坑全過程與生產級部署方案。

核心架構

應用 → MySQL Proxy (Lua 腳本路由) → Master (寫) / Slaves (讀)

坑一:Lua 腳本 API 破壞性變更

錯誤日誌**:

(critical) proxy-plugin.c:1367: .address is deprecated. Use .src.name or .dst.name instead
(critical) (read_query) .address is deprecated.
I have no server backend, closing connection

原因**:0.7 版本廢棄 proxy.connection.client.address,改為 .src.name/.dst.name。官方附帶的 rw-splitting.lua 未同步更新。

解決**:

  1. 從官方倉庫獲取最新腳本:https://launchpad.net/mysql-proxy-lua-scripts
  2. 或手動替換舊腳本中所有 .address → .src.name (客戶端) / .dst.name (後端)
  3. 關鍵函數 connect_server()、read_query() 內的後端選擇邏輯必須更新

坑二:PHP PDO Prepare 模式不兼容

現象**:單獨連 MySQL 正常,經 Proxy 查詢隨機無結果、無報錯。
根因**:Proxy 對 COM_STMT_PREPARE/COM_STMT_EXECUTE 二進制協議處理有缺陷。
繞過方案**:強制 PDO 使用模擬準備(客戶端模擬,非 Server 端):

$pdo = new PDO($dsn, $user, $pass, [
    PDO::ATTR_EMULATE_PREPARES => true,  // 關鍵!
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
]);

副作用**:失去 Server 端準備語句緩存優勢,但換取穩定性。實測模擬模式效能不差 (甚至略好,省去協議交互)。

坑三:Proxy 單點故障與 Keepalive 高可用

Proxy 自身會 Crash,需外部守護:

# 啟動參數加入 keepalive
mysql-proxy --defaults-file=/etc/mysql-proxy.cnf --keepalive --daemon

生產級高可用方案**:

  1. 雙 Proxy + VIP 漂移**:Keepalived 管理 VIP,健康檢查 mysqladmin ping
  2. Systemd 守護**:
    [Service]
    Restart=always
    RestartSec=5
    ExecStart=/usr/local/mysql-proxy/bin/mysql-proxy --defaults-file=/etc/mysql-proxy.cnf --keepalive
  3. 監控告警**:Prometheus 監控 proxy_up、proxy_backend_up、proxy_query_latency

完整配置範例

# /etc/mysql-proxy.cnf
[mysql-proxy]
daemon = true
keepalive = true
log_file = /var/log/mysql-proxy.log
log_level = info

proxy_address = 0.0.0.0:4040
proxy_read_only_backend_addresses = 10.0.1.10:3306,10.0.1.11:3306
proxy_backend_addresses = 10.0.1.9:3306

# Lua 腳本路徑 (使用更新版 rw-splitting.lua)
proxy_lua_script = /usr/local/mysql-proxy/share/lua/rw-splitting.lua

# 連接池/超時
proxy_pool_no_change_user = true
proxy_fix_bug_25371 = 1
proxy_connect_timeout = 5
proxy_read_timeout = 30
proxy_write_timeout = 30

Lua 腳本關鍵邏輯 (rw-splitting.lua 核心片段)

function read_query(packet)
    if packet:byte() == proxy.COM_QUERY then
        local query = packet:sub(2)
        -- SELECT / SHOW / BEGIN 走從庫
        if query:match("^%s*SELECT") or query:match("^%s*SHOW") or query:match("^%s*BEGIN") then
            proxy.queries:append(1, string.char(proxy.COM_QUERY) .. query)
            return proxy.PROXY_SEND_QUERY
        end
    end
    return nil  -- 其他 (INSERT/UPDATE/DELETE/DDL) 走主庫
end

function connect_server(proxy)
    -- 後端連接建立時的初始化
    -- 可在這裡 SET NAMES utf8mb4、SET SESSION sql_mode...
end

替代方案對比

方案優點缺點推薦場景
MySQL Proxy + Lua輕量、透明、可編程路由單點、Lua 維護成本高、Prepare 兼容差舊系統改造、簡單讀寫分離
ProxySQL高效能、連接池、查詢緩存、熔斷、集群管理、Web UI學習曲線、資源佔用較大**生產環境首選**
MaxScaleMariaDB 官方、Binlog 過濾、安全防火牆商業功能收費、較重MariaDB 生態、合規審計
應用層路由零中間件、靈活控制代碼侵入、連接池分散微服務、多語言

總結

MySQL Proxy 讀寫分離可用,但**必須使用更新版 Lua 腳本**、**強制 PDO 模擬 Prepare**、**部署 Keepalive/雙機高可用**。新架構強烈建議直接上 **ProxySQL**,功能完備、社群活躍、生產驗證充分。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved