- 浏览: 640603 次
- 性别:
- 来自: 杭州
文章分类
最新评论
-
liuche20083736:
非常好
从问题看本质: 研究TCP close_wait的内幕 -
xiaopohai85707:
优化算法与原来需求不符
过滤字符的性能调优?挤一挤还是有的 -
kmy_白衣:
生成的area图有时候 标签的数值和图标上看上去的数值不一致。 ...
OpenFlashChart2之恶心文档 -
tom&jerry:
大神,请教一个问题,按名称排序为何无效,用的2.4.3 XPA ...
深入浅出jackrabbit之十三 查询之AST和QT -
jd2bs:
改成精确匹配可以了< filter-mapping &g ...
细谈Ehcache页面缓存的使用
/**
* 作者:张荣华
* 日期: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的官方使用教程:
这个示例看上去非常之简单,我们可以很容易的就通过ReplicationDriver拿到了一个Connection,首先,对于我们来说,conn.setReadOnly对我们来说这个方法应该是通过spring的事务管理来设置,同时这个conn对象应该不是一个真正的connection,而是一个代理类,通过设置readonly,代理类会去使用不同的connection,那么问题是它该代理类使用的connection是哪里取的,抑或说难道它每次都会新开一个connection?,这就需要看源代码
那么现在我们要弄清楚ReplicationDriver是怎么回事,反编译之后我们看到:
看来看去,这个类中没有什么东西,那么再看看NonRegisteringReplicationDriver类吧。如下面的代码所示,这个类中主要就是这个方法connect方法
上面这个方法也很简单,就是解析url后,然后访问确定master和slave机器一些properties的配置。越来越接近真相了,继续往下看,让我们掀起ReplicationConnection的头盖来:
先看构造方法:
这个构造方法没有任何的玄机,从这里也可以看出,那么前文提出的猜想是正确的,每一个ReplicationDriver其实是两个Connection的代理,这两个Connection才是真正访问DB的connection。好了,看到这里看客们大概也看出来了,当调用connection.setReadonly的时候,其实就是把需要的masterConnection或者slavesConnection赋值给当前的currentConnection,ReplicationDriver就是这么个实现,原理也非常简单,那么怎么解决文章中开头提出的那个问题呢。
第一种方案:
改成多个datasource,这种方式是最简单,最粗鲁的,然后我们就可以看到一堆有一堆,一坨又一坨的datasource,然后你还有一堆堆一坨坨的JdbcTemplate,HibernateTemplate,SqlMapClientTemplate,等等。
第二种方案:
第二种方案是所有的驱动都是用ReplicationDriver,有同学问:那怎么行呢,因为我又的datasource不是master-slave模式的。还好,没有什么关系,即使是这样配置jdbc:mysql://192.168.1.1:3306,192.168.1.1:3306/xx也是没有关系的,带来的结果就是一个ReplicationDriver其实hold了两个connection,而这两个connection其实是连着同一个数据库。那么也就是说如果连接池里配置了50个connection,那么实际上却有100个connection连着数据库,这种事情还是比较让人郁闷的。
第三种方案:
看来看去,问题都出现在DriverManager上,如果我新建一个DriverManager,行否,于是新建一个类,名约ReplicationDriverManager。这样系统中就有两个DriverManager了,普通的DriverManager注册的驱动为Driver.java,ReplicationDriverManager注册的驱动为ReplicationDriver。大家互不干扰,貌似可行。粗略的看了一下代码,也是可以实现的,关键在于需要扩展连接池(至少c3p0是这样的,需要重写c3p0的两个类),然后还需要重写一个ReplicationDriver,将静态块中的DriverManager换成我们自己的DriverManager。然后还需要重写ReplicationConnection,Driver类等等,也是非常麻烦的。
想来想去,想破了头了,终于,还是有点头绪,就是在第二种方案的基础上,再次修改ReplicationConnection,也就是说,如果我的配置为jdbc:mysql://192.168.1.1:3306/xx,那么我强行把currentConnection设置为masterConnection,这样ReplicationConnection中的slavesConnection就一直是空着的,或者masterConnection和slavesConnection还有currentConnection这3个引用都指向同一个对象,那么连接池中配置50个连接,那么就是50个连接,不会变成100个连接了,而其他的master-slave模式的配置依旧,这个方式貌似看上去还是不错的。我们看看代码怎么写:
首先,来一个EasyReplicationDriver,代码如下:
接着再来一个EasyNonRegisteringReplicationDriver,如下:
注意上面我注释掉的这段代码,如果我们想要ReplicationDriver支持jdbc:mysql://192.168.1.1:3306/xxx,那么就必须把上面那段代码注释掉。
第3步,让我们看看EasyReplicationConnection这个类:
主要就是加了一个判断,一旦路径中出现///,那么就证明没有slave机器,那么就可以把masterConnection赋值给slavesConnection了。这样一来就ok了。
经过3个类的改写之后,终于,我们可以使用ReplicationDriver的功能了,看来看去还是这种方式最美好。
不过由于ahuaxuan的水平所限,可能在以上的方案中有其没有发现的问题,抑或有更好的方案,希望大家不吝赐教。
master和salve的配置应该是没有问题的(抑或说master-slave模式有多种配置,或者说为了使用replication有什么特殊的master-slave配置?),为什么说它没有问题呢,因为我分datasource作的时候就是可以正常复制的,而且这个配置在线上已经跑了很长时间了,一直是没有问题的。
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创建的事务进行的提交
jdbc:mysql:replication://这个协议应该是MySQL的Driver自己扩展出来的,MySQL的文档里面不会有。
从源码上看,jdbc:mysql:replication://这个协议其实只是在MySQL默认的Driver上用协议的名称来进行不同策略的Connection获取,和用ReplicationDriver时底层获取Connection的代码是一样的。所以我也不认为是协议出了问题。
Robbin曾经说过:99%的性能问题,是配置和网络的问题。呵呵,建议从配置上下手去找问题。当然,还有网络问题。
这个是具体的错误信息:
14:31:41,713 WARN BasicResourcePool:1841 - com.mchange.v2.resourcepool.BasicResourcePool$AcquireTask@16fc6b62 -- Acquisition Attempt Failed!!! Clearing pending acquires. While trying to acquire a needed new resource, we failed to succeed more than the maximum number of allowed acquisition attempts (30). Last acquisition attempt exception:
java.sql.SQLException: Must specify at least one slave host to connect to for master/slave replication load-balancing functionality
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1056)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:957)
刚才downpour提出不需要使用ReplicationDriver,只需要指定不同的协议即可,我试了一下,过了
也就是说这样就可以了:
刚才试了一下,好像不行,我是这样做的,
jdbc:mysql:replication://192.168.1.1,192.168.1.1/xx
这个地址用Driver作为驱动
jdbc:mysql://192.168.1.2/xxx
这个地址也用Driver类作为驱动。
谢谢readonly大哥和downpour,我对你们非常的拜服啊
从上面这段代码中可以看出,如果协议使用的是"jdbc:mysql:replication://",还是回返回ReplicationConnection的,所以不需要再使用ReplicationDriver
刚才试了一下,好像不行,我是这样做的,
jdbc:mysql:replication://192.168.1.1,192.168.1.1/xx
这个地址用ReplicationDriver作为驱动
jdbc:mysql://192.168.1.2/xxx
这个地址用Driver类作为驱动。
没明白这段的意思,你有应用要访问N个数据库,但是其中只有一个数据库需要ReplicationDriver?
既然这样的话,给这个数据库定义的datasource设置driver class name为ReplicationDriver,而其他的都设置成普通的mysql driver不可以么?
我开始也是这样做的,但是后来发现问题了,因为一个DriverManager只能有一个ReplicationDriver驱动,不能在使用其他驱动了
它的文档写道:ReplicationDriver does not currently work with java.sql.DriverManager -based connection creation unless it is the only MySQL JDBC driver registered with the DriverManager .
所以我就没有办法了,才有了这个扩展
没明白这段的意思,你有应用要访问N个数据库,但是其中只有一个数据库需要ReplicationDriver?
既然这样的话,给这个数据库定义的datasource设置driver class name为ReplicationDriver,而其他的都设置成普通的mysql driver不可以么?
* 作者:张荣华
* 日期: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的官方使用教程:
public static void main(String[] args) throws Exception { ReplicationDriver driver = new ReplicationDriver(); Properties props = new Properties(); // We want this for failover on the slaves props.put("autoReconnect", "true"); // We want to load balance between the slaves props.put("roundRobinLoadBalance", "true"); props.put("user", "foo"); props.put("password", "bar"); // // Looks like a normal MySQL JDBC url, with a // comma-separated list of hosts, the first // being the 'master', the rest being any number // of slaves that the driver will load balance against // Connection conn = driver.connect("jdbc:mysql://master,slave1,slave2,slave3/test", props); // // Perform read/write work on the master // by setting the read-only flag to "false" // //这个节点应该是通过spring的事务管理来设置,同时这个conn对象应该不是一个真正的connection, //而是一个代理类,通过设置readonly,代理类会去使用不同的connection, //那么问题是它该代理类使用的connection是哪里取的,抑或说难道它每次都会新开一个connection?,需要看源代码 conn.setReadOnly(false); conn.setAutoCommit(false); conn.createStatement().executeUpdate("UPDATE some_table ...."); conn.commit(); // // Now, do a query from a slave, the driver automatically picks one // from the list // conn.setReadOnly(true); ResultSet rs = conn.createStatement().executeQuery("SELECT a,b FROM alt_table"); ....... }
这个示例看上去非常之简单,我们可以很容易的就通过ReplicationDriver拿到了一个Connection,首先,对于我们来说,conn.setReadOnly对我们来说这个方法应该是通过spring的事务管理来设置,同时这个conn对象应该不是一个真正的connection,而是一个代理类,通过设置readonly,代理类会去使用不同的connection,那么问题是它该代理类使用的connection是哪里取的,抑或说难道它每次都会新开一个connection?,这就需要看源代码
那么现在我们要弄清楚ReplicationDriver是怎么回事,反编译之后我们看到:
public ReplicationDriver() throws SQLException { } static { try { DriverManager.registerDriver(new NonRegisteringReplicationDriver()); } catch (SQLException E) { throw new RuntimeException("Can't register driver!"); } }
看来看去,这个类中没有什么东西,那么再看看NonRegisteringReplicationDriver类吧。如下面的代码所示,这个类中主要就是这个方法connect方法
public Connection connect(String url, Properties info) throws SQLException { Properties parsedProps = parseURL(url, info); if (parsedProps == null) { return null; } Properties masterProps = (Properties) parsedProps.clone(); Properties slavesProps = (Properties) parsedProps.clone(); slavesProps.setProperty("com.mysql.jdbc.ReplicationConnection.isSlave", "true"); String hostValues = parsedProps.getProperty("HOST"); if (hostValues != null) { StringTokenizer st = new StringTokenizer(hostValues, ","); StringBuffer masterHost = new StringBuffer(); StringBuffer slaveHosts = new StringBuffer(); if (st.hasMoreTokens()) { String hostPortPair[] = parseHostPortPair(st.nextToken()); if (hostPortPair[0] != null) { masterHost.append(hostPortPair[0]); } if (hostPortPair[1] != null) { masterHost.append(":"); masterHost.append(hostPortPair[1]); } } boolean firstSlaveHost = true; do { if (!st.hasMoreTokens()) { break; } String hostPortPair[] = parseHostPortPair(st.nextToken()); if (!firstSlaveHost) { slaveHosts.append(","); } else { firstSlaveHost = false; } if (hostPortPair[0] != null) { slaveHosts.append(hostPortPair[0]); } if (hostPortPair[1] != null) { slaveHosts.append(":"); slaveHosts.append(hostPortPair[1]); } } while (true); if (slaveHosts.length() == 0) { throw SQLError .createSQLException( "Must specify at least one slave host to connect to for master/slave replication " + "load-balancing functionality", "01S00"); } masterProps.setProperty("HOST", masterHost.toString()); slavesProps.setProperty("HOST", slaveHosts.toString()); } return new ReplicationConnection(masterProps, slavesProps); }
上面这个方法也很简单,就是解析url后,然后访问确定master和slave机器一些properties的配置。越来越接近真相了,继续往下看,让我们掀起ReplicationConnection的头盖来:
先看构造方法:
public ReplicationConnection(Properties masterProperties, Properties slaveProperties) throws SQLException { Driver driver = new Driver(); StringBuffer masterUrl = new StringBuffer("jdbc:mysql://"); StringBuffer slaveUrl = new StringBuffer("jdbc:mysql://"); String masterHost = masterProperties.getProperty("HOST"); if (masterHost != null) { masterUrl.append(masterHost); } String slaveHost = slaveProperties.getProperty("HOST"); if (slaveHost != null) { slaveUrl.append(slaveHost); } String masterDb = masterProperties.getProperty("DBNAME"); masterUrl.append("/"); if (masterDb != null) { masterUrl.append(masterDb); } String slaveDb = slaveProperties.getProperty("DBNAME"); slaveUrl.append("/"); if (slaveDb != null) { slaveUrl.append(slaveDb); } //从这里可以看出,笔者前文提出的猜想是正确的,每一个ReplicationDriver其实是两个Connection的代理,这两个 //Connection才是真正访问DB的connection。 masterConnection = (com.mysql.jdbc.Connection) driver.connect(masterUrl .toString(), masterProperties); slavesConnection = (com.mysql.jdbc.Connection) driver.connect(slaveUrl .toString(), slaveProperties); currentConnection = masterConnection; }
这个构造方法没有任何的玄机,从这里也可以看出,那么前文提出的猜想是正确的,每一个ReplicationDriver其实是两个Connection的代理,这两个Connection才是真正访问DB的connection。好了,看到这里看客们大概也看出来了,当调用connection.setReadonly的时候,其实就是把需要的masterConnection或者slavesConnection赋值给当前的currentConnection,ReplicationDriver就是这么个实现,原理也非常简单,那么怎么解决文章中开头提出的那个问题呢。
第一种方案:
改成多个datasource,这种方式是最简单,最粗鲁的,然后我们就可以看到一堆有一堆,一坨又一坨的datasource,然后你还有一堆堆一坨坨的JdbcTemplate,HibernateTemplate,SqlMapClientTemplate,等等。
第二种方案:
第二种方案是所有的驱动都是用ReplicationDriver,有同学问:那怎么行呢,因为我又的datasource不是master-slave模式的。还好,没有什么关系,即使是这样配置jdbc:mysql://192.168.1.1:3306,192.168.1.1:3306/xx也是没有关系的,带来的结果就是一个ReplicationDriver其实hold了两个connection,而这两个connection其实是连着同一个数据库。那么也就是说如果连接池里配置了50个connection,那么实际上却有100个connection连着数据库,这种事情还是比较让人郁闷的。
第三种方案:
看来看去,问题都出现在DriverManager上,如果我新建一个DriverManager,行否,于是新建一个类,名约ReplicationDriverManager。这样系统中就有两个DriverManager了,普通的DriverManager注册的驱动为Driver.java,ReplicationDriverManager注册的驱动为ReplicationDriver。大家互不干扰,貌似可行。粗略的看了一下代码,也是可以实现的,关键在于需要扩展连接池(至少c3p0是这样的,需要重写c3p0的两个类),然后还需要重写一个ReplicationDriver,将静态块中的DriverManager换成我们自己的DriverManager。然后还需要重写ReplicationConnection,Driver类等等,也是非常麻烦的。
想来想去,想破了头了,终于,还是有点头绪,就是在第二种方案的基础上,再次修改ReplicationConnection,也就是说,如果我的配置为jdbc:mysql://192.168.1.1:3306/xx,那么我强行把currentConnection设置为masterConnection,这样ReplicationConnection中的slavesConnection就一直是空着的,或者masterConnection和slavesConnection还有currentConnection这3个引用都指向同一个对象,那么连接池中配置50个连接,那么就是50个连接,不会变成100个连接了,而其他的master-slave模式的配置依旧,这个方式貌似看上去还是不错的。我们看看代码怎么写:
首先,来一个EasyReplicationDriver,代码如下:
public class EasyReplicationDriver extends EasyNonRegisteringReplicationDriver implements Driver { public EasyReplicationDriver() throws SQLException { } static { try { DriverManager.registerDriver(new EasyNonRegisteringReplicationDriver()); } catch (SQLException E) { throw new RuntimeException("Can't register driver!"); } } }
接着再来一个EasyNonRegisteringReplicationDriver,如下:
/** * @author ahuaxuan(aaron zhang) * @since 2008-6-18 * @version $Id$ */ public class EasyNonRegisteringReplicationDriver extends NonRegisteringDriver { public EasyNonRegisteringReplicationDriver() throws SQLException { } public Connection connect(String url, Properties info) throws SQLException { Properties parsedProps = parseURL(url, info); if (parsedProps == null) { return null; } Properties masterProps = (Properties) parsedProps.clone(); Properties slavesProps = (Properties) parsedProps.clone(); slavesProps.setProperty("com.mysql.jdbc.ReplicationConnection.isSlave", "true"); String hostValues = parsedProps.getProperty("HOST"); if (hostValues != null) { StringTokenizer st = new StringTokenizer(hostValues, ","); StringBuffer masterHost = new StringBuffer(); StringBuffer slaveHosts = new StringBuffer(); if (st.hasMoreTokens()) { String hostPortPair[] = parseHostPortPair(st.nextToken()); if (hostPortPair[0] != null) { masterHost.append(hostPortPair[0]); } if (hostPortPair[1] != null) { masterHost.append(":"); masterHost.append(hostPortPair[1]); } } boolean firstSlaveHost = true; do { if (!st.hasMoreTokens()) { break; } String hostPortPair[] = parseHostPortPair(st.nextToken()); if (!firstSlaveHost) { slaveHosts.append(","); } else { firstSlaveHost = false; } if (hostPortPair[0] != null) { slaveHosts.append(hostPortPair[0]); } if (hostPortPair[1] != null) { slaveHosts.append(":"); slaveHosts.append(hostPortPair[1]); } } while (true); /*if (slaveHosts.length() == 0) { throw SQLError .createSQLException( "Must specify at least one slave host to connect to for master/slave replication " + "load-balancing functionality", "01S00"); }*/ masterProps.setProperty("HOST", masterHost.toString()); slavesProps.setProperty("HOST", slaveHosts.toString()); } return new EasyReplicationConnection(masterProps, slavesProps); }
注意上面我注释掉的这段代码,如果我们想要ReplicationDriver支持jdbc:mysql://192.168.1.1:3306/xxx,那么就必须把上面那段代码注释掉。
第3步,让我们看看EasyReplicationConnection这个类:
public EasyReplicationConnection(Properties masterProperties, Properties slaveProperties) throws SQLException { Driver driver = new Driver(); StringBuffer masterUrl = new StringBuffer("jdbc:mysql://"); StringBuffer slaveUrl = new StringBuffer("jdbc:mysql://"); String masterHost = masterProperties.getProperty("HOST"); if (masterHost != null) { masterUrl.append(masterHost); } String slaveHost = slaveProperties.getProperty("HOST"); if (slaveHost != null) { slaveUrl.append(slaveHost); } String masterDb = masterProperties.getProperty("DBNAME"); masterUrl.append("/"); if (masterDb != null) { masterUrl.append(masterDb); } String slaveDb = slaveProperties.getProperty("DBNAME"); slaveUrl.append("/"); if (slaveDb != null) { slaveUrl.append(slaveDb); } //从这里可以看出,笔者前文提出的猜想是正确的,每一个ReplicationDriver其实是两个Connection的代理,这两个 //Connection才是真正访问DB的connection。 masterConnection = (com.mysql.jdbc.Connection) driver.connect(masterUrl .toString(), masterProperties); if (slaveUrl.toString().contains("///")) { if (logger.isDebugEnabled()) { logger.debug(" ----- the salveUrl contains the '///', " + "that means there is no slaver, make slavesConnection = masterConnection --"); } slavesConnection = masterConnection; } else { slavesConnection = (com.mysql.jdbc.Connection) driver.connect(slaveUrl .toString(), slaveProperties); }
主要就是加了一个判断,一旦路径中出现///,那么就证明没有slave机器,那么就可以把masterConnection赋值给slavesConnection了。这样一来就ok了。
经过3个类的改写之后,终于,我们可以使用ReplicationDriver的功能了,看来看去还是这种方式最美好。
不过由于ahuaxuan的水平所限,可能在以上的方案中有其没有发现的问题,抑或有更好的方案,希望大家不吝赐教。
- code.rar (3.5 KB)
- 描述: 代码
- 下载次数: 154
评论
12 楼
kakaluyi
2008-07-30
ahuaxuan大大,佩服你的钻研精神!学习了很多
如果不想同步的数据库可以用mysql底层的配置
修改my.ini可以吗,
#不复制某个库
replicate-ignore-db=dbname
url就直接jdbc:mysql://192.168.1.1:3306/这样类型的就行吧
如果不想同步的数据库可以用mysql底层的配置
修改my.ini可以吗,
#不复制某个库
replicate-ignore-db=dbname
url就直接jdbc:mysql://192.168.1.1:3306/这样类型的就行吧
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/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创建的事务进行的提交
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://的时候,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%的性能问题,是配置和网络的问题。呵呵,建议从配置上下手去找问题。当然,还有网络问题。
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的日志和配置吧。
偶之前使用master/slave机制很顺利,唯一遇到的bug就是它的round robin策略有点异常,不过这个bug很快就被修正了,而且国内外使用mysql master/slave的成功案例也非常多,jdbc:mysql:replication协议和ReplicationDriver其实用的是相同的代码,你说的cpu 90%,偶怀疑和复制有关系,建议你先去检查master/slave的日志和配置吧。
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://这个协议,不知所措啊
还有一个情况,使用jdbc:mysql:replication://的时候,slave机器负载非常高,都到90%了,不使用replication的时候只写master,负载只有30%。
看来这个jdbc:mysql:replication://还有些问题,需要详细的测试才行,不能贸然的用到生产环境中去
这可能意味者还是要修改代码才行。估计还是得用主贴中重写ReplicationDriver的方式才行。
或者说我的用法还是不对,我暂时也想不起来哪里会出问题,一个小小的connection会让一个很牛叉的db服务器负载达到90-100%。
而且我在mysql的文档上怎么也查不到jdbc:mysql:replication://这个协议,不知所措啊
7 楼
ahuaxuan
2008-06-20
Readonly 写道
偶只用过单纯的ReplicationDriver,不过从源代码看jdbc:mysql:replication://这样是可用的,你遇到具体出错信息是啥?
这个是具体的错误信息:
14:31:41,713 WARN BasicResourcePool:1841 - com.mchange.v2.resourcepool.BasicResourcePool$AcquireTask@16fc6b62 -- Acquisition Attempt Failed!!! Clearing pending acquires. While trying to acquire a needed new resource, we failed to succeed more than the maximum number of allowed acquisition attempts (30). Last acquisition attempt exception:
java.sql.SQLException: Must specify at least one slave host to connect to for master/slave replication load-balancing functionality
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1056)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:957)
刚才downpour提出不需要使用ReplicationDriver,只需要指定不同的协议即可,我试了一下,过了
也就是说这样就可以了:
引用
刚才试了一下,好像不行,我是这样做的,
jdbc:mysql:replication://192.168.1.1,192.168.1.1/xx
这个地址用Driver作为驱动
jdbc:mysql://192.168.1.2/xxx
这个地址也用Driver类作为驱动。
谢谢readonly大哥和downpour,我对你们非常的拜服啊
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
6 楼
Readonly
2008-06-20
偶只用过单纯的ReplicationDriver,不过从源代码看jdbc:mysql:replication://这样是可用的,你遇到具体出错信息是啥?
5 楼
ahuaxuan
2008-06-20
Readonly 写道
明白你的意思了,因为这2个driver都用一样的url协议头jdbc:mysql://,所以就不能一起注册了。
对于你这种情况,你可用普通的driver class name,用不同的协议头:
1. jdbc:mysql:replication://
2. jdbc:mysql://
对于你这种情况,你可用普通的driver class name,用不同的协议头:
1. jdbc:mysql:replication://
2. jdbc:mysql://
刚才试了一下,好像不行,我是这样做的,
jdbc:mysql:replication://192.168.1.1,192.168.1.1/xx
这个地址用ReplicationDriver作为驱动
jdbc:mysql://192.168.1.2/xxx
这个地址用Driver类作为驱动。
4 楼
Readonly
2008-06-20
明白你的意思了,因为这2个driver都用一样的url协议头jdbc:mysql://,所以就不能一起注册了。
对于你这种情况,你可用普通的driver class name,用不同的协议头:
1. jdbc:mysql:replication://
2. jdbc:mysql://
对于你这种情况,你可用普通的driver class name,用不同的协议头:
1. jdbc:mysql:replication://
2. jdbc:mysql://
3 楼
downpour
2008-06-20
实践出真知,看来很多东西不去实践是不清楚的。
2 楼
ahuaxuan
2008-06-20
Readonly 写道
ahuaxuan 写道
我准备把它用于生产环境中,但是问题来了,因为我的应用访问的数据库有多个,主要访问的库是master-slave模式,其他辅助库是就是指定的一台机器,这时候问题来了。
没明白这段的意思,你有应用要访问N个数据库,但是其中只有一个数据库需要ReplicationDriver?
既然这样的话,给这个数据库定义的datasource设置driver class name为ReplicationDriver,而其他的都设置成普通的mysql driver不可以么?
我开始也是这样做的,但是后来发现问题了,因为一个DriverManager只能有一个ReplicationDriver驱动,不能在使用其他驱动了
它的文档写道:ReplicationDriver does not currently work with java.sql.DriverManager -based connection creation unless it is the only MySQL JDBC driver registered with the DriverManager .
所以我就没有办法了,才有了这个扩展
1 楼
Readonly
2008-06-20
ahuaxuan 写道
我准备把它用于生产环境中,但是问题来了,因为我的应用访问的数据库有多个,主要访问的库是master-slave模式,其他辅助库是就是指定的一台机器,这时候问题来了。
没明白这段的意思,你有应用要访问N个数据库,但是其中只有一个数据库需要ReplicationDriver?
既然这样的话,给这个数据库定义的datasource设置driver class name为ReplicationDriver,而其他的都设置成普通的mysql driver不可以么?
发表评论
-
过滤字符的性能调优?挤一挤还是有的
2010-05-29 05:54 3616/* *auth ... -
Master-Slave,Spring,Hibernate,故事曲折离奇,情结跌宕起伏
2009-02-05 13:49 8704/** *作者:张荣华 *日期 ... -
弃成见,反省,并重新认识struts.i18n.encoding
2008-12-24 15:42 3899[size=medium]之前和大家讨论了struts2.0中 ... -
关键字:查询,事务,粒度
2008-08-22 17:05 5146[size=medium]/** *作者: ... -
看看mina和memcached的联姻(适合不同语言客户端,高并发?)
2008-07-21 17:06 7996[size=medium]/** * 作者:张荣华 * 日 ... -
别装了,难道你们不想把properties直接注入到object中去(spring-plugin)?
2008-04-09 18:01 3661[size=small]/** *作者:张荣华(ahuaxu ... -
用jamon来监控你的sql执行效率
2008-02-25 15:48 3720/** *作者:张荣华 *日期:2008-2-25 ... -
java同msn的通信,大家想想用途吧
2007-11-24 17:14 2519程序员的生活真是单调,除了编程还是编程,工作日 ... -
EAI企业应用集成场景及解决方案
2007-09-21 18:21 3161/** *作者:张荣华(ahuaxuan) *2007-9 ... -
quartz和应用的集群问题
2007-08-21 18:36 12829之前看到很多关于quartz的讨论,尤其是关于quar ... -
优化程序之前,可用Jamon来监测你的Spring应用
2007-08-14 18:14 8147/** *作者:张荣华(ahuaxuan) *2007-8-1 ... -
请问责任链真的是一种设计模式吗
2007-07-26 18:12 9440坛子上讨论设计模式的也挺多的,但是关于这个责任链模式还没有人提 ... -
把ActiveMQ的控制台整合到你的web程序中
2007-07-19 12:06 8854在使用ActiveMQ的时候把ActiveMQ的控制台整 ... -
设计模式之:解剖观察者模式
2007-07-17 16:12 6870[size=9] 论坛上很多人都 ... -
java邮件:在简单和复杂之间的方案
2007-07-11 18:07 7587/** *作者:张荣华(ahuaxu ... -
强强连手, 在模板中分页,看Freemarker和displaytag的结合
2007-07-09 09:22 6931/** *作者:张荣华(ahuaxuan) *2007-0 ... -
解惑:在spring+hibernate中,只读事务是如何被优化的。
2007-06-28 18:22 7624/** *作者:张荣华(ahuaxuan) *2007- ... -
让webwork零配置 第二章(实现)(实例已放出,大家可以下载运行)
2007-06-25 09:23 5714/** *作者:张荣华(ahuaxuan) *2007-0 ... -
让webwork2零配置,第一章(主贴再次更新)
2007-06-18 15:41 13399/** *作者:张荣华(ahuaxuan) *2007-0 ... -
Spring声明式事务管理源码解读之事务提交
2007-06-11 09:19 7288/** *作者:张荣华(ahuaxuan) *2007-0 ...
相关推荐
在MySQL数据库系统中,主从复制(Master-Slave Replication)是一种常用的数据冗余和负载均衡策略。这种模式允许数据从一个主服务器(Master)实时同步到一个或多个从服务器(Slave)。当主服务器上的数据发生变化时...
在分布式系统中,为了确保数据的高可用性和容错性,MongoDB提供了两种复制模式:master-slave(主从模式)和master-master(主主模式)。本实验将深入探讨这两种模式的工作原理、设置方法以及它们在实际应用中的优...
标题中的"Modbus-Master-Slave-for-Arduino-master.zip_Master/Slave_arduino"指出这是一个关于Arduino平台的Modbus主从通信库。Modbus是一种广泛使用的工业通信协议,允许不同设备之间交换数据,尤其在自动化系统中...
在`sharding-master-slave`项目中,我们将看到如何将`Sharding-JDBC`与`SpringBoot`相结合,以实现数据的高效管理和访问。 1. **分库分表策略** `Sharding-JDBC`支持自定义分片策略,这在`描述`中提到。通常,分片...
在Java并发编程中,Master-Slave模式是一种常见的多线程处理策略,它借鉴了“分而治之”的思想,将一个大任务分解为多个小任务,分配给多个工作线程(Slave)执行,由一个主控线程(Master)协调管理。这种模式在...
ActiveMQ Master-Slave集群是一种高可用性和容错性的解决方案,确保即使主节点(Master Broker)发生故障,消息也不会丢失,因为它们已经被复制到从节点(Slave Broker)。这种配置是ActiveMQ推荐的策略之一,提供了...
5. **启动复制**:在从服务器上,使用`START SLAVE`命令启动复制进程。此时,从服务器将开始读取主服务器的binlog并执行相应的SQL语句。 二、主从复制工作原理 1. **写操作**:在主服务器上,任何数据修改都会被...
在JDBC Master Slave模式中,Master Broker和Slave Broker都尝试获取数据库的锁,成功获取的Broker将成为Master,而未能获取的则作为Slave。这种配置通常要求Master和Slave部署在不同的服务器上,以提高容错能力。在...
在企业级开发中,主从关系(Master-Slave)是一种常见的架构模式,广泛应用于数据库复制、分布式系统、任务调度等多个领域。这种模式的核心在于,一个主节点(Master)负责处理请求、执行关键操作或决策制定,而一个...
Master-Slave的数据库机构解决了很多问题,特别是read/write比较高的web2.0应用: 1、写操作全部在Master结点执行,并由Slave数据库结点定时(默认60s)读取Master的bin-log 2、将众多的用户读请求分散到更多的...
MySQL的Master-Slave架构是一种常见的数据库高可用性和负载均衡解决方案。它允许数据从一个主服务器(Master)实时同步到一个或多个从服务器(Slave)。在这种架构中,所有的写操作都在主服务器上执行,而从服务器则...
第1步 master-slave1和slave2配置网络和搭建Hadoop集群环境.docx
此资源为shardingsphere 调研...内容:一个master mysql docker实例,一个slave docker实例 内置3个库,mydb,mydb0,mydb1。仅开启了这三个库的主从。如果三个库主从不够用,自行配置。 使用:1.解压 2.执行build.sh
"Master-_-Slave-Core"标题暗示了这是一个关于I2C主从核心的项目,其中包含了一套用于实现I2C主从模式的代码。 I2C协议是由飞利浦(现NXP半导体)在1980年代初设计的,它允许在一个总线上连接多个设备,减少了所需...
1. **安装库**:首先,需要将解压后的"Modbus-Master-Slave-for-Arduino-master"文件夹放入Arduino IDE的库文件夹中,重启IDE后,即可在“Sketch”->"Include Library"菜单中看到Modbus的相关选项。 2. **配置主...
3. **主从配置**:在主节点的 `activemq.xml` 中配置 master-slave 组件,包括 slave URL 和其他相关参数。同时,确保 slave 节点的配置文件指向主节点。 ### 启动与验证 1. **启动 MQ**:先启动 master,然后启动...
《FreeModbus_Slave-Master-RTT-STM32-master_stm32mastermodbus_stm32:深入理解MODBUS通信在STM32中的应用》 MODBUS通信协议,作为工业自动化领域的标准通信协议,因其简单、开放、易实现的特点,在嵌入式系统...
MySQL数据库复制Master-Slave架构是一种常见的数据库高可用性和扩展性的解决方案。在这一架构中,数据库被分为一个主服务器(Master)和一个或多个从服务器(Slave)。主服务器接收并处理所有的写操作,如INSERT、...
MySQL的主主复制(Master-Master Replication)是一种高可用性解决方案,它允许两个或多个数据库服务器互相复制数据,形成一个集群。在这种模式下,每个节点既是主节点,也是从节点,可以接受读写操作。当一个节点...
"Master-slave-alarm-system"是一个基于主从模式的分布式系统,由主设备(Master)和多个从设备(Slave)组成。主设备负责协调和监控所有从设备,而从设备则负责采集温度数据并向主设备报告。这种架构允许系统扩展至...