一個支援主從,事務以及連線池功能的mysql-proxy指令碼
看了點例子,根據mysql-proxy裡的keepalive例子修改了一個支援主從分離,事務到主庫,非事務查詢到從庫,以及連線斷開時自動回滾的指令碼,分享一下。
- --[[ $%BEGINLICENSE%$
- Copyright (C) 2007-2008 MySQL AB, 2008 Sun Microsystems, Inc
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; version 2 of the License.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- $%ENDLICENSE%$ --]]
- --[[
- --]]
- ---
- -- a flexible statement based load balancer with connection pooling
- --
- -- * build a connection pool of min_idle_connections for each backend and
- -- maintain its size
- -- * reusing a server-side connection when it is idling
- --
- --- config
- --
- -- connection pool
- local min_idle_connections = 4
- local max_idle_connections = 8
- -- debug
- local is_debug = true
- --- end of config
- ---
- -- read/write splitting sends all non-transactional SELECTs to the slaves
- --
- -- is_in_transaction tracks the state of the transactions
- local is_in_transaction = 0
- ---
- -- get a connection to a backend
- --
- -- as long as we don't have enough connections in the pool, create new connections
- --
- function connect_server()
- -- make sure that we connect to each backend at least ones to
- -- keep the connections to the servers alive
- --
- -- on read_query we can switch the backends again to another backend
- if is_debug then
- print()
- print("[connect_server] ")
- end
- local least_idle_conns_ndx = 0
- local least_idle_conns = 0
- for i = 1, #proxy.global.backends do
- local s = proxy.global.backends[i]
- local pool = s.pool
- -- we don't have a username yet, try to find a connections which is idling
- local cur_idle = pool.users[""].cur_idle_connections
- if cur_idle == nil then
- cur_idle = 0
- end
- if is_debug then
- print(" [".. i .."].connected_clients = " .. s.connected_clients)
- print(" [".. i .."].idling_connections = " .. cur_idle)
- print(" [".. i .."].type = " .. s.type)
- print(" [".. i .."].state = " .. s.state)
- end
- if s.state ~= proxy.BACKEND_STATE_DOWN then
- -- try to connect to each backend once at least
- if cur_idle == 0 then
- proxy.connection.backend_ndx = i
- if is_debug then
- print(" [".. i .."] open new connection")
- end
- return
- end
- -- try to open at least min_idle_connections
- if least_idle_conns_ndx == 0 or
- ( cur_idle
- cur_idle
- least_idle_conns_ndx = i
- least_idle_conns = s.idling_connections
- if least_idle_conns == nil then
- least_idle_conns = 0
- end
- end
- end
- end
- if least_idle_conns_ndx > 0 then
- proxy.connection.backend_ndx = least_idle_conns_ndx
- end
- if proxy.connection.backend_ndx > 0 then
- local s = proxy.global.backends[proxy.connection.backend_ndx]
- local pool = s.pool -- we don't have a username yet, try to find a connections which is idling
- local cur_idle = pool.users[""].cur_idle_connections
- if cur_idle >= min_idle_connections then
- -- we have 4 idling connections in the pool, that's good enough
- if is_debug then
- print(" using pooled connection from: " .. proxy.connection.backend_ndx)
- end
- return proxy.PROXY_IGNORE_RESULT
- end
- end
- if is_debug then
- print(" opening new connection on: " .. proxy.connection.backend_ndx)
- end
- -- open a new connection
- end
- ---
- -- put the successfully authed connection into the connection pool
- --
- -- @param auth the context information for the auth
- --
- -- auth.packet is the packet
- function read_auth_result( auth )
- if auth.packet:byte() == proxy.MYSQLD_PACKET_OK then
- -- auth was fine, disconnect from the server
- proxy.connection.backend_ndx = 0
- elseif auth.packet:byte() == proxy.MYSQLD_PACKET_EOF then
- -- we received either a
- --
- -- * MYSQLD_PACKET_ERR and the auth failed or
- -- * MYSQLD_PACKET_EOF which means a OLD PASSWORD (4.0) was sent
- print("(read_auth_result) ... not ok yet");
- elseif auth.packet:byte() == proxy.MYSQLD_PACKET_ERR then
- -- auth failed
- end
- end
- ---
- -- read/write splitting
- function read_query( packet )
- if is_debug then
- print("[read_query]")
- print(" authed backend = " .. proxy.connection.backend_ndx)
- print(" used db = " .. proxy.connection.client.default_db)
- end
- if packet:byte() == proxy.COM_QUIT then
- -- don't send COM_QUIT to the backend. We manage the connection
- -- in all aspects.
- proxy.response = {
- type = proxy.MYSQLD_PACKET_OK,
- }
- if is_in_transaction then
- print(" transaction on, rollback now")
- proxy.queries.append(1, string:char(proxy.COM_QUERY) .. "ROLLBACK", { resultset_is_needed = false})
- end
- return proxy.PROXY_SEND_RESULT
- end
- if proxy.connection.backend_ndx == 0 then
- if is_debug then
- print(" no connection, select now")
- end
- is_master = true
- if packet:byte() == proxy.COM_QUERY then
- command = packet:sub(2, 7)
- print(" command:" .. command)
- if string.lower(command) == "select" then
- print(" session not in transaction, select go to slave")
- is_master = false
- end
- end
- -- we don't have a backend right now
- --
- -- let's pick a master as a good default
- for i = 1, #proxy.global.backends do
- local s = proxy.global.backends[i]
- local pool = s.pool
- -- we don't have a username yet, try to find a connections which is idling
- local cur_idle = pool.users[proxy.connection.client.username].cur_idle_connections
- if cur_idle > 0 and s.state ~= proxy.BACKEND_STATE_DOWN then
- if s.type == proxy.BACKEND_TYPE_RW and is_master == true then
- proxy.connection.backend_ndx = i
- break
- elseif s.type == proxy.BACKEND_TYPE_RO and is_master == false then
- proxy.connection.backend_ndx = i
- break
- end
- end
- end
- end
- if is_debug then
- print(" connection:" .. proxy.connection.backend_ndx)
- end
- if true or proxy.connection.client.default_db and
- proxy.connection.client.default_db ~= proxy.connection.server.default_db then
- -- sync the client-side default_db with the server-side default_db
- proxy.queries:append(2, string.char(proxy.COM_INIT_DB) .. proxy.connection.client.default_db,
- { resultset_is_needed = true })
- end
- proxy.queries:append(1, packet, { resultset_is_needed = true })
- return proxy.PROXY_SEND_QUERY
- end
- ---
- -- as long as we are in a transaction keep the connection
- -- otherwise release it so another client can use it
- function read_query_result( inj )
- local res = assert(inj.resultset)
- local flags = res.flags
- if inj.id ~= 1 then
-
-- ignore the result of the USE
- return proxy.PROXY_IGNORE_RESULT
- end
- is_in_transaction = flags.in_trans
- if not is_in_transaction then
- -- release the backend
- proxy.connection.backend_ndx = 0
- end
- end
- ---
- -- close the connections if we have enough connections in the pool
- --
- -- @return nil - close connection
- -- IGNORE_RESULT - store connection in the pool
- function disconnect_client()
- if is_debug then
- print("[disconnect_client]")
- end
- if proxy.connection.backend_ndx == 0 then
- -- currently we don't have a server backend assigned
- --
- -- pick a server which has too many idling connections and close one
- for i = 1, #proxy.global.backends do
- local s = proxy.global.backends[i]
- local pool = s.pool
- -- we don't have a username yet, try to find a connections which is idling
- local cur_idle = pool.users[proxy.connection.client.username].cur_idle_connections
- if s.state ~= proxy.BACKEND_STATE_DOWN and
- cur_idle > max_idle_connections then
- -- try to disconnect a backend
- proxy.connection.backend_ndx = i
- if is_debug then
- print(" [".. i .."] closing connection, idling: " .. cur_idle)
- end
- return
- end
- end
- end
- end
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/90618/viewspace-775782/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- JavaWEB開發13——事務與連線池JavaWeb
- 設計一個可靠的連線池
- 轉:MySQL主從、字典死鎖、連線數的Python監控指令碼MySqlPython指令碼
- 實現一個redis連線池Redis
- 使Domino支援連線池技術
- 從原始碼分析DBCP資料庫連線池的原理原始碼資料庫
- 一個資料庫連線池的問題資料庫
- JDBC、JDBC框架、資料庫事務、資料庫連線池JDBC框架資料庫
- 理解資料庫連線池和ThreadLocal實現的事務控制資料庫thread
- 資料庫事務以及事務的四個特性資料庫
- 【JDBC】java連線池模擬測試連線Oracle資料庫指令碼參考JDBCJavaOracle資料庫指令碼
- Go語言之從0到1實現一個簡單的Redis連線池GoRedis
- 執行緒池、連線池、物件池從0到1執行緒物件
- 使用FlexyPool度量你的XA事務連線池合適大小 - Vlad MihalceaFlex
- 第77節:Java中的事務和資料庫連線池和DBUtilesJava資料庫
- ServiceStack.Redis的原始碼分析(連線與連線池)Redis原始碼
- 一文講透 Redis 事務 (事務模式 VS Lua 指令碼)Redis模式指令碼
- web服務中連線池用法Web
- 自己實現一個資料庫連線池資料庫
- Gopusher 一個通用的長連線服務Go
- 連線池
- JavaWeb之事務&資料庫連線池JavaWeb資料庫
- 《四 資料庫連線池原始碼》手寫資料庫連線池資料庫原始碼
- 資料庫連線池-Druid資料庫連線池原始碼解析資料庫UI原始碼
- 為vert x框架新增druid連線池支援框架UI
- 問個jrun連線池的問題
- 一個不錯的JDBC連線池教程(帶具體例子)JDBC
- spring 簡單的使用 Hikari連線池 和 jdbc連線mysql 的一個簡單例子SpringJDBCMySql單例
- MOSN 原始碼解析 - 連線池原始碼
- Hikari連線池原始碼解讀原始碼
- 從原始碼中分析關於phpredis中的連線池可持有數目原始碼PHPRedis
- 【SQL】長事務診斷指令碼SQL指令碼
- Redis篇:事務和lua指令碼的使用Redis指令碼
- JDBC,SQL隱碼攻擊,事務,C3P0與Druid連線池(最詳細解析)JDBCSQLUI
- Go連線池Go
- HTTP連線池HTTP
- django連線池Django
- 記錄阿里巴巴連線池DruidDataSource的一個bug阿里UI