全部產品
Search
文件中心

Hologres:基於JDBC的負載平衡

更新時間:Jun 30, 2024

Hologres從 V1.3版本開始,支援在JDBC配置多個唯讀從執行個體以支援簡單的負載平衡。本文為您介紹如何基於JDBC實現負載平衡。

背景資訊

Hologres中一個主執行個體可以綁定多個唯讀從執行個體,執行個體與執行個體之間共用儲存,但是計算資源是互相隔離的,從而實現讀寫分離高可用部署,詳情請參見主從執行個體讀寫分離部署(共用儲存)

Hologres支援使用JDBC配置多個唯讀從執行個體,實現簡單的負載平衡,如下圖所示:image..png

您使用JDBC配置多個唯讀從執行個體可以實現以下功能:

  • 將查詢請求隨機分配到您的唯讀從執行個體,避免單個唯讀從執行個體負載過高。

  • 查詢請求按照順序串連唯讀從執行個體,極大程度避免因為唯讀從執行個體故障導致服務不可用,存在以下情況:

    • 當唯讀從執行個體1串連失敗時,JDBC會自動嘗試串連唯讀從執行個體2。

    • 當唯讀從執行個體1和唯讀從執行個體2串連失敗時,JDBC會自動嘗試串連唯讀從執行個體3。

    • 只有當唯讀從執行個體1、唯讀從執行個體2和唯讀從執行個體3均串連失敗時,系統才會提示串連失敗。

從Hologres V2.0.10版本開始,targetServerType參數支援更加豐富的取值,擴充負載平衡使用的情境。

使用說明

前提條件

命令格式

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

允許串連到指定狀態的唯讀從執行個體。取值為any,即表示可以串連到URL中的任意Endpoint。

僅Hologres V2.0.10及以上版本支援如下取值:

  • master:僅串連主執行個體。

  • slave:僅串連唯讀從執行個體。

  • preferSlave:優先串連唯讀從執行個體,如果串連不上唯讀從資料庫才串連到主執行個體。

JDBC會根據GUC參數in_hot_standby的取值判斷執行個體為主執行個體還是唯讀從執行個體。in_hot_standby取值說明如下:

  • off:為主執行個體。

  • on:為唯讀從執行個體。

loadBalanceHosts

指定嘗試串連唯讀從執行個體的順序,取值如下:

  • False(預設):按串連URL內順序串連唯讀從執行個體。

  • True:隨機串連唯讀從執行個體。

hostRecheckSeconds

可串連Endpoint列表的緩衝時間,預設為10s

若您希望調整該緩衝的時間,可以修改hostRecheckSeconds的參數值,如下樣本將緩衝改為30s

jdbc:postgresql://{ENDPOINT1}:{PORT1},{ENDPOINT2}:{PORT2},{ENDPOINT3}:{PORT3}.../{DBNAME}?targetServerType=any&loadBalanceHosts=true&hostRecheckSeconds=30

說明

關於更多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的監控資訊。image..png

    • 執行個體hgpostcn-cn-wxxxxxxxx05的監控資訊。image..png