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

MySQL Proxy 讀寫分離實戰篇:Lua 腳本實現與連接池管理

     編輯:MySQL 資料庫相關知識

核心原理

MySQL Proxy 介於應用與後端資料庫之間,攔截查詢:

  • 事務性查詢(INSERT/UPDATE/DELETE/BEGIN/COMMIT)→ Master
  • 非事務 SELECT → Slave(負載均衡)

關鍵挑戰:MySQL 協議先握手認證,再進入查詢階段。Proxy 必須預先建立並維護對每個後端的已認證連接池,才能在查詢階段無縫切換。

Lua 讀寫分離腳本完整版

-- read_write_split.lua
-- 非事務 SELECT 路由到空閒 Slave

function read_query(packet)
    if proxy.connection.client.is_in_transaction == 0 and
       packet:byte() == proxy.COM_QUERY and
       packet:sub(2, 7):upper() == "SELECT" then

        local max_conns = -1
        local chosen = 0

        for i = 1, #proxy.servers do
            local s = proxy.servers[i]
            -- 僅考慮只讀後端且有空閒連線
            if s.type == proxy.BACKEND_TYPE_RO and s.idling_connections > 0 then
                if max_conns == -1 or s.connected_clients < max_conns then
                    max_conns = s.connected_clients
                    chosen = i
                end
            end
        end

        if chosen > 0 then
            proxy.connection.backend_ndx = chosen
            return proxy.PROXY_SEND_QUERY
        end
    end

    -- 預設路由到 Master (寫入或事務中)
    return proxy.PROXY_SEND_QUERY
end

關鍵 API 說明

API用途
proxy.connection.client.is_in_transaction0=非事務,1=事務中
packet:byte()封包第一字節,COM_QUERY=3
packet:sub(2, 7)取 SQL 前 6 字元判斷 SELECT
proxy.servers[i]後端伺服器陣列
s.typeBACKEND_TYPE_RW (主) / BACKEND_TYPE_RO (從)
s.idling_connections空閒連線數
s.connected_clients當前使用連線數
proxy.connection.backend_ndx指定路由目標後端索引
proxy.PROXY_SEND_QUERY繼續發送查詢

部署架構

App --> MySQL Proxy (Lua) --> Master (RW)
                        --> Slave1 (RO)
                        --> Slave2 (RO)

啟動參數範例

mysql-proxy --proxy-address=0.0.0.0:4040 \
            --proxy-backend-addresses=10.0.0.1:3306 \   # Master
            --proxy-read-only-backend-addresses=10.0.0.2:3306,10.0.0.3:3306 \  # Slaves
            --proxy-lua-script=read_write_split.lua \
            --admin-username=admin --admin-password=pass \
            --admin-lua-script=admin.lua

連接池預熱策略

  • 啟動時建立 min_idle_connections 到每個後端。
  • 定期 ping 檢測連線存活,失效即時重建。
  • 避免查詢高峰期建立新連線導致延遲尖峰。

擴展:分片路由

同樣在 read_query 中解析 SQL,提取分片鍵(如 user_id),根據一致性雜湊或範圍映射到對應後端:

local shard_key = extract_shard_key(packet)
proxy.connection.backend_ndx = shard_map[shard_key]

監控與管理

  • Admin 介面:SELECT * FROM proxy.backends; 看連線狀態。
  • 統計:每後端 QPS、錯誤率、延遲分位數。
  • 動態上下線:proxy.backend_add()、proxy.backend_remove()。

避坑指南

  1. Proxy 單點 → 部署多實例 + VIP/Keepalived/LVS 高可用。
  2. 2. Lua 腳本錯誤導致全掛 → 充分測試、灰度發布、備用直連模式。 3. 事務中 SELECT 路由到 Slave → 造成讀舊資料,腳本嚴格判斷 is_in_transaction。 4. 大查詢佔據連線池 → 設定 max_query_time 超時熔斷。 5. 準備語句路由 → 需在 prepare_query 階段同樣判斷路由。

生產替代方案

  • ProxySQL:功能更豐富、效能更高、社群活躍,推薦新專案優先評估。
  • MyCat:Java 開發、分片功能強,適合中大型遷移專案。
  • 應用層路由:ShardingSphere、Spring Cloud Gateway,無中間件部署成本。

MySQL Proxy + Lua 實現讀寫分離雖經典,但新專案建議評估 ProxySQL 等現代化方案。

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