连接器和 API 手册  / 第 3 章 MySQL Connector/J 开发人员指南  / 3.8 多主机连接  /  3.8.4 使用 Connector/J 配置 Source/Replica 复制

3.8.4 使用 Connector/J 配置 Source/Replica 复制

本节描述了 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调用时对可用源主机 的测试,Connection.setReadOnly(false)如果无法建立与源的连接则抛出 SQLException,或者如果主机可用则切换到源连接。

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

通过将读取流量分配给副本来横向扩展读取负载

Connector/J 支持复制感知连接。它可以自动将查询发送到读/写源主机,或者基于Connection.getReadOnly().

应用程序通过调用 发出它希望事务为只读的信号 Connection.setReadOnly(true)。复制感知连接将使用其中一个副本连接,这些连接使用循环方案在每个副本主机上进行负载平衡。在发出事务边界命令(提交或回滚)或从服务中删除副本之前,给定的连接会粘附到副本。调用后Connection.setReadOnly(true),如果你想在没有副本可用时允许连接到源,请将属性设置 readFromSourceWhenNoReplicastrue”。请注意,在这些情况下,源主机将以只读状态使用,就好像它是副本主机一样。另请注意,设置 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)假定第一个(并且只有第一个)主机是源主机。支持具有任意数量的源和副本的部署需要 第 3.5.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当配置为使用多个源时,会公开相同的选项来平衡源主机之间的负载,如 第 3.8.3 节“配置负载平衡”中所述带连接器/J”

复制拓扑的实时重新配置

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

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

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

  • 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 对象的数量

复制连接组管理器

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

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

中的其他方法与 中 的方法ReplicationConnectionGroupManager相同ReplicationConnectionGroup,只是第一个参数是字符串组名称。这些方法将对所有匹配的 ReplicationConnectionGroups 进行操作,这有助于从服务中删除服务器并使其在所有可能的 ReplicationConnectionGroups.

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

使用 JMX 管理复制主机

当 Connector/J 启动 ha.enableJMX=true并为属性设置值时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 配置源/副本复制

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