如何解决mysql的master-slave模式中ReplicationDriver的使用问题
/**
* 作者:张荣华
* 日期:2008-6-19
**/
前言:
之前downpour有一个贴(http://www.iteye.com/topic/143714)讨论了在java中如何使用mysql的master-slave模式(master-slave模式的介绍见Qieqie的这个贴:http://www.iteye.com/topic/162717),其中readonly大大提到我们可以使用ReplicationDriver来从connection层把read或者write操作分开。这确实是一个比较好的方案,在那个帖子讨论后不久,我就在自己的机器上搭了一个mysql的master-slave模式,然后使用ReplicationDriver来控制读写访问不同的机器,测试通过了,事隔几个月之后,我准备把它用于生产环境中,但是问题来了,因为我的应用访问的数据库有多个,主要访问的库是master-slave模式,其他辅助库是就是指定的一台机器,这时候问题来了。
Mysql的文档是这么写的:ReplicationDriver does not currently work with java.sql.DriverManager -based connection creation unless it is the only MySQL JDBC driver registered with the DriverManager . DriverManager是一个单例模式,一个DriverManager只能注册一个ReplicationDriver驱动,也就是说ReplicationDriver和Driver两个类不能同时使用,郁闷,及其郁闷,由于我之前没有仔细看这段说明,所以没有预料到这种情况。摆在前面的路有几条
一,使用多个datasource解决问题,
二,所有得datasource都使用这个驱动,但是这样做有一个缺点,在文章后面我会详细阐述这种做法得缺点。
三,扩展再扩展,hack再hack。
四,这种方案是第二种方案的补充,详见后文。
首先,我们来看一下ReplicationDriver的官方使用教程:
主要就是加了一个判断,一旦路径中出现///,那么就证明没有slave机器,那么就可以把masterConnection赋值给slavesConnection了。这样一来就ok了。
经过3个类的改写之后,终于,我们可以使用ReplicationDriver的功能了,看来看去还是这种方式最美好。
不过由于ahuaxuan的水平所限,可能在以上的方案中有其没有发现的问题,抑或有更好的方案,希望大家不吝赐教。
public Connection connect(String url, Properties info) throws SQLException { Properties props; if(url != null) { if(StringUtils.startsWithIgnoreCase(url, "jdbc:mysql:loadbalance://")) { return connectLoadBalanced(url, info); } if(StringUtils.startsWithIgnoreCase(url, "jdbc:mysql:replication://")) { return connectReplicationConnection(url, info); } } props = null; if((props = parseURL(url, info)) == null) { return null; } com.mysql.jdbc.Connection newConn = ConnectionImpl.getInstance(host(props), port(props), props, database(props), url); return newConn; SQLException sqlEx; sqlEx; throw sqlEx; Exception ex; ex; throw SQLError.createSQLException(Messages.getString("NonRegisteringDriver.17") + ex.toString() + Messages.getString("NonRegisteringDriver.18"), "08001"); }
从上面这段代码中可以看出,如果协议使用的是"jdbc:mysql:replication://",还是回返回ReplicationConnection的,所以不需要再使用ReplicationDriver 8 楼 ahuaxuan 2008-07-02 在实际环境中,使用jdbc:mysql:replication://有一些问题,在小数据量的情况时没有问题,但是在大的批量任务的时候发现,master中的数据并不能复制到slave机器上,数据正常的插入了master,但是却没有复制slave
还有一个情况,使用jdbc:mysql:replication://的时候,slave机器负载非常高,都到90%了,不使用replication的时候只写master,负载只有30%。
看来这个jdbc:mysql:replication://还有些问题,需要详细的测试才行,不能贸然的用到生产环境中去
这可能意味者还是要修改代码才行。估计还是得用主贴中重写ReplicationDriver的方式才行。
或者说我的用法还是不对,我暂时也想不起来哪里会出问题,一个小小的connection会让一个很牛叉的db服务器负载达到90-100%。
而且我在mysql的文档上怎么也查不到jdbc:mysql:replication://这个协议,不知所措啊
9 楼 Readonly 2008-07-07 master/slave的复制机制和jdbc driver无关,是靠服务器之间通讯来处理的,你应该从master的log入手,看看是否有任何replication error
偶之前使用master/slave机制很顺利,唯一遇到的bug就是它的round robin策略有点异常,不过这个bug很快就被修正了,而且国内外使用mysql master/slave的成功案例也非常多,jdbc:mysql:replication协议和ReplicationDriver其实用的是相同的代码,你说的cpu 90%,偶怀疑和复制有关系,建议你先去检查master/slave的日志和配置吧。 10 楼 downpour 2008-07-07 ahuaxuan 写道在实际环境中,使用jdbc:mysql:replication://有一些问题,在小数据量的情况时没有问题,但是在大的批量任务的时候发现,master中的数据并不能复制到slave机器上,数据正常的插入了master,但是却没有复制slave
还有一个情况,使用jdbc:mysql:replication://的时候,slave机器负载非常高,都到90%了,不使用replication的时候只写master,负载只有30%。
看来这个jdbc:mysql:replication://还有些问题,需要详细的测试才行,不能贸然的用到生产环境中去
这可能意味者还是要修改代码才行。估计还是得用主贴中重写ReplicationDriver的方式才行。
或者说我的用法还是不对,我暂时也想不起来哪里会出问题,一个小小的connection会让一个很牛叉的db服务器负载达到90-100%。
而且我在mysql的文档上怎么也查不到jdbc:mysql:replication://这个协议,不知所措啊
jdbc:mysql:replication://这个协议应该是MySQL的Driver自己扩展出来的,MySQL的文档里面不会有。
从源码上看,jdbc:mysql:replication://这个协议其实只是在MySQL默认的Driver上用协议的名称来进行不同策略的Connection获取,和用ReplicationDriver时底层获取Connection的代码是一样的。所以我也不认为是协议出了问题。
Robbin曾经说过:99%的性能问题,是配置和网络的问题。呵呵,建议从配置上下手去找问题。当然,还有网络问题。 11 楼 ahuaxuan 2008-07-07 Readonly 写道master/slave的复制机制和jdbc driver无关,是靠服务器之间通讯来处理的,你应该从master的log入手,看看是否有任何replication error
偶之前使用master/slave机制很顺利,唯一遇到的bug就是它的round robin策略有点异常,不过这个bug很快就被修正了,而且国内外使用mysql master/slave的成功案例也非常多,jdbc:mysql:replication协议和ReplicationDriver其实用的是相同的代码,你说的cpu 90%,偶怀疑和复制有关系,建议你先去检查master/slave的日志和配置吧。
master和salve的配置应该是没有问题的(抑或说master-slave模式有多种配置,或者说为了使用replication有什么特殊的master-slave配置?),为什么说它没有问题呢,因为我分datasource作的时候就是可以正常复制的,而且这个配置在线上已经跑了很长时间了,一直是没有问题的。
downpour 写道
jdbc:mysql:replication://这个协议应该是MySQL的Driver自己扩展出来的,MySQL的文档里面不会有。
从源码上看,jdbc:mysql:replication://这个协议其实只是在MySQL默认的Driver上用协议的名称来进行不同策略的Connection获取,和用ReplicationDriver时底层获取Connection的代码是一样的。所以我也不认为是协议出了问题。
Robbin曾经说过:99%的性能问题,是配置和网络的问题。呵呵,建议从配置上下手去找问题。当然,还有网络问题。
总的来说,我也认为协议应该是没有问题的,因为从代码上看其实就是一个普通的connection,上周我想到一个问题,就是可能在使用的过程中可能有问题,问题如下:
如果事务开始之前设置readonly,那么首先使用的connection应该是slaveconnection,那么也就是说,开始事务的connection是slaveconnection,在事务中connection被设置了非readonly,那么也就是说执行操作的connection就变成了masterconnection,最后事务提交的时候还是slaveconnection创建的事务进行的提交
12 楼 kakaluyi 2008-07-30 ahuaxuan大大,佩服你的钻研精神!学习了很多
如果不想同步的数据库可以用mysql底层的配置
修改my.ini可以吗,
#不复制某个库
replicate-ignore-db=dbname
url就直接jdbc:mysql://192.168.1.1:3306/这样类型的就行吧