jdbc 多主机部署 Source/Replica Replication 实现只读数据源
1. 背景
业务要实现一个只读数据源的需求,并且具有高可用特性。MySQL 主从复制,1主2从,只读数据源默认连接到从库,两个从库负载均衡。其中一个从库挂了,流量全部打到另外一个从库。两个从库都挂了,流量打到主库。从库恢复后,流量重新打到从库。
看了 jdbc 官方文档,觉得 jdbc 多主机部署方案 Source/Replica Replication 可以实现上述需求。
2. 配置
jdbc 版本:5.1.49
jdbc 相关参数设置:
- readFromMasterWhenNoSlaves=true
- allowSlaveDownConnections=true
- allowMasterDownConnections=true
- roundRobinLoadBalance=true
- retriesAllDown=1
jdbc url 示例:
jdbc:mysql:replication://192.168.56.101:3306,192.168.56.102:3306,192.168.56.103:3306/sysbench?useSSL=false&readFromMasterWhenNoSlaves=true&allowSlaveDownConnections=true&allowMasterDownConnections=true&retriesAllDown=1&roundRobinLoadBalance=true&connectTimeout=3000&autoReconnect=true&user=sysbench&password=123456
- 192.168.56.101 主库
- 192.168.56.102 从库
- 192.168.56.103 从库
3. 测试结果
- 当 2 个从库都正常时,读流量均衡负载到两个从库上。
- 当其中 1 个从库宕机时,所有读流量负载到剩下的那个从库上。
- 当 2 个从库都宕机时,读流量负载到主库上。(从库宕机到流量切换到主库,中间大约有1分钟左右的时间,为什么会这么长,有待进一步调查,可能有相关参数进行配置)
- 当从库恢复后,新创建的连接会打到从库上,主库上已有的连接保持不变。
注意:
ReplicationDriver 有一个限制,创建的连接需要设置 readOnly=true 才能将流量打到从库上,这个配置项不支持在 jdbc url 或者 jdbc Properties 里面设置,需要业务在代码中设置。无法做到业务无感知地使用只读数据源,对业务代码有一定的侵入性。
当然也可以简单地修改一下 jdbc 驱动,让 readOnly 的默认值从 jdbc url 或者 jdbc Properties 里面获取。
另外关于参数 allowSlaveDownConnections,在官方文档中,该参数名为allowSlavesDownConnections,在 jdbc 源码中,实际为 allowSlaveDownConnections,注意区别,以代码中的为准,否则配置不会生效。
4. 相关代码
import java.sql.*;
import java.sql.Connection;
import java.sql.ResultSet;
import java.util.Properties;
import com.mysql.jdbc.ReplicationDriver;
class JDBCClient {
public static void main(String[] args) throws SQLException {
try{
ReplicationDriver driver = new ReplicationDriver();
String jdbc_url = "jdbc:mysql:replication://192.168.56.101:3306,192.168.56.102:3306,192.168.56.103:3306/sysbench?useSSL=false"
Properties props = new Properties();
props.put("connectTimeout","3000");
props.put("autoReconnect","true");
props.put("roundRobinLoadBalance", "true");
props.put("readFromMasterWhenNoSlaves", "true");
props.put("allowSlaveDownConnections", "true");
props.put("allowMasterDownConnections", "true");
props.put("retriesAllDown", 1);
props.put("user", "sysbench");
props.put("password", "123456");
Connection conn = driver.connect(jdbc_url, props);
conn.setReadOnly(true);
conn.createStatement().executeQuery("select sleep(1)");
conn.close();
}catch (Exception e) {
e.printStackTrace();
}
}
}
编译运行:
javac -cp /root/jdbc_connector/5.1.49/mysql-connector-java-5.1.49.jar JDBCClient.java
java -Djava.ext.dirs=/root/jdbc_connector/5.1.49/ JDBCClient
参考资料:
https://dev.mysql.com/doc/connector-j/5.1/en/connector-j-source-replica-replication-connection.html
文章评论