> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kasoftware.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 集群

> 如何配置多个知行之桥安装协同工作以实现高可用性和可扩展性。

export const siteNameShort = "知行之桥";

export const siteName = "知行之桥";

集群可以让多个 {siteName} 安装协同工作，用相同的配置处理相同的数据。工作负载可以水平分布在 {siteNameShort} 集群中，以提高可扩展性并确保可用性。

## 概述

为了利用 {siteNameShort} 支持的高可用性和故障转移功能，应将应用程序安装在同一服务器集群（同一集群）的多个系统上。然后由负载均衡器在承载 {siteNameShort} 实例的多个系统之间分配传入的流量。

<img src="https://mintcdn.com/qiao/U-KEZ9JbQY4Wqs1D/public/images/clustering_load_balancer.png?fit=max&auto=format&n=U-KEZ9JbQY4Wqs1D&q=85&s=3f266f0ea2a032919d6bfb0a4d977db2" alt="Cluster behind a load balancer" width="350" data-path="public/images/clustering_load_balancer.png" />

当配置集群时，服务器集群中的每个 {siteNameShort} 安装都使用相同的应用程序配置，处理磁盘上相同位置的数据，并将事务记录在相同的数据库表中。

因此，应用程序的多个实例表现得就像是一个实例，并且任何一个实例的关闭都不会破坏集群的性能。

## 配置 {siteNameShort} 进行集群

在集群内的每个节点都安装 {siteNameShort} 后，每个安装都应该配置为使用相同的 *应用程序数据库* 和 *应用程序数据目录*。

### 许可

必须为集群中的每个节点应用唯一的许可证密钥。转到每个节点的许可页面并应用其中一个密钥。应用程序在集群的共享目录中创建一个许可证文件。许可证文件名包括共享目录中两个节点的计算机名称。

### 应用程序数据库

{siteNameShort} 使用数据库来记录交易历史和发生在应用程序中的所有错误。{siteNameShort} 的每个实例都应该配置为使用同一个应用程序数据库，以确保所有处理的文件最终合并到数据库中。

#### .NET 版本

在 .NET 版本中配置应用程序数据库，必须将 `AppDb` 环境变量配置为包括正确的连接字符串和提供程序。为此，请修改安装目录 `www` 文件夹中的 `Web.Config` 文件。在此文件中有一个被注释掉的名为 *connectionStrings* 的 XML 元素，例如：

```xml theme={null}
<!-- connectionStrings>
 <add 
  name="AppDb" 
  connectionString="server=SQLSERVER_LOCATION;database=DATABASE_NAME;uid=USER_ID;password=PASSWORD;" 
  providerName="System.Data.SqlClient"
 />
</connectionStrings -->
```

取消 *connectionStrings* 元素的注释，将 `connectionString` 和 `providerName` 属性设置为所需数据库的适当连接参数。如果 {siteNameShort} 可以成功地使用这个连接字符串建立连接，那么它将使用这个数据库作为应用程序数据库。

#### 内置 Java 服务器

将跨平台版本与内置 Jetty 服务器一起使用时，应用程序数据库在安装目录 webapp 文件夹中的 `arc.xml` 文件中配置。在此服务器配置文件中，必须将 `APP_DB` 环境变量设置为包含所需数据库适当连接参数的 JDBC 连接字符串。例如：

```xml theme={null}
<Call name="setInitParameter">
 <Arg>APP_DB</Arg>
 <Arg>jdbc:cdata:mysql:Server=MySQLServer;Port=3306;Database=mysql;User=user;Password=password</Arg>
</Call>
```

如果 {siteNameShort} 可以成功地使用 `APP_DB` 连接字符串建立连接，那么它将使用该数据库作为应用程序数据库。

#### 外部 Java 服务器

将跨平台版本与外部 Java servlet（应用程序内置 Jetty 服务器以外的任何服务器）一起使用时，配置应用程序数据库的细节取决于所使用的特定 servlet。使用适用于特定 servlet 的语法，在配置服务器时使用以下其中一种方法：

* 定义一个包括目标数据库连接属性的 JNDI 数据源。
* 将 `APP_DB` 环境变量设置为 JDBC 连接字符串。

如果 {siteNameShort} 可以使用 JNDI 数据源或 `APP_DB` 连接字符串连接到数据库，那么它将使用该数据库作为应用程序数据库。

### 应用程序数据目录

{siteNameShort} 将所有配置数据和应用程序数据存储在磁盘上一个名为数据目录的文件夹中。使用集群时，{siteNameShort} 的每个实例都应该配置为使用同一个数据目录。这确保了所有实例处理相同的文件并使用相同的配置。

#### .NET 版本

在 .NET 版本中配置应用程序数据目录，必须将 `AppDirectory` 环境变量设置为应创建目录的路径。为此，请修改安装目录 www 文件夹中的 `Web.Config` 文件。在此文件中有一个被注释掉的名为 *AppDirectory* 的 XML 元素，其下方有一个名为 *appSettings* 的元素，可以在其中指定自定义数据目录位置：

```xml theme={null}
<!-- appSettings>
 <add key="AppDirectory" value="C:\\directory\\subdirectory\\subdirectory\\" />
</appSettings -->
```

取消 *appSettings* 元素的注释，将 `AppDirectory` 键值设置为磁盘上数据目录的适当路径。如果 {siteNameShort} 可以找到该路径，并且在给定路径上具有适当的读写权限，它将在指定目录中创建数据文件夹。

#### 内置 Java 服务器

将跨平台版本与内置 Jetty 服务器一起使用时，应用程序数据目录在安装目录 webapp 文件夹中的 `arc.xml` 文件中配置。在此服务器配置文件中，必须将 `AppDirectory` 环境变量设置为所需目录的路径。以下示例演示了将数据目录设置为已挂载驱动器上的共享文件夹时的情况：

```xml theme={null}
<Call name="setInitParameter">
 <Arg>AppDirectory</Arg>
 <Arg>/mnt/shared/arc</Arg>
</Call>
```

如果 {siteNameShort} 可以找到该路径，并且在给定路径上具有适当的读写权限，它将在指定目录中创建数据文件夹。

#### 外部 Java 服务器

将跨平台版本与外部 Java servlet（应用程序内置 Jetty 服务器以外的任何服务器）一起使用时，配置应用程序数据目录的细节取决于所使用的特定 servlet。使用适用于特定 servlet 的语法，必须将 `AppDirectory` 环境变量设置为所需目录的路径。

如果 {siteNameShort} 可以找到 `AppDirectory` 路径，并且在给定路径上具有适当的读写权限，它将在指定目录中创建数据文件夹。

### 锁与并发

{siteNameShort} 使用锁来确保多个实例不会相互干扰或两次处理同一个文件。在集群环境中，有效的锁定对于保持吞吐量和防止冲突至关重要。因此，强烈建议不要跨多个服务器场对 {siteNameShort} 实例进行集群，因为这样可能会产生文件系统延迟。

为 {siteNameShort} 的每个实例设置一个共享的应用程序目录足以确保每个实例都遵守文件锁。

### 配置反向代理

反向代理是位于客户端和后端服务器之间的服务器，用于拦截传入流量并将其转发到适当的目的地。配置得当时，反向代理可以通过请求头转发保留真实的客户端 IP 地址，同时保护后端基础设施免于直接暴露。这种架构提供了负载均衡、增强安全性、缓存和 SSL 终结等优势。

当反向代理通过 `X-Forwarded-For` 等请求头转发客户端信息时，限制受信任的代理至关重要。如果未明确仅信任已知的代理 IP 地址，恶意用户可能会伪造这些请求头来欺骗其来源，从而可能绕过安全控制或日志记录机制。

#### 跨平台版（Cross-Platform Edition）

要在跨平台版中配置反向代理，请将 `arc.properties` 文件中的 [proxyMode](../installation/arc-properties-configuration#cdata-http-proxymode) 设置为 true，如下字符串所示：`cdata.http.proxyMode=true`。

当 `proxyMode=true` 时，内嵌的 Jetty 服务器将使用 `ForwardedRequestCustomizer` 从转发的请求头中提取并应用真实的客户端 IP。

如果使用外部 Java Servlet 容器，请在 Servlet 级别配置请求重写，以适当地处理转发的请求头。

#### .NET 版

要在 .NET 版中配置反向代理，必须在 **安全性** 页面的 [代理设置](./settings/proxy-settings) 部分的 **HTTP 转发请求头** 字段中，提供一个以逗号分隔的列表，包含应用程序应用于确定客户端 IP 地址的请求头名称。

#### 示例：使用 nginx 代理设置反向代理

确保客户端无法欺骗用于转发 IP 地址的请求头是代理服务器的责任。以下示例说明了包含反向代理设置的代理配置。

```
location /arc/ {
  proxy_pass http://localhost:8080/;
  proxy_set_header Host              $host;
  proxy_set_header Referer           $http_referer;
  proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
  proxy_set_header X-Forwarded-Proto $scheme;
  proxy_set_header X-Forwarded-Port  $server_port;
  proxy_set_header X-NginX-Proxy     true;
  proxy_redirect http://localhost:8008/ http://$host:8008/arc/;
}
  # Declare all trusted IP or CIDR
  set_real_ip_from 192.168.1.100;
  set_real_ip_from 10.0.0.0/8;

  # Define the request header field whose value will be used to replace the client address
  real_ip_header X-Forwarded-For;

  # Enable recursive resolution to skip all trusted proxy IPs from X-Forwarded-For
  real_ip_recursive on
  
  # Optionally, set the real client IP to a new header
  Jetty_Forwarded-For: $remote_addr
```

此配置通过仅明确信任指定的代理 IP（192.168.1.100 和 10.0.0.0/8）来防止请求头欺骗。如果恶意用户伪造了 `X-Forwarded-For` 请求头，nginx 将忽略它，并使用通过受信任代理进入的、最接近客户端的 IP。
