一年前听Hiro说过MySQL Proxy这个应用,直到现在才来了兴致鼓弄鼓弄,也是因为来到这边后,有生产环境一直在用mysql-proxy实现应用的读写分离,前辈搭好的架构现在好好学习下。也就是从昨天开始,亲自搭建了这个环境,学习学习。下面就说说我的测试环境以及遇到的很多晕来晕去的问题。
先简单说下什么是MySQL Proxy。从名字上就清晰可见代理嘛,就是在你能直接进行操作前,都要经过这个代理或是agent(国外片里的特工),client-agent-server就是这么一个过程,既然mysql-proxy加在客户端和服务端之间,那么它就必须要能听懂双方说的是什么,它的角色就像一名接线员(operator)。我们都知道mysql client和mysqld通信时,采用的是MySQL自己的网络协议,而MySQL Proxy也同样使用的是这个网络协议,那么三者之间也就没有什么障碍了。除了可以按照策略分发请求,既然放在两者中间,那么所有过来的请求它自然都可以截获,如果你愿意当然还可以做操作前的审核,也可注入些新的东西。Agent嘛,无所不能,不过你需要先对Lua无所不能LoL。
实验环境:
CentOS 5.4 + mysql-proxy-0.8.1-linux-glibc2.3-x86-64bit.tar.gz + mysql-5.0.77
192.168.109.5 (mysql-proxy) — 在前端,做读写分离(proxy和主库在一台机器上);
192.168.109.5 (master) + 192.168.109.6 (slave) — 主从同步(测试读写是否分离是,关闭同步,便于我们观察分离情况)
具体实施:
mysql-proxy -admin-lua-script=/usr/local/mysql-proxy/admin.lua -admin-username=root -admin-password=pass -proxy-address=192.168.109.5:4040 -proxy-backend-addresses=192.168.109.5:3306 -proxy-read-only-backend-addresses=192.168.109.6:3306 -proxy-lua-script=/usr/local/mysql-proxy/rw-splitting.lua -proxy-lua-script=/usr/local/mysql-proxy/reporter.lua -daemon > /tmp/mysql-proxy-err.log
NOTE: mysql-proxy二进制包解压好就能用了,但是需要注意的是一些lib和libexec的路径,即便你-plugin-dir,-lua-path,-basedir都用了执行上面的语句还是会告诉你不是libmysql-chassis.so.0、libadmin.so发现不了,就是commands.so,commands.lua,proxy.so这些找不到。你看下源码包下的./configure -help,就会知道mysql-proxy的相关默认路径(/usr/local/bin, /usr/local/lib),所以,解压后把目录下对应的文件/文件夹copy到这些目录下就不会在有那些犯人的error了。
Lua Scripts: admin.lua和reporter.lua这两个Lua脚本就可以使用mysql-proxy提供的Admin Plugin的功能,对请求进行统计同时还可以显示各种状态;rw-splitting.lua这个脚本就是我们用来做读写分离的,它里面还有两个可以调整的参数分别是:min_idle_connections,max_idle_connections,测试中发现,mysql-proxy与mysqld建立的是长连接,如果你不去主动断开连接,该线程会一直空置在那里,那么这两个命令就可以很好的控制空闲线程的数量,减少资源的浪费。
Admin Plugin 测试:
打开一个客户端,通过mysql-proxy的管理端口(4041),登录到mysql-proxy上,便可以执行Proxy的一些管理语句。
1. shell> mysql -uroot -ppass -P4041 -h192.168.109.5
2. mysql> show querycounter;
+——————-+
| query_counter |
+——————-+
| 2 |
+——————-+
Note: 这个语句显示的数字是一个累加值,默认一开始是NULL,由这么几部分组成:当你通过mysql连接proxy时会被+1,当你每执行一次sql语句时会被+1,当你quit断开连接时会被+1。
3. mysql> show proxy processlist;
+——+——————————+————————————+
| Id | IP Address | Time |
+——+——————————+————————————+
| 14 | 192.168.115.9:48611 | Wed Nov 10 10:17:58 2010 |
| 15 | 192.168.115.10:47626 | Wed Nov 10 10:18:24 2010 |
+——+——————————+————————————+
Note: 这个语句的输出结果,可以告诉我们当前的请求都来自哪里是什么时候连过来的,和Mysql的show processlist效果一样,只不过信息不是那么丰富。有时候执行这个语句会报错误,别太在意,当有请求连接过来以后,你再次执行,就正常了,不知道什么原因。
4. mysql> SELECT * FROM backends;
+—————-+————————-+——-+——+
| backend_ndx | address | state | type |
+—————-+————————-+——-+——+
| 1 | 192.168.109.5:3306 | 1 | 1 |
| 2 | 192.168.109.6:3306 | 0 | 2 |
+—————-+————————-+——-+——+
Note: 这个sql语句,还是蛮不错的,告诉我们proxy后端当前代理了哪些DB Server;type这个字段有两个值,1表示该数据库是主库,2表示该数据库是从库;state字段提示DB处于一个什么状态,0表示当前没有请求处于空闲,1表示已经有客户端发起过请求了,即便你断开客端后,这个值还是1,2表示mysqld的服务被停掉了。
5. 还有一个sql可以执行,打开admi.lua你会看到有一个help,就是下面的,告诉你可以执行的语句有谁。
mysql> select help;
+————————————+———————————————————-+
| command | description |
+————————————+———————————————————-+
| SELECT HELP | This command. |
| SHOW PROXY PROCESSLIST | Show all connections and their true IP Address. |
+———————————-+———————————————————-+
NOTE: 当reporter.lua和rw-splitting.lua一起被设置时,show querycounter;与show proxy processlist; 执行失败没有结果输出。
读写分离遇到的问题:
通过mysql-proxy的4040端连接进来,无论我执行写的操作还是查询的操作,所有的请求都会被发到主库(192.168.109.5)上,也就是-proxy-backend-addresses指定的主机。还发现上面启动的mysql-proxy,也不会对多了连接请求进行轮询分配,就是盯着那个192.168.109.5的主机一个来-_-!!!…郁啦。如果将上面的启动项中-proxy-read-only-backend-addresses也改为-proxy-backend-addresses,那么就可以对请求做轮询处理了,不过这样的话,客服端的请求就也会在从库进行写入操作,不允许的。
终于有了新的发现,就在此刻为了这个纠结的问题,我又再一次的仔细看了一下线上前辈配置的启动项,发现和我的有区别呀,没有配置主库的-proxy-backend-addresses,只有-proxy-read-only-backend-addresses配置的4个从库的ip。我调整后,还是不行呀!!!!奇怪的是,4040连接过来后,mysql-proxy直接就与主库建立了连接,不应该呀,还没有发送具体的操作请求怎么就,擅自决定呢,霸道!?苍天呀。。。有谁能拯救下我呀。。。都第二天啦
troubleshooting…….helping…….
——UPDATED——
2010-11-10 17:20 —MySQL Proxy终于弄明白了,问题解决了,谢谢坐在我旁边东软的哥们,还有MSN群里Dong兄的提示。分析如下:
其实,之前的启动选项是没有问题的,问题的关键在于rw-splitting.lua脚本中的min_idle_connections,max_idle_connections,这两个参数的默认设置最小是4,最大是8,而恰恰之前我测试的时候开启的客户端只有3个,所以,每次连接进来,select看到的总是主库上的记录,proxy会将预先建好的连接连到主库上,如果你连接的请求数小于这个默认值,那么是不会进行读写分离的,只有当请求数大于这个默认值时才会将读的请求发给从库去读,因为proxy会通过read_query()这个函数将新建立连接,按照我们之前启动项中的规则重定向,写到proxy-backend-addresses,读到proxy-read-only-backend-addresses。
此外,当我们使用rw-splitting.lua这个脚本启动,proxy-backend-addresses是读写均可,proxy-read-only-backend-addresses是只读;否则如果光设置后者,也均支持读写。
@打完,收工!
您好,请问为什么我链接4041端口后运行任何命令都报错呢?
ERROR 2006 (HY000): MySQL server has gone away
No connection. Trying to reconnect…
Connection id: 1
Current database: *** NONE ***
ERROR 1105 (07000): need a resultset + proxy.PROXY_SEND_RESULT