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

文章评论

0条评论