# 配置独享型负载均衡
在大数据处理场景中，通常需要通过负载均衡器来分发流量，以提高OpenSearch集群的可用性和性能。然而，默认的共享型负载均衡器在功能和性能上存在局限性，无法满足高并发和复杂业务需求。如何配置独享型负载均衡器，以充分利用其更丰富的功能和更强的性能，成为了一个亟待解决的问题。本文将详细介绍如何配置独享型负载均衡器，以实现更高效、更安全的集群访问能力。
#### 配置方案介绍
使用独享型负载均衡器接入集群具有如下优点：
- 非安全模式集群也支持集成弹性负载均衡服务的能力。
- 支持用户使用自定义证书进行HTTPS双向认证。
- 支持7层流量监控及告警配置，方便用户随时查看监控情况。
 
不同安全模式的集群对接独享型负载均衡器共有8种不同的服务形态，不同服务形态对应的ELB能力如[表1]所示，8种组合的配置概览如[表2]所示。
 表1不同集群对应的ELB能力 
| 集群安全模式       | ELB最终对外提供的服务形态                                                                                                                | ELB负载均衡 | ELB流量监控 | ELB双向认证 |
|:---|:---|:---|:---|:---|
| 非安全        | 无认证                                                                                                                          | 支持      | 支持      | 不支持      |
| 非安全        | 单向认证 双向认证            | 支持        | 支持        | 支持        |
| 安全+HTTP    | 密码认证                                                                                                                           | 支持        | 支持        | 不支持        |
| 安全+HTTP    | 单向认证+密码认证 双向认证+密码认证  | 支持        | 支持       | 支持        |
| 安全+HTTPS | 单向认证+密码认证 双向认证+密码认证 | 支持       | 支持     | 支持         |
   
 表2不同集群对接ELB的配置概览 
| **集群安全模式**                          | **ELB最终对外提供的服务形态**                  | **ELB监听器**                         | **ELB监听器**                         | **ELB监听器**                       | **后端服务器组**                       | **后端服务器组**                           | **后端服务器组**                                               |
| **集群安全模式**                          | **ELB最终对外提供的服务形态**                  | **前端协议**                           | **前端端口**                           | **SSL解析方式**                         | **后端协议**                           | **健康检查端口**                        | **健康检查路径**                                              |
|:---|:---|:---|:---|:---|:---|:---|:---|
| 非安全      | 无认证        | HTTP       | 9200    | 无认证     | HTTP     | 9200     | /                             |
| 非安全      | 单向认证     | HTTPS  | 9200   | 单向认证 | HTTP  | 9200 | /                             |
| 非安全      | 双向认证       | HTTPS   | 9200    | 双向认证    | HTTP    | 9200      | /                             |
| 安全+HTTP | 密码认证     | HTTP     | 9200     | 无认证      | HTTP   | 9200      | /_opendistro/_security/health |
| 安全+HTTP | 单向认证+密码认证 | HTTPS  | 9200 | 单向认证   | HTTP  | 9200 | /_opendistro/_security/health |
| 安全+HTTP | 双向认证+密码认证  | HTTPS   | 9200   | 双向认证   | HTTP    | 9200      | /_opendistro/_security/health |
| 安全+HTTPS   | 单向认证+密码认证  | HTTPS    | 9200     | 单向认证   | HTTPS   | 9200     | /_opendistro/_security/health |
| 安全+HTTPS   | 双向认证+密码认证  | HTTPS | 9200  | 双向认证    | HTTPS | 9200     | /_opendistro/_security/health |
   
#### 约束限制
- 如果ELB绑定了公网，则不推荐接入非安全模式的集群。由于非安全模式的集群使用HTTP协议通信，且不需要安全认证即可访问，如果对接公网访问会存在安全风险。
- 开启了HTTPS访问的安全模式的集群不支持HTTP类型的前端协议认证，如果需要使用HTTP类型的前端协议，需要将集群的"安全模式"变更为"非安全模式"，具体操作请参见[安全模式变更](https://support.huaweicloud.com/usermanual-css/css_01_0310.html)。在变更安全模式前，请先关闭"负载均衡"，安全模式变更完成后再开启"负载均衡"。
 
#### 前提条件
- 已经创建独享型负载均衡器，操作指导请参见[创建独享型负载均衡器](https://support.huaweicloud.com/usermanual-elb/elb_lb_000006.html)。负载均衡器需要满足如下条件：
  - "所属VPC"和CSS集群的虚拟私有云保持一致。确保两者之间网络互通。
  
  - 开启"IP类型后端"。只有开启IP类型后端，独享型负载均衡器才支持接入CSS集群。
  
  - 根据业务需求，选择是否配置"弹性公网IP"。只有配置了弹性公网IP，CSS集群对接的负载均衡实例才会显示"公网IP"，才支持通过负载均衡实现公网访问CSS集群。
   
- 如果规划ELB监听器的前端协议是HTTPS，则需要将服务器证书或CA证书上传至ELB管理控制台。操作指导请参见[创建证书](https://support.huaweicloud.com/usermanual-elb/elb_ug_szs_0003.html)。
  - 监听器的SSL解析方式是单向认证，则需要上传服务器证书。
  
  - 监听器的SSL解析方式是双向认证，则需要上传服务器证书和CA证书。
   
 
#### CSS集群对接负载均衡器
1. 登录[云搜索服务管理控制台](https://console.huaweicloud.com/elasticsearch/)。
2. 在左侧导航栏，选择"集群管理 \> OpenSearch"。
3. 在集群列表，单击目标集群名称，进入集群详情页。
4. 选择"访问配置 \> 负载均衡"，在"OpenSearch"页签，打开"负载均衡开关"右侧的开关，在弹窗中完成基础配置。
   表3负载均衡基础配置 
   | 参数   | 说明                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
   |:---|:---|
   | 负载均衡器 | 选择准备好的独享型负载均衡器。 如果没有合适的ELB，可以单击创建负载均衡器前往创建页面，操作步骤请参见[创建独享型负载均衡器](https://support.huaweicloud.com/usermanual-elb/elb_lb_000006.html)。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
   | 委托   | 配置负载均衡器需要当前账号具备ELB资源的使用权限。通过配置IAM委托，使当前账号授权CSS服务访问其拥有的ELB资源。 - 当首次配置委托时，可以单击"自动创建委托"新建委托"css_elb_agency"直接使用。  - 当已有自动创建的委托时，可以单击"委托一键授权"，自动删除委托中"ELB Administrator"系统角色或"ELB FullAccess"系统策略的权限，并自动新增如下自定义策略授权委托到最小化权限。 ``` "elb:loadbalancers:list", "elb:loadbalancers:get", "elb:certificates:list", "elb:healthmonitors:*", "elb:members:*", "elb:pools:*", "elb:listeners:*" ```   - 执行"自动创建委托"和"委托一键授权"的用户需要如下最小权限。 ``` "iam:agencies:listAgencies", "iam:roles:listRoles", "iam:agencies:getAgency", "iam:agencies:createAgency", "iam:permissions:listRolesForAgency", "iam:permissions:grantRoleToAgency", "iam:permissions:listRolesForAgencyOnProject", "iam:permissions:revokeRoleFromAgency", "iam:roles:createRole" ```   - 使用委托的用户需要如下最小权限。 ``` "iam:agencies:listAgencies", "iam:agencies:getAgency", "iam:permissions:listRolesForAgencyOnProject", "iam:permissions:listRolesForAgency" ```    |
      
   图1开启负载均衡   
   ![](https://support.huaweicloud.com/usermanual-css/figure/zh-cn_image_0000002416074461.png "点击放大") 
5. 单击"确定"，开启负载均衡。 开启后，页面会显示负载均衡实例的信息。
   
6. 在"监听器配置"区域，您可以单击右侧![](https://support.huaweicloud.com/usermanual-css/figure/zh-cn_image_0000002382515146.png)配置监听器以确保客户端能够正常访问CSS集群。
   表4配置监听器 
   | 参数     | 说明                                                                                                                                                                                                                                                                                         |
   |:---|:---|
   | 前端协议      | 客户端与负载均衡监听器建立流量分发连接的协议。 支持选择"HTTP"或"HTTPS"。 建议根据实际业务需要选择协议。                                                                       |
   | 前端端口    | 客户端与负载均衡监听器建立流量分发连接的端口。 建议根据实际业务需要自定义。                                                                                                                                                                           |
   | SSL解析方式 | 客户端到服务器端认证方式。仅"前端协议"选择"HTTPS"才需要配置。 支持"单向认证"或"双向认证"。 建议根据实际业务需要选择解析方式。                                                           |
   | 服务器证书   | 服务器证书用于SSL握手协商，需提供证书内容和私钥。仅"前端协议"选择"HTTPS"才需要配置服务器证书。 选择在ELB创建的服务器证书。                                                                                                                                         |
   | CA证书  | CA证书又称客户端CA公钥证书，用于验证客户端证书的签发者。仅"SSL解析方式"选择"双向认证"时，才需要配置CA证书。 选择在ELB创建的CA证书。 在开启HTTPS双向认证功能时，只有当客户端能够出具指定CA签发的证书时，HTTPS连接才能成功。 |
      
   图2配置监听器   
   ![](https://support.huaweicloud.com/usermanual-css/figure/zh-cn_image_0000002416194325.png "点击放大") 
7. （可选）在监听器配置区域，单击"访问控制"后的"设置"跳转到负载均衡器的监听器列表，单击监听器访问控制列的"设置"，配置监听器的访问控制以限制访问CSS集群的IP地址，提高安全性。设置访问控制的操作指导请参见[访问控制策略](https://support.huaweicloud.com/usermanual-elb/elb_03_0003.html)。
   ![](https://support.huaweicloud.com/usermanual-css/public_sys-resources/warning_3.0-zh-cn.png)
   不设置的话默认允许所有的IP地址通过负载均衡实例访问CSS集群，此时存在安全风险。
   
8. 在健康检查区域，您可以查看各个节点IP的健康检查结果，确保集群各个节点正常运行。
   表5健康检查结果状态说明 
   | 健康检查结果 | 说明        |
   |:---|:---|
   | 正常     | 节点IP连接正常。 |
   | 异常    | 节点IP连接不可用 |
      
   
9. 当集群无需使用负载均衡访问时，可以解绑独享型负载均衡器，释放资源。 在"负载均衡 \> OpenSearch"页面，关闭"负载均衡开关"右侧的开关，在弹窗中单击"确定"，解绑ELB。
   ![](https://support.huaweicloud.com/usermanual-css/public_sys-resources/caution_3.0-zh-cn.png)
   关闭负载均衡后，监听器及后端服务器组配置将被删除，且不可恢复。
   
 
#### 通过Curl命令使用负载均衡接入集群
1. 在云搜索服务管理控制台，单击左侧导航栏的"集群管理"。
2. 登录[云搜索服务管理控制台](https://console.huaweicloud.com/elasticsearch/)。
3. 在左侧导航栏，选择"集群管理 \> OpenSearch"。
4. 在集群列表，单击目标集群名称，进入集群详情页。
5. 选择"访问配置 \> 负载均衡"，在"OpenSearch"页签，获取并记录负载均衡实例的"私有IP"、"IPv6地址"或"公网IP"，以及监听器配置的"前端协议/端口"。
   ![](https://support.huaweicloud.com/usermanual-css/public_sys-resources/caution_3.0-zh-cn.png)
   如果ELB绑定了公网，则不推荐接入非安全模式的集群。非安全模式的集群使用HTTP通信且不需要安全认证即可访问，如果对接公网访问存在安全风险。
   
6. 在ECS服务器中执行如下Curl命令测试能否通过独享型负载均衡实例接入集群。
   表6不同集群的接入命令 
   | 集群安全模式       | ELB最终对外提供的服务形态 | 接入集群的Curl命令 |
   |:---|:---|:---|
   | 非安全        | 无认证           | ``` curl http://IP:port ```                                                                                          |
   | 非安全        | 单向认证            | ``` curl --cacert ./ca.crt https://IP:port ```                                                                       |
   | 非安全        | 双向认证           | ``` curl --cacert ./ca.crt --cert ./client.crt --key ./client.key https://IP:port ```                                |
   | 安全+HTTP    | 密码认证            | ``` curl http://IP:port -u user:pwd ```                                                                              |
   | 安全+HTTP    | 单向认证+密码认证     | ``` curl --cacert ./ca.crt https://IP:port -u user:pwd ```                                                           |
   | 安全+HTTP    | 双向认证+密码认证      | ``` curl --cacert ./ca.crt --cert ./client.crt --key ./client.key https://IP:port -u user:pwd ```                    |
   | 安全+HTTPS | 单向认证+密码认证     | ``` curl --cacert ./ca.crt https://IP:port -u user:pwd ```                                                           |
   | 安全+HTTPS | 双向认证+密码认证     | ``` curl --cacert ./ca.crt --cert ./client.crt --key ./client.key https://IP:port -u user:pwd ```                    |
      
   表7变量说明 
   | 变量名 | 说明                 |
   |:---|:---|
   | IP  | 负载均衡实例的IP地址。        |
   | port                              | 监听器配置的"前端协议/端口"。                              |
   | user    | 集群的用户名，仅安全集群需要配置。  |
   | pwd    | 用户名对应的密码，仅安全集群需要配置。 |
      
   当可以正常返回集群信息时，表示连接成功。
   
本文还提供了通过独享型负载均衡实例接入集群的Java客户端代码示例：[通过负载均衡器的HTTPS双向认证方式接入集群的代码示例（Java）]
 #### 通过负载均衡器的HTTPS双向认证方式接入集群的代码示例（Java）
在Java客户端，通过负载均衡器的HTTPS双向认证方式接入集群的代码示例。
#### OpenSearchDemo代码示例
```
package org.example;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Base64;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.TrustManagerFactory;
public class OpensearchDemo {
    private static final String TRUSTED_CA_PATH = "path\\ca.pem"; // CA证书路径
    private static final String PKCS12_PATH = "path\\client.p12"; // 客户端证书路径
    private static final String KEY_PASSWORD = ""; // 客户端证书密码
    private static final String HOST_NAME = ""; // ELB IP或域名
    private static final int PORT = 9200;  //ELB 端口
    private static final String ELB_URL = "https://" + HOST_NAME + ":" + PORT;
    private static final String OS_USER = ""; // Opensearch用户名
    private static final String OS_PASS = ""; // Opensearch用户名的密码
    public static void main(String[] args) throws Exception {
        // 1. 创建标准的 SSLContext
        SSLContext sslContext = createStrictMtlsSslContext();
        // 2. 注入 SSLContext
        HttpClient client = HttpClient.newBuilder()
            .sslContext(sslContext)
            .connectTimeout(java.time.Duration.ofSeconds(10))
            .build();
        String authHeader = getBasicAuthHeader(OS_USER, OS_PASS);
        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create(ELB_URL + "/_cat/indices?v"))
            .GET()
            .header("Accept", "application/json")
            .header("Authorization", authHeader)
            .build();
        try {
            // 发送请求
            HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
            System.out.println("http statusCode: " + response.statusCode());
            System.out.println("response body:\n" + response.body());
        } catch (SSLHandshakeException e) {
            System.err.println("SSLHandshakeException: " + e.getMessage());
            e.printStackTrace();
        } catch (IOException e) {
            System.err.println("IOException: " + e.getMessage());
            e.printStackTrace();
        }
    }
    /**
     * 创建SSLContext
     */
    private static SSLContext createStrictMtlsSslContext() throws Exception {
        // --- 1. 准备 TrustStore (验证服务器) ---
        KeyStore trustStore = KeyStore.getInstance("PKCS12");
        trustStore.load(null, null);
        X509Certificate caCert = loadCertificate(TRUSTED_CA_PATH);
        trustStore.setCertificateEntry("ca-root", caCert);
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        tmf.init(trustStore);
        // --- 2. 准备 KeyStore (客户端身份) ---
        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        File p12File = new File(PKCS12_PATH);
        try (InputStream is = new FileInputStream(p12File)) {
            keyStore.load(is, KEY_PASSWORD.toCharArray());
        }
        KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        kmf.init(keyStore, KEY_PASSWORD.toCharArray());
        // --- 3. 初始化 SSLContext (标准模式) ---
        SSLContext sslContext = SSLContext.getInstance("TLSv1.3");
        sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new SecureRandom());
        return sslContext;
    }
    private static X509Certificate loadCertificate(String path) throws Exception {
        try (InputStream is = new FileInputStream(path)) {
            String pem = new String(is.readAllBytes(), StandardCharsets.UTF_8);
            String base64 = pem.replace("-----BEGIN CERTIFICATE-----", "")
                .replace("-----END CERTIFICATE-----", "")
                .replaceAll("\\s+", "");
            byte[] der = Base64.getDecoder().decode(base64);
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            return (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(der));
        }
    }
    private static String getBasicAuthHeader(String user, String pass) {
        String auth = user + ":" + pass;
        String encoded = Base64.getEncoder().encodeToString(auth.getBytes(StandardCharsets.UTF_8));
        return "Basic " + encoded;
    }
}
```
#### pom.xml代码示例
```
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.example</groupId>
    <artifactId>opensearch-demo</artifactId>
    <version>1.0</version>
    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.opensearch.client</groupId>
            <artifactId>opensearch-java</artifactId>
            <version>2.19.0</version>
        </dependency>
        <dependency>
            <groupId>org.opensearch.client</groupId>
            <artifactId>opensearch-rest-client</artifactId>
            <version>2.19.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.httpcomponents.client5</groupId>
            <artifactId>httpclient5</artifactId>
            <version>5.3.1</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.17.0</version>
        </dependency>
    </dependencies>
</project>
```
