【15.7.5.1. Using the Administration Interface】
mysql-proxy 的 administration 接口可以通过任何 MySQL 客户端按照标准协议进行访问。你可以通过 administration 接口获取 proxy 服务器的整体信息 - 向 proxy 建立的标准连接是处于隔离状态的,其模拟了直接连接到后端 MySQL 服务器的情形。
在 mysql-proxy 0.8.0 或者更早的版本中,一组最基本的接口已被添加到 proxy 中。在后续版本中,这种方式已被替换,你必须要使用的 administration 脚本以连接到 administration 接口。
为了使用 administration 接口,需要通过 --admin-username 和 --admin-password 选项指定连接 admin 服务器所需的用户名和密码。同样必须通过 admin-lua-script 脚本选项指定提供访问 administration 服务所需接口的 Lua 脚本。
例如,你可以使用下面的脚本创建一个访问 mysql-proxy 系统内部组件基本接口,由 Diego Medina 提供:
--[[
Copyright 2008, 2010, Oracle and/or its affiliates. All rights reserved.
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
--]]
-- admin.lua
--[[
See http://www.chriscalender.com/?p=41
(Thanks to Chris Calender)
See http://datacharmer.blogspot.com/2009/01/mysql-proxy-is-back.html
(Thanks Giuseppe Maxia)
--]]
function set_error(errmsg)
proxy.response = {
type = proxy.MYSQLD_PACKET_ERR,
errmsg = errmsg or "error"
}
end
function read_query(packet)
if packet:byte() ~= proxy.COM_QUERY then
set_error("[admin] we only handle text-based queries (COM_QUERY)")
return proxy.PROXY_SEND_RESULT
end
local query = packet:sub(2)
local rows = { }
local fields = { }
-- try to match the string up to the first non-alphanum
local f_s, f_e, command = string.find(packet, "^%s*(%w+)", 2)
local option
if f_e then
-- if that match, take the next sub-string as option
f_s, f_e, option = string.find(packet, "^%s+(%w+)", f_e + 1)
end
-- we got our commands, execute it
if command == "show" and option == "querycounter" then
---
-- proxy.PROXY_SEND_RESULT requires
--
-- proxy.response.type to be either
-- * proxy.MYSQLD_PACKET_OK or
-- * proxy.MYSQLD_PACKET_ERR
--
-- for proxy.MYSQLD_PACKET_OK you need a resultset
-- * fields
-- * rows
--
-- for proxy.MYSQLD_PACKET_ERR
-- * errmsg
proxy.response.type = proxy.MYSQLD_PACKET_OK
proxy.response.resultset = {
fields = {
{ type = proxy.MYSQL_TYPE_LONG, name = "query_counter", },
},
rows = {
{ proxy.global.query_counter }
}
}
-- we have our result, send it back
return proxy.PROXY_SEND_RESULT
elseif command == "show" and option == "myerror" then
proxy.response.type = proxy.MYSQLD_PACKET_ERR
proxy.response.errmsg = "my first error"
return proxy.PROXY_SEND_RESULT
elseif string.sub(packet, 2):lower() == 'select help' then
return show_process_help()
elseif string.sub(packet, 2):lower() == 'show proxy processlist' then
return show_process_table()
elseif query == "SELECT * FROM backends" then
fields = {
{ name = "backend_ndx",
type = proxy.MYSQL_TYPE_LONG },
{ name = "address",
type = proxy.MYSQL_TYPE_STRING },
{ name = "state",
type = proxy.MYSQL_TYPE_STRING },
{ name = "type",
type = proxy.MYSQL_TYPE_STRING },
}
for i = 1, #proxy.global.backends do
local b = proxy.global.backends[i]
rows[#rows + 1] = {
i, b.dst.name, b.state, b.type
}
end
else
set_error()
return proxy.PROXY_SEND_RESULT
end
proxy.response = {
type = proxy.MYSQLD_PACKET_OK,
resultset = {
fields = fields,
rows = rows
}
}
return proxy.PROXY_SEND_RESULT
end
function make_dataset (header, dataset)
proxy.response.type = proxy.MYSQLD_PACKET_OK
proxy.response.resultset = {
fields = {},
rows = {}
}
for i,v in pairs (header) do
table.insert(proxy.response.resultset.fields, {type = proxy.MYSQL_TYPE_STRING, name = v})
end
for i,v in pairs (dataset) do
table.insert(proxy.response.resultset.rows, v )
end
return proxy.PROXY_SEND_RESULT
end
function show_process_table()
local dataset = {}
local header = { 'Id', 'IP Address', 'Time' }
local rows = {}
for t_i, t_v in pairs (proxy.global.process) do
for s_i, s_v in pairs ( t_v ) do
table.insert(rows, { t_i, s_v.ip, os.date('%c',s_v.ts) })
end
end
return make_dataset(header,rows)
end
function show_process_help()
local dataset = {}
local header = { 'command', 'description' }
local rows = {
{'SELECT HELP', 'This command.'},
{'SHOW PROXY PROCESSLIST', 'Show all connections and their true IP Address.'},
}
return make_dataset(header,rows)
end
function dump_process_table()
proxy.global.initialize_process_table()
print('current contents of process table')
for t_i, t_v in pairs (proxy.global.process) do
print ('session id: ', t_i)
for s_i, s_v in pairs ( t_v ) do
print ( '\t', s_i, s_v.ip, s_v.ts )
end
end
print ('---END PROCESS TABLE---')
end
--[[ Help
we use a simple string-match to split commands are word-boundaries
mysql> show querycounter
is split into
command = "show"
option = "querycounter"
spaces are ignored, the case has to be as is.
mysql> show myerror
returns a error-packet
--]]
上述脚本需要配合下面的 proxy 脚本一起使用,名字为 reporter.lua :
--[[
Copyright 2008, 2010, Oracle and/or its affiliates. All rights reserved.
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
--]]
-- reporter.lua
--[[
See http://www.chriscalender.com/?p=41
(Thanks to Chris Calender)
See http://datacharmer.blogspot.com/2009/01/mysql-proxy-is-back.html
(Thanks Giuseppe Maxia)
--]]
proxy.global.query_counter = proxy.global.query_counter or 0
function proxy.global.initialize_process_table()
if proxy.global.process == nil then
proxy.global.process = {}
end
if proxy.global.process[proxy.connection.server.thread_id] == nil then
proxy.global.process[proxy.connection.server.thread_id] = {}
end
end
function read_auth_result( auth )
local state = auth.packet:byte()
if state == proxy.MYSQLD_PACKET_OK then
proxy.global.initialize_process_table()
table.insert( proxy.global.process[proxy.connection.server.thread_id],
{ ip = proxy.connection.client.src.name, ts = os.time() } )
end
end
function disconnect_client()
local connection_id = proxy.connection.server.thread_id
if connection_id then
-- client has disconnected, set this to nil
proxy.global.process[connection_id] = nil
end
end
---
-- read_query() can return a resultset
--
-- You can use read_query() to return a result-set.
--
-- @param packet the mysql-packet sent by the client
--
-- @return
-- * nothing to pass on the packet as is,
-- * proxy.PROXY_SEND_QUERY to send the queries from the proxy.queries queue
-- * proxy.PROXY_SEND_RESULT to send your own result-set
--
function read_query( packet )
-- a new query came in in this connection
-- using proxy.global.* to make it available to the admin plugin
proxy.global.query_counter = proxy.global.query_counter + 1
end
为了使用上述脚本,首先需要将第一个脚本保存为文件(在下面的例子中文件名为 admin.lua ),第二个命名为 reporter.lua ,然后通过命令指定 mysql-proxy 执行的 admin 脚本和后端 MySQL 服务器:
shell> mysql-proxy --admin-lua-script=admin.lua --admin-password=password \ »
--admin-username=root --proxy-backend-addresses=127.0.0.1:3306 -proxy-lua-script=reporter.lua
在另外一个窗口中,通过 proxy 连接 MySQL 服务器:
shell> mysql --user=root --password=password --port=4040
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 1798669
Server version: 5.0.70-log Gentoo Linux mysql-5.0.70-r1
Type 'help;' or '\h' for help. Type '\c' to clear the buffer.
mysql>
在第三个窗口中,使用指定的用户名和密码连接 mysql-proxy 的 admin 服务:
shell> mysql --user=root --password=password --port=4041 --host=localhost
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 1
Server version: 5.0.99-agent-admin
Type 'help;' or '\h' for help. Type '\c' to clear the buffer.
mysql>
为了监视 proxy 的状态信息,可以请求当前活动进行的列表信息:
mysql> show proxy processlist;
+---------+---------------------+--------------------------+
| Id | IP Address | Time |
+---------+---------------------+--------------------------+
| 1798669 | 192.168.0.112:52592 | Wed Jan 20 16:58:00 2010 |
+---------+---------------------+--------------------------+
1 row in set (0.00 sec)
mysql>