Mysql服务器和客户端建立连接过程如下

认证通过,客户端发起查询请求,服务器可能返回3种结果;


图片来源http://blog.sina.com.cn/s/blog_98cb2d960100zs0e.html

Mysql-proxy作为一个代理,工作于mysql客户端和服务器之间(对两者皆透明)


http://dev.mysql.com/doc/mysql-proxy/en/mysql-proxy-scripting-injection.html

 

首先MySQL Proxy以服务器的身份接受客户端请求,根据配置对这些请求进行分析处理,然后以客户端的身份转发给相应的后端数据库服务器,再接受服务器的信息,返回给客户端,所以MySQL Proxy
要同时实现客户端和服务器的协议。

由于要对客户端发送过来的SQL语句进行分析,还需要包含一个SQL解析器。可以说MySQL Proxy相当于一个轻量级的MySQL了,实际上,MySQL Proxyadmin server是可以接受SQL来查询状态信息的。


MySQL Proxy通过lua脚本来控制连接转发,主要的函数都是配合MySQL Protocol各个过程的:

    * connect_server()     // 接收到Client的连接请求时调用

    * read_handshake()   // 读取server发起的handshake信息时调用

    * read_auth()               // 读取Client的认证信息时调用

    * read_auth_result() // 读取认证结果时调用

    * read_query()            // 读取Clientquery请求时调用

  * read_query_result()   //读取query结果时调用



具体功能

   1.数据连接的故障转移

   2.数据连接的负载均衡

   3.拦截查询(取通信包,实现关键字替换)

   4.重写查询(例如,强制密码度等规则)

   5.添加额外的查询(附)

   6.删除,修改或者添加返回到客户端的 SQL结果集



配置文件

mysql-proxy.cnf(权限设为660)

 [mysql-proxy]

    admin-username=root

    admin-password=123456

    admin-lua-script=/usr/local/lib/admin.lua

    proxy-read-only-backend-addresses=192.168.2.115

    proxy-backend-addresses=192.168.2.117

    proxy-lua-script=/usr/local/lib/rw-splitting.lua

    log-file=/var/log/mysql-proxy.log

    log-level=debug

    daemon=true

keepalive=true

proxy-lua-script,指定一个Lua脚本来控制mysql-proxy的运行和设置,这个脚本在每次新建连接和脚本发生修改的的时候将重新调用

keepalive,额外建立一个进程专门监控mysql_proxy进程,当mysql_proxy crash予以重新启动;


启动

/usr/local/mysql-proxy/bin/mysql-proxy -P 192.168.2.112:3306 --defaults-file=/etc/mysql-proxy.cnf



读写分离

proxy-lua-script指定为rw-splitting.lua时,mysql_proxy会对客户端传入的sql执行读写分离;

同一个事务,DML传输给backendselect则被传到read-only-backend

Lua脚本默认最小4个最大8个以上的客户端连接才会实现读写分离(这是因为mysql-proxy会检测客户端连接当连接没有超过min_idle_connections预设值时,不会进行读写分离,即查询操作会发生到Master上),现改为最小1个最大2个,我们用vim修改/usr/local/lib/rw-splitting.lua脚本,改动内容如下所示:

    if not proxy.global.config.rwsplit then

            proxy.global.config.rwsplit = {

                    min_idle_connections = 1,

                    max_idle_connections = 2,

   

                    is_debug = false

            }

    end

 

read_query()函数内有这么一个判断

if stmt.token_name == "TK_SQL_SELECT" then 

这个语句的作用就是判断sql语句是不是以SELECT开始的,如果是查询的话,接下来会有这么个语句

local backend_ndx = lb.idle_ro() 

lb.idle_ro() 是通过 local lb = require("proxy.balance") 引入的balance.lua文件

这个函数的作用就是选择使用哪个读服务器,并返回服务器的index:max_conns_ndx

如何选择服务器呢? 它通过循环遍历所有服务器,然后选出一个客户端连接(s.connected_clients)最少的服务器,这样在一定程度上实现负载均衡

    function idle_ro()  

        local max_conns = -1 

        local max_conns_ndx = 0 

     

        for i = 1, #proxy.global.backends do 

            local s = proxy.global.backends[i] 

            local conns = s.pool.users[proxy.connection.client.username] 

            -- pick a slave which has some idling connections 

            if s.type == proxy.BACKEND_TYPE_RO and s.state ~= proxy.BACKEND_STATE_DOWN and conns.cur_idle_connections > 0 then 

                if max_conns == -1 or s.connected_clients < max_conns then 

                    max_conns = s.connected_clients 

                    max_conns_ndx = i 

                end 

            end

        end 

     

        return max_conns_ndx 

    end

http://blog.csdn.net/clh604/article/details/8906022




failover

利用mysql_proxy实现failover

缺点:mysql_proxy单点故障;

原理:默认连接A,如果A宕掉则连接BA启动后再连接到A

编写failover脚本

vi $mysql-proxy_path/share/doc/mysql-proxy/mysql_failover.lua

function connect_server()

    for i = 1, #proxy.backends do

        local s = proxy.backends[i]

        print ("s.state:" + s.state)

        if s.state ~= proxy.BACKEND_STATE_DOWN then

            proxy.connection.backend_ndx = i

            print ("connecting to " .. i)

            return

        end

    end

end

function read_query(packet)

    for i = 1, #proxy.backends do

        local s = proxy.backends[i]

        print ("s.state:" + s.state)

        if s.state ~= proxy.BACKEND_STATE_DOWN then

            proxy.connection.backend_ndx = i

            print ("connecting to " .. i)

            return

        end

    end

end

启动mysql-proxy

$mysql-proxy_path/bin/mysql-proxy --proxy-address=:4040 --proxy-lua-script=$mysql-proxy_path/share/doc/mysql-proxy/mysql_failover.lua --proxy-backend-addresses=$A:3306 --proxy-backend-addresses=$B:3306 --log-level=error  --log-file=$mysql-proxy_path/mysql-proxy.log --keepalive --proxy-fix-bug-25371

此时客户端直接连接mysql-proxy即可;

http://www.cnblogs.com/lenolix/archive/2013/04/06/3003226.html