在动手操作前最好先安装好MySQL-Proxy,并配置好MySQL主从服务器。补充:新版MySQL已经内建支持

延迟问题

读写分离不能回避的问题之一就是延迟,可以考虑Google提供的SemiSyncReplicationDesign补丁。

端口问题

MySQL-Proxy缺省使用的是4040端口,如果你想透明的把3306端口的请求转发给4040的话,那么可以:

iptables -t nat -I PREROUTING -s ! 127.0.0.1 -p tcp --dport 3306 -j REDIRECT --to-ports 4040

如果想删除这条规则,可以把上面例子中的-I换成-D。

参考链接

密码加密方式

MySQL-Proxy不支持老的密码加密方式,所以如果你使用的是老版本的MySQL,或者启用了old_passwords选项的话,则可能会出现错误:

ERROR 2013: Lost connection to MySQL server

此时最好的修复方法就是使用新的密码加密方式,如果你的用户表是老式的,可能需要先运行MySQL源代码里scripts目录下的mysql_fix_privilege_tables脚本升级表结构。有时候客观情况可能不允许立刻进行升级操作,此时可以为MySQL-Proxy专门建立一个密码为空的用户(通过主机限制访问,或者起一个很复杂的用户名),因为不管是新的密码加密方式还是旧的密码加密方式,空密码都同样是一个空字符串,这样就规避了密码加密的问题。

查询乱码

连接上MySQL-Proxy后,执行查询时,随机出现乱码。出现此问题的原因是当我们使用MySQL-Proxy读写分离时,通常会有多个后端服务器,客户端发出查询请求时,一般会先发出一条类似"SET NAME gbk"的语句来声明客户端编码,然后再发出实际查询的SQL语句,但MySQL-Proxy可能会把这两条语句分发给不同的后端服务器,于是就出现了乱码。

解决方法是强行指定后端服务器的字符编码:

init-connect='SET NAME gbk'
skip-character-set-client-handshake  忽略客户端字符集

如果使用init-connect,则需要注意操作用户不能有SUPER权限,否则此选项无效。

即便做好了以上的设置后,还有可能会出现乱码,比如说数据库是gbk的,当我们用PHPMyAdmin连接MySQL-Proxy时,查询还是会出现乱码,不过这是正常的!因为PHPMyAdmin使用的是utf8编码,它发出的“SET NAMES utf8”语句被skip-character-set-client-handshake屏蔽了,所以出现乱码。

进程崩溃

MySQL-Proxy偶尔会出现进程崩溃的情况,具体原因不明。

新版的MySQL-Proxy为了应付这个问题加入了一个keepalive选项(try to restart the proxy if it crashed),当使用这个选项时,会先后启动两个mysql-proxy进程,先启动的mysql-proxy进程用来监控后启动的mysql-proxy进程,实际提供服务的是后启动的mysql-proxy进程,一旦后启动的mysql-proxy进程挂掉(你可以自己kill试试),先启动的mysql-proxy进程会重新启动一个mysql-proxy提供服务。

不过现在很多人用的还是旧版的MySQL-Proxy,此时可以利用init来实现类似keepalive的效果:

编写脚本/usr/local/sbin/mysql-proxy.sh,加入以下内容(具体写法视安装情况而定):

LUA_PATH="/usr/local/mysql-proxy/share/mysql-proxy/?.lua" \
/usr/local/mysql-proxy/sbin/mysql-proxy \
--proxy-backend-addresses=192.168.0.1:3306 \
--proxy-read-only-backend-addresses=192.168.0.2:3306 \
--proxy-lua-script=/usr/local/mysql-proxy/share/mysql-proxy/rw-splitting.lua

别忘了加上可执行属性:

chmod a+x /usr/local/sbin/mysql-proxy.sh

0.7.0版本有一个新的选项:--defaults-file,可以把相关信息都写到配置文件里:

# MySQL Proxy's configuration file (mysql-proxy.cnf)

[mysql-proxy]
daemon = true
keepalive = true
proxy-backend-addresses = 192.168.0.1:3306
proxy-read-only-backend-addresses = 192.168.0.2:3306
proxy-lua-script = /usr/local/mysql-proxy/share/mysql-proxy/rw-splitting.lua

启动时可以使用:mysql-proxy --defaults-file=mysql-proxy.cnf

修改inittab:

vi /etc/inittab

加入以下内容:

mp:12345:respawn:/usr/local/sbin/mysql-proxy.sh

然后让init重新读取inittab内容:

kill -HUP 1

系统会自动检测/usr/local/sbin/mysql-proxy.sh是否正在运行,如果没有就自动运行。

需要注意的是在编写mysql-proxy.sh脚本的时候,不要加入--daemon选项,否则/usr/local/sbin/mysql-proxy.sh一运行就结束了,系统会不停的尝试运行脚本,从而在/var/log/message里留下大量的错误信息(init: Id "mp" respawning too fast: disabled for 5 minutes)。

init的方法可能显得有点另类了,可以使用其他的工具,比如svscan

有状态的查询

一些有状态的特殊的查询可能失效,比如说:

SELECT SQL_CALC_FOUND_ROWS ..
SELECT FOUND_ROWS()

这种查询是有状态的,应该保证在同一个后端处理,查看rw-splitting.lua脚本可以看到MySQL-Proxy实际上已经对这样的查询进行了 判断,但在实际应用中发现还是存在问题。估计是脚本写得不咋地,实际应用中,建议大家不要使用这样的查询,一来没有可移植性,而来效率也不见得好。

另一个可能会产生问题的查询是:

INSERT ... (AUTO_INCREMENT)
SELECT LAST_INSERT_ID()

当系统执行完INSERT后,再执行SELECT时,可能已经被分发到了不同的后端服务器,如果你使用的编程语言是PHP的话,此时应该通过 mysql_insert_id()来得到最新插入的id,每次INSERT结束后,其实对应的autoincrement值就已经计算好返回给PHP 了,你无需再发出一次独立的查询,直接用mysql_insert_id()就可以了。不过很多PHP程序使用的都是SELECT LAST_INSERT_ID()的方式,如AdbDB,CakePHP等等,如果你正在使用它们的话需多加小心。(当使用bigint 时,mysql_insert_id()存在问题,详情见手册,不过对于大多数人而言,bigint基本不会遇到,所以你可以无视这个问题)

注:对于这两个问题,官方BUG库里有人给出了相应的补丁

脚本问题

MySQL-Proxy读写分离的功能是通过lua脚本(rw-splitting.lua)实现的,但是这个脚本年久失修,问题多多,比如说使用时可能会出现:

ERROR 1105: can't change DB to on slave

出现这个问题的原因在于当客户端发出查询时,MySQL-Proxy会比较当前客户端所处数据库和服务器所处数据库是否一致,如果不一致则会在服务端尝试执行一个"USE 数据库"的操作,一个可能性是主从服务器的数据库结构不同,在USE一个不存在的数据库的时候自然会出错,还有一个原因有些查询操作并没有所处数据库这个上下文,比如说SHOW DATABASES这个查询,并不需要事先“USE 数据库”,只要连上服务器就可以执行,这时候如果还尝试同步客户端和服务端所处的数据库,出错就是无法避免的事了。

rw-splitting.lua恰恰没有屏蔽后者所描述的情况,修复方法如下,在合适的位置加入粗体代码,

276         if cmd.type ~= proxy.COM_INIT_DB and
277            c.default_db and c.default_db ~= "" and c.default_db ~= s.default_db then
if is_debug
278                    print("    server default db: " .. s.default_db)
279                    print("    client default db: " .. c.default_db)
280                    print("    syncronizing")
end
281                 proxy.queries:prepend(2, string.char(proxy.COM_INIT_DB) .. c.default_db)
282         end

在lua中,~=是不等于的意思,另外,lua里空字符串""用在if里被认为是true,所以单靠c.default_db不够。

顺手加上is_debug的判断,不然即使不是debug状态,服务器的命令行里也会偶尔冒出一些调试信息。

此外,新版MySQL-Proxy里,虽然源代码包里有rw-splitting.lua脚本,但缺省并没有安装,你需要手动拷贝,而且数据结构发生了变化,脚本需要按照数据结构的变化做出适当的修改,可以参考作者的描述操作,或者参考官方Bug管理或者直接下载。值得期待的是现在有了专门的MySQL-Proxy-Lua-Scripts项目,希望开发进度能跟上来。

使用MySQL-Proxy读写分离时的注意事项的更多相关文章

  1. Linux MySQL Proxy 读写分离

    导读 因为读写分离是建立在MySQL集群主从复制的基础上,还不了解的,先看我另一篇博客:点我直达 MySQL-Proxy简介 mysql-proxy是mysql官方提供的mysql中间件服务,上游可接 ...

  2. MySQL ProxySQL读写分离实践

    目的 在上一篇文章MySQL ProxySQL读写分离使用初探里初步介绍了ProxySQL的使用,本文继续介绍它的一些特点和DBProxy的性能差异.深入一些去了解ProxySQL,通过测试来说明Pr ...

  3. MySQL Router实现MySQL的读写分离

    1.简介 MySQL Router是MySQL官方提供的一个轻量级MySQL中间件,用于取代以前老版本的SQL proxy. 既然MySQL Router是一个数据库的中间件,那么MySQL Rout ...

  4. MySQL的读写分离的几种选择

    MySQL的读写分离的几种选择 MySQL主从复制(Master-Slave)与读写分离(MySQL-Proxy)实践 原址如下: http://heylinux.com/archives/1004. ...

  5. MySQL/MariaDB读写分离配置

    DB读写分离描述 数据库的读写分离其实就是为了加减少数据库的压力:数据库的写入操作由主数据库来进行,读取操作由从数据库来进行操作.实现数据库读写分离技术是有很多方法的,在这里我就用一个比较简单的mys ...

  6. 使用mysql-proxy实现mysql的读写分离

     前言: MySQL读写分离是指让master处理写操作,让slave处理读操作,非常适用于读操作量比较大的场景,可减轻master的压力.使用mysql-proxy实现mysql的读写分离,mysq ...

  7. 实现mysql的读写分离(mysql-proxy)____2

    mysql-proxy简介 MySQL读写分离是指让master处理写操作,让slave处理读操作,非常适用于读操作量比较大的场景,可减轻master的压力. 使用mysql-proxy实现mysql ...

  8. Amoeba搞定mysql主从读写分离

    前言:一直想找一个工具,能很好的实现mysql主从的读写分离架构,曾经试用过mysql-proxy发现lua用起来很不爽,尤其是不懂lua脚本,突然发现了Amoeba这个项目,试用了下,感觉还不错,写 ...

  9. Centos7源码安装mysql及读写分离,互为主从

       Linux服务器 -源码安装mysql 及读写分离,互为主从   一.环境介绍: Linux版本: CentOS 7 64位 mysq版本: mysql-5.6.26 这是我安装时所使用的版本, ...

随机推荐

  1. python yield from 语法

    python yield from 语法 yield语法比较简单, 教程也很多 , yield from的中文讲解很少 , python官网是这样解释的 PEP 380 adds the yield ...

  2. Excel文件按照指定模板导入数据(用jxl.jar包)

        本文中的方法只适合Excel2003,要读取Excel2007最好使用poi.jar,据说poi.jar还在更新,jxl.jar已经不更新了,处理Excel文件的读写问题最好还是学习poi.j ...

  3. OpenCV 之 网络摄像头

     1  RTSP RTSP (Real Time Streaming Protocol),是一种语法和操作类似 HTTP 协议,专门用于音频和视频的应用层协议. 和 HTTP 类似,RTSP 也使用 ...

  4. 【前端】用jQuery实现瀑布流效果

    jQuery实现瀑布流效果 何为瀑布流: 瀑布流,又称瀑布流式布局.是比较流行的一种网站页面布局,视觉表现为参差不齐的多栏布局,随着页面滚动条向下滚动,这种布局还会不断加载数据块并附加至当前尾部.最早 ...

  5. Java纸牌小demo以及日历小demo

    //卡牌类 public class Card { //定义卡牌的点数 public static final String[] cardName = { "3", "4 ...

  6. HDU 1698 Just a Hook(线段树成段更新)

    题目网址:http://acm.hdu.edu.cn/showproblem.php?pid=1698 题目: Problem Description   In the game of DotA, P ...

  7. MySQL oracle 分页

    (1)MySql的Limit m,n语句 Limit后的两个参数中,参数m是起始下标,它从0开始:参数n是返回的记录数.我们需要分页的话指定这两个值即可. 比如:查询10行记录,起始行从3开始 SEL ...

  8. docker~大叔对术语的解释

    回到目录 接触和使用docker已经有1年多了,起初对概念本身理解的不是很好,或者说,没有找到一本比较好的书,在自己的研究下,对docker一些基本的概念有了自己的一些认识和看法,现在分享给正在学习d ...

  9. Week 1 # A A + B Problem II

    原题描述: A - A + B Problem II I have a very simple problem for you. Given two integers A and B, your jo ...

  10. (转)xml

    1  XML理论回顾 1.1 XML概述 1.XML是可扩展标记语言.是由W3C指定并维护的,目前最新的版本是1.0 2.XML作用: 2.1传输数据,它是一种通用的数据交换格式 2.2配置文件. 1 ...