Hologres从 V1.3版本开始,支持在JDBC配置多个只读从实例以支持简单的负载均衡。本文为您介绍如何基于JDBC实现负载均衡。
背景信息
Hologres中一个主实例可以绑定多个只读从实例,实例与实例之间共享存储,但是计算资源是互相隔离的,从而实现读写分离高可用部署,详情请参见主从实例读写分离部署(共享存储)。
Hologres支持使用JDBC配置多个只读从实例,实现简单的负载均衡,如下图所示:
您使用JDBC配置多个只读从实例可以实现以下功能:
将查询请求随机分配到您的只读从实例,避免单个只读从实例负载过高。
查询请求按照顺序连接只读从实例,极大程度避免因为只读从实例故障导致服务不可用,存在以下情况:
当只读从实例1连接失败时,JDBC会自动尝试连接只读从实例2。
当只读从实例1和只读从实例2连接失败时,JDBC会自动尝试连接只读从实例3。
只有当只读从实例1、只读从实例2和只读从实例3均连接失败时,系统才会提示连接失败。
从Hologres V2.0.10版本开始,targetServerType
参数支持更加丰富的取值,扩展负载均衡使用的场景。
使用说明
前提条件
已购买多个Hologres只读从实例并绑定至Hologres主实例,详情请参见配置共享存储的主从实例。
已下载42.3.2以上版本的Postgres JDBC驱动,详情请参见JDBC。
命令格式
JDBC配置多个只读从实例需要在连接URL中将多个只读从实例的Endpoint:Port
信息用半角逗号(,
)分隔,命令格式如下:
jdbc:postgresql://<Endpoint1>:<Port1>,<Endpoint2>:<Port2>,<Endpoint3>:<Port3>.../<DBNAME>?user=<AccessKey ID>&password=<AccessKey Secret>&targetServerType=any&loadBalanceHosts=<value>[&hostRecheckSeconds=<value>]
参数说明
参数 | 描述 |
Endpoint | Hologres实例的网络地址。 进入Hologres管理控制台的实例详情页获取网络地址。 |
Port | Hologres实例的端口。 进入Hologres管理控制台的实例详情页获取端口。 |
DBNAME | Hologres创建的数据库名称。 |
AccessKey ID | 当前阿里云账号的AccessKey ID。 您可以单击AccessKey 管理,获取AccessKey ID。 |
AccessKey Secret | 当前阿里云账号的AccessKey Secret。 您可以单击AccessKey 管理,获取AccessKey Secret。 |
targetServerType | 允许连接到指定状态的只读从实例。取值为 仅Hologres V2.0.10及以上版本支持如下取值:
JDBC会根据GUC参数
|
loadBalanceHosts | 指定尝试连接只读从实例的顺序,取值如下:
|
hostRecheckSeconds | 可连接Endpoint列表的缓存时间,默认为 若您希望调整该缓存的时间,可以修改
|
关于更多JDBC配置说明,详情请参见JDBC的手册。
使用示例
如下示例会将查询随机分发到三个只读从实例上,并且当其中一个实例连接失败时,JDBC会自动尝试切换到另一个实例连接。
import java.sql.*; import java.util.HashMap; import java.util.Map; import java.util.Properties; public class hatest { public static void main(String[] args) { // 设置Hologres实例的连接endpoint,只读从实例1 String endpoint1 = "hgpostcn-cn-wxxxxxxxx01-cn-shanghai.hologres.aliyuncs.com:80"; // 设置Hologres实例的连接endpoint,只读从实例2 String endpoint2 = "hgpostcn-cn-wxxxxxxxx02-cn-shanghai.hologres.aliyuncs.com:80"; // 设置Hologres实例的连接endpoint,只读从实例3 String endpoint3 = "hgpostcn-cn-wxxxxxxxx03-cn-shanghai.hologres.aliyuncs.com:80"; // 设置待连接的数据库名 String dbname = "postgres"; String jdbcUrl = "jdbc:postgresql://" + endpoint1 + "," + endpoint2 + "," + endpoint3 + "/" + dbname; Properties properties = new Properties(); // 设置连接数据库的用户名 properties.setProperty("user", "xxxx"); //设置连接数据库的密码 properties.setProperty("password", "xxxx"); // 配置targetServerType,此处配置为any,表示可以对任意endpoint发送请求 properties.setProperty("targetServerType", "any"); // 配置LoadBalance策略,此处配置true,表示开启LoadBalance properties.setProperty("loadBalanceHosts", "true"); // 配置hostRecheckSeconds时间,此处配置为10秒 properties.setProperty("hostRecheckSeconds", "10"); try { Class.forName("org.postgresql.Driver"); Connection connection = DriverManager.getConnection(jdbcUrl, properties); PreparedStatement preparedStatement = connection.prepareStatement("show hg_frontend_endpoints;" ); ResultSet resultSet = preparedStatement.executeQuery(); while (resultSet.next()) { ResultSetMetaData rsmd = resultSet.getMetaData(); int columnCount = rsmd.getColumnCount(); Map map = new HashMap(); for (int i = 0; i < columnCount; i++) { map.put(rsmd.getColumnName(i + 1).toLowerCase(), resultSet.getObject(i + 1)); } System.out.println(map); } } catch (Exception exception) { exception.printStackTrace(); } } }
如下示例可以将查询轮询100次分发到2个实例上。
import java.sql.*; import java.util.HashMap; import java.util.Map; import java.util.Properties; public class hatest { public static void main(String[] args) { int x = 1; while( x <= 100 ){ // 设置Hologres实例的连接endpoint,主实例 String endpoint1 = "hgpostcn-cn-wxxxxxxxx04-cn-hangzhou.hologres.aliyuncs.com:80"; // 设置Hologres实例的连接endpoint,只读从实例 String endpoint2 = "hgpostcn-cn-wxxxxxxxx05-cn-hangzhou.hologres.aliyuncs.com:80"; // 设置待连接的数据库名 String dbname = "postgres"; String jdbcUrl = "jdbc:postgresql://" + endpoint1 + "," + endpoint2 + "/" + dbname ; Properties properties = new Properties(); // 设置连接数据库的用户名 properties.setProperty("user", "xxx"); // 设置连接数据库的密码 properties.setProperty("password", "xxx"); // 配置targetServerType,此处配置为any,表示可以对任意endpoint发送请求 properties.setProperty("targetServerType", "any"); // 配置LoadBalance策略,此处配置true,表示开启LoadBalance properties.setProperty("loadBalanceHosts", "true"); // 配置hostRecheckSeconds时间,此处配置为10秒 properties.setProperty("hostRecheckSeconds", "10"); try { Class.forName("org.postgresql.Driver"); Connection connection = DriverManager.getConnection(jdbcUrl, properties); PreparedStatement preparedStatement = connection.prepareStatement("show hg_frontend_endpoints;" ); ResultSet resultSet = preparedStatement.executeQuery(); while (resultSet.next()) { ResultSetMetaData rsmd = resultSet.getMetaData(); int columnCount = rsmd.getColumnCount(); Map map = new HashMap(); for (int i = 0; i < columnCount; i++) { map.put(rsmd.getColumnName(i + 1).toLowerCase(), resultSet.getObject(i + 1)); } System.out.println(map); } } catch (Exception exception) { exception.printStackTrace(); } x++; } } }
此时观察两个实例的监控信息,可以看到两个实例的连接数基本一致,查看实例的监控信息请参见查看监控指标。
实例hgpostcn-cn-wxxxxxxxx04的监控信息。
实例hgpostcn-cn-wxxxxxxxx05的监控信息。