这部分描述了Mysql-JDBC对于replication协议的一系列特性的支持。
mysql-jdbc-replication初始化于创建连接URL阶段,和通常的jdbc URL类似,但也有些特殊性:
jdbc:mysql:replication://[master host][:port],[slave host 1][:port][,[slave host 2][:port]]...[/[database]] »
[?propertyName1=propertyValue1[&propertyName2=propertyValue2]...]
用户需要指定allowMasterDownConnections=true 来允许即便没有主库,也能创建连接对象。这些连接对象是只读的,调用 isMasterConnection()将返回false,这些连接当Connection.setReadOnly(false)被调用时,会测试主节点的可用性,如果到主节点不可用,将抛出一个SQLException,如果可用,则会在主节点执行操作。
对于mysql-jdbc 5.1.38 和更久之后,用户需要具体指定allowSlavesDownConnections=true,来允许即便没有从库,也能创建连接对象。一个连接,那时候,在运行时,在Connection.setReadOnly(true)时,将测试连接的可用性,如果到从节点不可达(包括readFromMasterWhenNoSlaves=true时,主节点也不可达),将抛出SQLException。
mysql-jdbc 3.1.7和更高的版本,包括一系列的驱动来分发请求到读/写节点,提供failover的保障,和基于Connection.getReadOnly()实现的从节点负载均衡。
一个应用如果想通过Connection.setReadOnly(true)开启一个只读事务,驱动知道了应用要使用其中一个从节点,会随机取一个。在一个事务中,所有操作会附着在一个连接上,知道这个事务提交或者回滚,或这个从节点被服务移除。在mysql-jdbc 5.1.38和更久之后,在调用Connection.setReadOnly(true),如果没有从库可用时,你想让连接打到主节点那么你需要设置readFromMasterWhenNoSlaves=true。
如果你有一个写事务,或者你有个读请求是时间敏感的(binlog同步有延迟),通过设置Connection.setReadOnly(false),驱动将会保证你的请求会到主库。驱动负责维护事务的传播等级,隔离级别,以及连接之间的关系和列表。
为了确保这个功能,在创建连接池,或者为单体应用创建JDBC连接时,请使用com.mysql.jdbc.ReplicationDriver 这个驱动,他也接受Mysql-JDBC的标准驱动,ReplicationDriver目前不能和基于java.sql.DriverManager创建的连接一起工作,除非是Mysql-JDBC官方的驱动注册到DriverManager。
这里有个ReplicationDriver的例子:
import java.sql.Connection;
import java.sql.ResultSet;
import java.util.Properties;
import com.mysql.jdbc.ReplicationDriver;
public class ReplicationDriverDemo {
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", "password");
//
// 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:replication://master,slave1,slave2,slave3/test",
props);
//
// Perform read/write work on the master
// by setting the read-only flag to "false"
//
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");
.......
}
}
可以考虑使用loadBalance JDBC连接池工具–lbpool:它在标准jdbc-driver的包装器,包括失败检查,和负载分发,关于更多的信息,请关注:https://code.google.com/archive/p/mysql-lbpool/
在mysql-jdbc 5.1.27后,开始支持多主replication驱动
连接模式如下:
jdbc:mysql:replication://address=(type=master)(host=master1host),address=(type=master)(host=master2host),address=(type=slave)(host=slave1host)/database
Connector/J本质上使用了loadBalance来管理多主连接,这意味着,ReplicationConnection在配置使用多主时,暴露相同的选项来平衡主节点的负载。详情:https://dev.mysql.com/doc/connector-j/5.1/en/connector-j-usagenotes-j2ee-concepts-managing-load-balanced-connections.html
自动mysql-jdbc 5.1.28后,提供了replication实时重构的功能,用户可以在不停用java应用时,动态的添加,删除节点。
replication主机连接在replication连接组下管理最有效,一个replication连接组,代表了被统一管理的一个逻辑组,在一个java应用,可能有一个或多个replication连接组,主类暴露出管理replication连接内主机的方法,replication对象注册在自己的连接组内。每个连接组追踪自己的连接,直至关闭,并且操作这些关联的主机。
有一些重要的管理主机的方法:
有些有用的管理方法如下:
com.mysql.jdbc.ReplicationConnectionGroupManager 提供了接入replication连接组的方法,和其他一些方法
当Connector/J以replicationEnableJMX=true开头,而且设置了replicationConnectionGroup属性,JMX的MBean将会被注册,允许通过JMX客户端操作Replication主机,MBean的接口定义在com.mysql.jdbc.jmx.ReplicationGroupManagerMBean并且促使ReplicationConnectionGroupManager改变静态方法。
public abstract void addSlaveHost(String groupFilter, String host) throws SQLException;
public abstract void removeSlaveHost(String groupFilter, String host) throws SQLException;
public abstract void promoteSlaveToMaster(String groupFilter, String host) throws SQLException;
public abstract void removeMasterHost(String groupFilter, String host) throws SQLException;
public abstract String getMasterHostsList(String group);
public abstract String getSlaveHostsList(String group);
public abstract String getRegisteredConnectionGroups();
public abstract int getActiveMasterHostCount(String group);
public abstract int getActiveSlaveHostCount(String group);
public abstract int getSlavePromotionCount(String group);
public abstract long getTotalLogicalConnectionCount(String group);
public abstract long getActiveLogicalConnectionCount(String group);