文档主页
MySQL Connector/J 开发人员指南
相关文档 下载本手册
PDF (US Ltr) - 1.2Mb
PDF (A4) - 1.2Mb


MySQL Connector/J 开发人员指南  /  多主机连接  /  使用 Connector/J 配置源/副本复制

9.4 使用 Connector/J 配置源/副本复制

本节介绍 Connector/J 对复制感知部署的支持的一些功能。

复制是在服务器连接的初始设置阶段由连接 URL 配置的,其格式类似于 用于 MySQL 连接的通用 JDBC URL,但使用的是特殊的方案

jdbc:mysql:replication://[source host][:port],[replica host 1][:port][,[replica host 2][:port]]...[/[database]] »
[?propertyName1=propertyValue1[&propertyName2=propertyValue2]...]

用户可以指定属性 allowSourceDownConnections=true 以允许创建 Connection 对象,即使无法访问任何源主机。此类 Connection 对象报告它们是只读的,并且 isSourceConnection() 对它们返回 false。当调用 Connection.setReadOnly(false) 时,Connection 会测试可用的源主机,如果无法建立与源的连接,则抛出 SQLException,如果主机可用,则切换到源连接。

用户可以指定属性 allowReplicasDownConnections=true 以允许创建 Connection 对象,即使无法访问任何副本主机。然后,Connection 在运行时会在调用 Connection.setReadOnly(true) 时测试可用的副本主机(请参阅下面的方法说明),如果无法建立与副本的连接,则抛出 SQLException,除非属性 readFromSourceWhenNoReplicas 设置为 true(请参阅下面的属性说明)。

通过将读取流量分发到副本来扩展读取负载

Connector/J 支持复制感知连接。它可以根据 Connection.getReadOnly() 的状态自动将查询发送到读/写源主机,或故障转移或循环负载均衡的副本集。

应用程序通过调用 Connection.setReadOnly(true) 来指示它希望事务是只读的。复制感知连接将使用其中一个副本连接,这些连接使用循环方案按副本主机进行负载均衡。给定连接会粘滞到副本,直到发出事务边界命令(提交或回滚)或从服务中删除副本。调用 Connection.setReadOnly(true) 后,如果希望在没有可用副本时允许连接到源,请将属性 readFromSourceWhenNoReplicas 设置为 true”。 请注意,在这些情况下,源主机将处于只读状态,就像它是一个副本主机一样。另请注意,设置 readFromSourceWhenNoReplicas=true 可能会以透明的方式导致源主机的额外负载。

如果您有一个写事务,或者您有一个对时间敏感的读操作(请记住,MySQL 中的复制是异步的),请通过调用 Connection.setReadOnly(false) 将连接设置为非只读,驱动程序将确保将进一步的调用发送到源 MySQL 服务器。驱动程序负责在它用来实现此负载均衡功能的所有连接之间传播自动提交、隔离级别和目录的当前状态。

要启用此功能,请在连接到服务器时使用特殊的复制方案 ( jdbc:mysql:replication://)。

以下是在独立应用程序中如何使用复制感知连接的简短示例

import java.sql.Connection;
import java.sql.ResultSet;
import java.util.Properties;
import java.sql.DriverManager;

public class ReplicationDemo {

  public static void main(String[] args) throws Exception {
  
    Properties props = new Properties();

    // We want this for failover on the replicas
    props.put("autoReconnect", "true");

    // We want to load balance between the replicas
    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 'source', the rest being any number
    // of replicas that the driver will load balance against
    //

    Connection conn =
        DriverManager.getConnection("jdbc:mysql:replication://source,replica1,replica2,replica3/test",
            props);

    //
    // Perform read/write work on the source
    // 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 replica, the driver automatically picks one
    // from the list
    //

    conn.setReadOnly(true);

    ResultSet rs =
      conn.createStatement().executeQuery("SELECT a,b FROM alt_table");

     .......
  }
}

请考虑使用负载均衡 JDBC 池 (lbpool) 工具,该工具提供标准 JDBC 驱动程序的包装器,并允许您使用包含系统故障和负载分布不均检查的数据库连接池。有关更多信息,请参阅 适用于 MySQL 的负载均衡 JDBC 驱动程序 (mysql-lbpool)

支持多源复制拓扑

Connector/J 支持多源复制拓扑。

前面讨论的复制连接 URL(即格式为 jdbc:mysql:replication://source,replica1,replica2,replica3/test)假设第一个(且仅第一个)主机是源主机。要支持具有任意数量的源和副本的部署,需要使用 第 6.2 节“连接 URL 语法” 中讨论的多主机连接的“地址等于”URL 语法,并使用属性 type=[source|replica];例如

jdbc:mysql:replication://address=(type=source)(host=source1host),address=(type=source)(host=source2host),address=(type=replica)(host=replica1host)/database

Connector/J 在内部使用负载均衡连接来管理源连接,这意味着 ReplicationConnection 在配置为使用多个源时,会公开与 第 9.3 节“使用 Connector/J 配置负载均衡” 中所述相同的选项来平衡源主机上的负载。

复制拓扑的实时重新配置

Connector/J 还支持实时管理复制主机(单源或多源)拓扑。这使得用户无需重新启动应用程序即可为 Java 应用程序提升副本。

复制主机最有效地管理是在复制连接组的上下文中进行的。ReplicationConnectionGroup 类表示可以一起管理的连接的逻辑分组。在给定的 Java 类加载器中可能存在一个或多个此类复制连接组(应用程序可能有两个不同的 JDBC 资源需要独立管理)。这个关键类公开了用于复制连接的主机管理方法,如果为新的 replicationConnectionGroup 属性指定了值,则 ReplicationConnection 对象会向相应的 ReplicationConnectionGroup 注册自己。ReplicationConnectionGroup 对象会跟踪这些连接,直到它们关闭,并且它用于操作与这些连接关联的主机。

一些与主机管理相关的重要方法包括

  • getSourceHosts():返回一个字符串集合,表示配置为源主机的主机

  • getReplicaHosts():返回一个字符串集合,表示配置为副本主机的主机

  • addReplicaHost(String host):将新主机添加到可能的副本主机池中,以便在新的只读工作负载开始时进行选择

  • promoteReplicaToSource(String host):从未来只读进程的潜在副本主机池中删除主机(允许现有只读进程继续完成),并将主机添加到潜在源主机池中

  • removeReplicaHost(String host, boolean closeGently):从配置的副本主机列表中删除主机(主机名匹配必须完全一致);如果 closeGently 为 false,则当前活动主机为此主机的现有连接将被强制关闭(应用程序应预期会出现异常)

  • removeSourceHost(String host, boolean closeGently):与 removeReplicaHost() 相同,但从配置的源主机列表中删除主机

一些有用的管理指标包括

  • getConnectionCountWithHostAsReplica(String host):返回将给定主机配置为可能的副本主机的 ReplicationConnection 对象的数量

  • getConnectionCountWithHostAsSource(String host):返回将给定主机配置为可能的源主机的 ReplicationConnection 对象的数量

  • getNumberOfReplicasAdded():返回动态添加到组池中的副本主机次数

  • getNumberOfReplicasRemoved():返回从组池中动态移除副本主机次数。

  • getNumberOfReplicaPromotions():返回副本主机被提升为源主机的次数。

  • getTotalConnectionCount():返回已向该组注册的 ReplicationConnection 对象的数量。

  • getActiveConnectionCount():返回当前由该组管理的 ReplicationConnection 对象的数量。

ReplicationConnectionGroupManager

com.mysql.cj.jdbc.ha.ReplicationConnectionGroupManager 提供对复制连接组的访问,以及一些实用方法。

  • getConnectionGroup(String groupName):返回与提供的 groupName 匹配的 ReplicationConnectionGroup 对象。

ReplicationConnectionGroupManager 中的其他方法与 ReplicationConnectionGroup 中的方法类似,不同之处在于第一个参数是 String 类型的组名。这些方法将对所有匹配的 ReplicationConnectionGroups 进行操作,这有助于从服务中移除服务器并使其在所有可能的 ReplicationConnectionGroups 中退役。

如果应用程序触发拓扑更改,则这些方法可能对 JVM 内部的复制主机管理很有用。对于从 JVM 外部管理主机配置,可以使用 JMX。

使用 JMX 管理复制主机

当使用 ha.enableJMX=true 启动 Connector/J 并为属性 replicationConnectionGroup 设置值时,将注册一个 JMX MBean,允许 JMX 客户端操作复制主机。MBean 接口在 com.mysql.cj.jdbc.jmx.ReplicationGroupManagerMBean 中定义,并利用 ReplicationConnectionGroupManager 静态方法。

 public abstract void addReplicaHost(String groupFilter, String host) throws SQLException;
 public abstract void removeReplicaHost(String groupFilter, String host) throws SQLException;
 public abstract void promoteReplicaToSource(String groupFilter, String host) throws SQLException;
 public abstract void removeSourceHost(String groupFilter, String host) throws SQLException;
 public abstract String getSourceHostsList(String group);
 public abstract String getReplicaHostsList(String group);
 public abstract String getRegisteredConnectionGroups();
 public abstract int getActiveSourceHostCount(String group);
 public abstract int getActiveReplicaHostCount(String group);
 public abstract int getReplicaPromotionCount(String group);
 public abstract long getTotalLogicalConnectionCount(String group);
 public abstract long getActiveLogicalConnectionCount(String group);

使用 DNS SRV 配置源/副本复制

有关详细信息,请参见第 6.14 节“支持 DNS SRV 记录”