> ## 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 companyName = "知行软件";

export const siteNameShort = "知行之桥";

export const siteName = "知行之桥";

{siteName} 是一个用于集成业务流程的消息驱动平台。它提供了一个集中的通信中心，使应用程序、数据库和外部消息系统能够相互通信。

## 设计原则与实现

{siteNameShort} 的架构决策源于一套核心设计原则。本节重点介绍 {siteNameShort} 设计的三个方面：

* 优先考虑的原则和价值
* 深入理解 {siteNameShort} 所需的核心概念
* 架构决策及其如何符合设计原则

[核心原则](#核心原则)和[概念](#概念)部分适用于技术和非技术用户。其余实现部分旨在帮助工程师了解如何利用 {siteNameShort} 架构。

### 核心原则

下图展示了 {siteNameShort} 设计的核心原则：

<img src="https://mintcdn.com/qiao/U-KEZ9JbQY4Wqs1D/public/images/architecture_core_principles.png?fit=max&auto=format&n=U-KEZ9JbQY4Wqs1D&q=85&s=1a87ce1b29416b51c7b9d4b5286c8398" alt="Core principles diagram" width="600" data-path="public/images/architecture_core_principles.png" />

{siteNameShort} 架构并不是在集成平台中实现上述设计原则的唯一方式。以下是对实现选择及其如何符合设计原则的说明。

## 概念

从高层看，{siteNameShort} 的实现由三个元素组成：

* 工作流 (Flows)
* 端口 (Connectors)
* 消息 (Messages)

下图展示了这些元素之间的关系：

<img src="https://mintcdn.com/qiao/U-KEZ9JbQY4Wqs1D/public/images/architecture_data_processing.png?fit=max&auto=format&n=U-KEZ9JbQY4Wqs1D&q=85&s=0a12dfc757ac09eae98d2aaf0867b03d" alt="Data processing relationships" width="800" data-path="public/images/architecture_data_processing.png" />

### 工作流 (Flows)

{siteNameShort} [工作流](/26.2/self-hosted/zh/flows)是配置好的工作流程，用于执行一组自动化的数据处理任务。工作流由多个端口组成，这些端口相互连接，使一个端口处理的数据会自动传递给工作流中的下一个端口。

在 UI 中，工作流位于**工作流**页面的工作区内。端口被添加到空白画布上，并在此进行配置和相互连接。下图展示了一个由两个端口（AS2 和 File）组成的简单工作流。

<img src="https://mintcdn.com/qiao/U-KEZ9JbQY4Wqs1D/public/images/architecture_flow.png?fit=max&auto=format&n=U-KEZ9JbQY4Wqs1D&q=85&s=11034f807db5a81d8b217255fb8362e5" alt="Simple flow with two connectors" width="800" data-path="public/images/architecture_flow.png" />

端口之间的蓝色箭头表示 AS2 端口接收的数据会自动传递给 File 端口。通过将一个端口右侧的蓝点拖动到另一个端口的左侧，即可建立这种关系。

工作流中的一系列端口建立了逻辑数据处理链，因此工作流的设计应旨在完成特定的业务任务。这些任务的复杂度各不相同，从简单下载文件到根据接收到的业务单据同步多个后端应用程序。

可以在 {siteNameShort} 中配置多个工作流来完成不同的任务。除非通过蓝色工作流箭头显式连接，否则工作流之间相互独立。

### 端口 (Connectors)

[端口](/26.2/self-hosted/zh/connectors)是工作流的单个构建块，作用于应用程序数据或消息。每个端口对消息执行特定操作，并将其传递给工作流中的下一个端口，或传递给外部对象（如 FTP 目的地）。

操作主要分为三类：触发 (Trigger)、转换 (Transform) 和终结 (Terminal)。

* 触发端口通过**接收自动化**拉取或创建文件来启动工作流；对于支持被动接收的端口，则是在端口从外部客户端接收文件时启动。示例包括 [AS2](/26.2/self-hosted/zh/connectors/as2)、[Email Receive](/26.2/self-hosted/zh/connectors/email-receive) 或 [SFTP](/26.2/self-hosted/zh/connectors/sftp)。
* 转换端口位于工作流中间，负责对消息执行操作（以某种方式对其进行修改）。示例包括 [X12](/26.2/self-hosted/zh/connectors/x12)、[XML Map](/26.2/self-hosted/zh/connectors/xml-map/xml-map) 或 [CSV](/26.2/self-hosted/zh/connectors/csv)。
* 终结端口是工作流的终点，此时 {siteNameShort} 将消息移交给底层磁盘，或者消息在端口执行发送操作期间被消耗且不生成输出。示例包括 [File](/26.2/self-hosted/zh/connectors/file)、[MySQL](/26.2/self-hosted/zh/connectors/mysql/mysql)，或任何配置为 Upsert 的数据库端口。

端口每次执行上述操作之一时，都在处理一个*事务*。

在**工作流**页面的工作区中，将端口添加到画布时，其配置设置面板会打开：

<img src="https://mintcdn.com/qiao/U-KEZ9JbQY4Wqs1D/public/images/architecture_connector.png?fit=max&auto=format&n=U-KEZ9JbQY4Wqs1D&q=85&s=2ce3075a236ce6afbd6d729163bd67de" alt="Connector configuration panel" width="800" data-path="public/images/architecture_connector.png" />

端口根据其类型（AS2、SQL Server、XML 等）具有不同的配置设置集。

某些端口（如 AS2 和 SFTP）既可以从外部对象或服务器接收数据，也可以将数据发送到外部对象或服务器（或两者兼有）。这些端口通常位于工作流的开始或结束，因为这是数据进入或离开应用程序的位置。

其他端口（如 XML Map 和 X12）在应用程序本地处理数据。这些端口通常位于工作流的中间，因为它们只能从其他端口接收数据（不能从外部源接收），并且只能将数据发送到其他端口（不能发送到外部目的地）。

### 消息 (Messages)

当数据在工作流中的端口之间传递时，它以消息的形式传递。消息主要由文件有效载荷数据（{siteNameShort} 正在处理的数据）和元数据（{siteNameShort} 用于跟踪应用程序中数据流向的信息）组成。

消息在[消息实现](#消息实现)中有更详细的解释，但高层核心点是：消息是标准 RFC822（互联网消息）格式的文件。当一个端口将数据传递给工作流中的另一个端口时，它将数据写入文件，然后将该文件传递给下游的下一个端口，如下图所示。

<img src="https://mintcdn.com/qiao/U-KEZ9JbQY4Wqs1D/public/images/architecture_message_flow.png?fit=max&auto=format&n=U-KEZ9JbQY4Wqs1D&q=85&s=ccdeee4fedf069d7544aec25dc7d94eb" alt="Message flow between connectors" width="800" data-path="public/images/architecture_message_flow.png" />

在工作流的每个步骤中，消息（文件）通过触发端口被接收或下载到应用程序中，通过转换端口在应用程序本地进行转换，或者通过终结端口被发送或上传出应用程序。这些操作中的每一个都称为一个*事务*。

{siteNameShort} 是透明的：可以通过查看文件系统、观察消息如何从一个文件夹复制到另一个文件夹，以及使用常规文本编辑器或其他工具查看消息内容，来观察平台内部发生的情况。

## 实现概述

本节提供有关 {siteNameShort} 对上述核心概念（[工作流](#工作流-flows)、[端口](#端口-connectors)和[消息](#消息-messages)）实现的技术细节，并解释为什么这种实现满足我们的[核心原则](#核心原则)。

#### 基于文件的架构

{siteNameShort} 将所有数据存储在文件系统的文件中，因此应用程序中的所有内容都会持久化到磁盘。例如：

* 应用程序数据（消息）
* 配置数据（[个人设置](./administration/profiles)和工作流）
* 日志（详见[日志](./administration/activity)）

配置好的工作流中的端口从**交易选项卡**读取和写入文件（消息）。当数据从一个端口传递到下一个端口时，这些消息文件将从第一个端口的 Receive 文件夹移动到下一个端口的 Send 文件夹。

{siteNameShort} 在这种基于文件系统的基础架构之上提供了 Web UI，以便轻松构建和配置工作流。{siteNameShort} 的 [Admin API](/26.2/self-hosted/zh/admin-api) 和 UI 是管理配置的推荐方法。这些方法会直接修改磁盘上的配置文件。基于文件的架构还使 {siteNameShort} 易于与基础设施即代码 (IaC) 工具和 Git 等版本控制系统集成。有关如何将 Git 与 {siteNameShort} 集成的更多信息，请参阅 <a href="https://arc.cdata.com/kb/articles/arc-git.rst" target="_blank">将 Git 与 {siteName} 结合使用</a>。

## 消息实现

{siteNameShort} 中的消息是磁盘上的简单文件，包含应用程序处理的原始数据。消息由两部分组成：

* 正文：应用程序数据有效载荷
* 标头：消息元数据

标头和正文的组合存储在符合 RFC2822 标准且扩展名为 `.eml` 的文件中，可以使用任何标准文本编辑器或邮件客户端打开。标头是由 `newline` 字符分隔的 `name: value` 标头简单列表，正文通过两个 `newline` 字符与标头分隔。

<Warning>为确保 {siteNameShort} 运行可靠，请勿在应用程序运行时直接与这些文件交互。外部程序对这些文件加锁可能会导致性能和可靠性问题。</Warning>

### 消息正文

消息正文或有效载荷是应用程序处理的实际文件数据。这是从远程源接收、由转换端口处理的数据等。虽然消息标头主要由 {siteNameShort} 用于跟踪消息，但消息有效载荷包含了用户最关心的数据。

接收数据时，{siteNameShort} 会生成一条消息（在磁盘上写入一个新的消息文件），并将传入的数据作为消息正文。例如，当 SFTP 端口从远程服务器下载文件时，该远程文件的内容将成为新消息的正文。

当数据在应用程序本地处理时（例如将 EDI 翻译为 XML，或将文件映射到新格式），执行操作的端口读取输入消息的正文，在内存中处理数据，并将结果写入输出消息的正文。

当数据离开应用程序时（例如上传文件到远程服务器、发送文件给伙伴或插入数据库），仅发送输入消息的正文。

### 消息标头

消息标头帮助 {siteNameShort} 跟踪数据在应用程序中的进度。标头包括唯一的 MessageId（帮助 {siteNameShort} 了解消息的完整生命周期，即使文件名被更改）、端口处理消息时的时间戳、处理过程中可能发生的任何错误以及其他元数据。

标头以 *headerName: headerValue* 语法列在消息顶部，由换行符分隔。将鼠标悬停在消息上并点击**查看详情**，可以显示其关联的标头，并允许下载消息文件内容。

消息标头还用于存储 {siteNameShort} 在工作流中需要了解的各种辅助值。例如，从远程 FTP 服务器的子文件夹下载文件时，{siteNameShort} 使用[子文件夹标头](/26.2/self-hosted/zh/connectors/ftp#subfolder-headers)来跟踪消息的文件夹路径，以便在本地系统上需要重建此文件夹路径时使用。

{siteNameShort} 为原始数据文件增补了描述应用程序如何处理该文件的元数据。以下是一些最常见的标头：

* 唯一且持久的 MessageId，在整个工作流中标识该文件
* 文件被处理的时间戳
* 处理该文件的任何端口的 ConnectorId
* 任何由于错误导致文件处理失败的记录

应用程序永远不会编辑或覆盖消息标头。新的标头总是附加到现有列表的末尾，以便保留完整的处理历史。

### 工作流中的消息

虽然 {siteNameShort} 在内部使用消息标头来跟踪和理解应用程序处理的数据，但除非检查消息，否则会对用户隐藏这些细节。例如，{siteNameShort} 使用内部 MessageId 来标识消息，但在**交易选项卡**和**消息**页面上显示公共文件名。

要检查消息上的标头，请悬停在消息上并选择**查看消息详情**。下图显示了**交易选项卡**上的消息。

<img src="https://mintcdn.com/qiao/U-KEZ9JbQY4Wqs1D/public/images/architecture_headers.png?fit=max&auto=format&n=U-KEZ9JbQY4Wqs1D&q=85&s=8aef9c105fba5b0adb9c6edbaa2dee88" alt="Messages on the Transactions tab" width="800" data-path="public/images/architecture_headers.png" />

无论消息处于工作流的哪个位置，当消息被写入端口的内部 Receive 文件夹时，{siteNameShort} 都会以 `.eml` 格式存储。但是，当消息发送到外部系统（例如数据库或 SFTP 服务器）时，{siteNameShort} 仅上传文件内容，不包括 `.eml` 标头。同样，在使用 [File 端口](/26.2/self-hosted/zh/connectors/file)的发送操作将文件写入磁盘时，{siteNameShort} 会省略 `.eml` 结构，以便输出符合外部程序的预期。换句话说，`.eml` 标头是 {siteNameShort} 内部文件格式的一部分，但在向外部目的地交付数据时不被包含。

### 批量组和批量消息

消息可以包含多个有效载荷，在这种情况下，它们被视为*批量组*。批量组中的每个单独有效载荷被视为一条*批量消息*，如下图所示。

<img src="https://mintcdn.com/qiao/U-KEZ9JbQY4Wqs1D/public/images/architecture_batch_processing.png?fit=max&auto=format&n=U-KEZ9JbQY4Wqs1D&q=85&s=b481fddf1b4476226458522385b25d41" alt="Batch groups and batch messages" width="800" data-path="public/images/architecture_batch_processing.png" />

#### 批量组

消息可以分批组成批量组，以提高性能并使大型消息组更易于管理。批量组是 MIME 格式的文件，其中每个 MIME 部分是一条单独的批量消息。批量组使用与基本消息相同的标头方案维护有关批次的元数据。这些标头跟踪整个批次的处理，而不是批次的各个部分。

#### 批量消息

批量组中的每条批量消息都是一个包含应用程序处理的文件有效载荷数据的 MIME 部分。每条批量消息都包含与有效载荷（而非批量组）关联的元数据。批量消息具有多组元数据：一组标头用于跟踪整个批量组，另一组单独的标头用于跟踪批次中的每条消息。

### 访问和查看消息

由于消息只是磁盘上的简单文件，用户和外部系统可以访问和查看当前处于 {siteNameShort} 管道中的消息。要使用外部应用程序访问消息，需要了解在文件系统的何处查找消息 `.eml` 文件。请参阅[文件夹层级](#文件夹层级)了解消息文件的确切位置。

<Warning>为确保 {siteNameShort} 运行可靠，请勿在应用程序运行时直接与消息文件交互。外部程序对这些文件加锁可能会导致性能和可靠性问题。</Warning>

也可以在 {siteNameShort} UI 和 {siteNameShort} [Admin API](/26.2/self-hosted/zh/admin-api) 中查看消息。消息显示在处理过该消息的任何端口的**交易选项卡**中，以及[日志](./administration/activity)页面上。点击**查看详情**打开**消息信息**页面：

<img src="https://mintcdn.com/qiao/U-KEZ9JbQY4Wqs1D/public/images/architecture_message_headers.png?fit=max&auto=format&n=U-KEZ9JbQY4Wqs1D&q=85&s=86c8e11c0c2484d57c6ee2f3a4f10ad2" alt="Message Information panel showing headers" width="800" data-path="public/images/architecture_message_headers.png" />

此面板中显示的值是消息标头。点击**下载**按钮访问消息正文。点击**下载日志**下载与消息关联的[日志](#消息跟踪与日志)。

### 消息跟踪与日志

消息包含一个 MessageId 标头，作为消息的唯一标识符。当文件通过工作流时，即使文件本身被重命名，该 MessageId 仍保持不变。因此，可以通过参考其 MessageId 来追踪任何文件在整个工作流中的进度。该值还允许用户查找与特定事务关联的日志数据。

{siteNameShort} 以两种格式存储日志数据：

* [应用程序数据库](#应用程序数据库)
* 磁盘上的[详细日志文件](#详细日志文件)

这些格式及其关系详见下文。

#### 应用程序数据库

\_应用程序数据库\_是一个关系型数据库，{siteNameShort} 用它来：

* 存储有关应用程序处理的每个事务的元数据
* 存储不属于任何特定事务的应用程序操作日志
* 存储某些端口的状态（例如，当端口正在等待确认或回执时）

{siteNameShort} 捆绑了 SQLite (Windows/.NET) 或 H2 (Java) 数据库，但也可以配置为使用外部数据库，如 SQL Server、PostgreSQL 或 MySQL。{siteNameShort} 负责处理应用程序数据库中所有相关表的创建和维护。

要使用外部数据库，必须在托管应用程序的服务器配置文件中配置数据库连接字符串（请参阅 [.NET 版](./installation/windows-edition)中的[配置应用程序数据库](./installation/windows-edition#configuring-the-application-database)，以及[跨平台版](./installation/cross-platform-edition) `arc.properties` 文件中的 [cdataappdb](./installation/arc-properties-configuration#cdata-app-db) 设置）。

应用程序数据库中有一个表用于跟踪消息并查找日志。它存储应用程序处理的每个事务的元数据，元数据包括所处理消息的 MessageId。使用 UI 中的**日志**页面查找消息和事务日志。可以在**日志**页面上搜索事务元数据（如时间戳、ConnectorId 和状态）。为了最大限度地减少数据库占用空间，详细日志数据不包含在**日志**页面中，而是存储在磁盘上的日志文件中。

#### 详细日志文件

每当 {siteNameShort} 处理一条消息时，它都会生成一个与 MessageId 同名的日志文件夹。此文件夹包含详细日志文件，具体日志内容取决于发送和/或接收文件的端口类型。例如，AS2 端口除了记录代表消息本身的 `.eml` 文件外，还会记录 MDN 回执、原始请求和响应以及连接日志。

这些日志文件对于仅在工作流中跟踪消息并非必需；存储在应用程序数据库中的元数据足以跟踪消息。但是，为了查找有关特定事务的详细信息（特别是在调试时），需要根据消息的 MessageId 和处理该消息的端口在磁盘上找到相应的文件。

用户在知道 MessageId 后可以手动导航到磁盘上相应的日志文件夹；但是，使用应用程序数据库查找这些详细日志文件通常更方便。详情请参阅[应用程序数据库与日志文件之间的关系](#应用程序数据库与日志文件之间的关系)。

#### 应用程序数据库与日志文件之间的关系

存储在应用程序数据库中的元数据包含了查找与特定事务关联的日志文件所需的所有信息。{siteNameShort} UI 和 [Admin API](/26.2/self-hosted/zh/admin-api) 利用这种关系来提供对任何事务日志文件的便捷访问。

* **日志**页面包含所有事务元数据。悬停在任何事务条目上并点击**查看详情**以访问关联的日志文件；在底层，{siteNameShort} 正在使用 MessageId 查找磁盘上相应的日志文件。

* 同样，端口配置面板上的**交易选项卡**提供了访问由该特定端口处理的任何事务的入口。展开这些事务以查看和下载详细日志文件。

* 应用程序数据库对于手动导航到存放事务日志文件的相应文件夹也很有帮助。通常，用户知道事务的文件名但不知道内部 MessageId。**日志**页面上的**消息**页面是可搜索的，因此搜索特定文件名会显示与该文件名关联的任何事务的 MessageId。有关知道 MessageId 和端口后如何查找日志文件夹的更多信息，请参阅[文件夹层级](#文件夹层级)。

### 消息实现背后的设计决策

我们希望应用程序数据对用户和外部系统保持透明，因此消息是通过文件系统上的简单数据文件传递的，而不是通过不透明的内部数据通道。因此，{siteNameShort} 不是一个在处理过程中隐藏数据的黑匣子。这意味着 {siteNameShort} 可以有效地嵌入到任何从文件系统特定文件夹提取或放置文件的系统中。

我们还希望无需专门的工具或程序即可访问消息。消息存储在符合 RFC2822 标准的文件中，因此任何文本编辑器都可以打开该文件。由于消息具有 `.eml` 扩展名，双击文件即可打开消息并在系统默认邮件客户端中显示其内容。

为了使消息和日志可访问且透明，我们提供了一个可搜索的事务元数据数据库。此数据库可用于直接访问消息有效载荷和详细日志文件，同时保持较小的数据库占用空间。

## 端口实现

端口代表[工作流](/26.2/self-hosted/zh/flows)中的一个步骤。复杂的工作流是通过将多组端口连接在一起来执行逻辑数据处理链而创建的。

端口执行三种类型的操作：

* 接收数据并写入输出消息（例如通过 SFTP 下载远程文件）
* 读取输入消息并将数据发送给外部对象（例如通过 AS2 发送文件）
* 读取输入消息，在本地进行处理，并写入输出消息（例如将 EDI 文件翻译为 XML）

大多数端口可以执行前两个操作（向远程端点发送数据和从远程端点接收数据）或最后一个操作（在本地转换数据）。端口执行的每个操作都称为一个\_事务\_。

端口从**交易选项卡**读取和写入输入和输出消息。当端口在工作流中连接时，{siteNameShort} 会自动将消息从第一个端口的**交易选项卡**移动到下一个端口的**交易选项卡**文件夹。（在磁盘上，输入文件夹标记为 Send，输出文件夹标记为 Receive。）

### 端口文件和文件夹

端口的每个实例在磁盘上都作为一个以 ConnectorId（工作流中的显示名称）命名的单个文件夹存在。每个端口文件夹包含以下内容：

* 包含配置设置的 [port.cfg](#port-cfg) 文件
* [Send](#输入消息) 子文件夹中待发送或处理的消息（如输入消息）
* [Receive](#输出消息) 子文件夹中已接收的消息（如输出消息）
* 由端口处理的消息的[日志文件](#日志文件)
* [端口特定文件](#其他配置文件)，如映射、模板和脚本

以下部分解释了这些文件夹内容在应用程序中的功能。[文件夹层级](#文件夹层级)解释了端口文件夹及其子文件夹的确切位置。

#### Port.cfg

每个端口的 `port.cfg` 文件包含管理端口行为的设置（出现在端口**设置**和**高级**选项卡中的设置）。该文件为 INI 格式：端口设置以 `SettingName = SettingValue` 语法列出，每行一个设置。在 UI 中编辑端口设置在功能上等同于直接在 `port.cfg` 文件中编辑设置。

`port.cfg` 文件支持\_间接值\_，这意味着设置可以使用引用而不是字符串字面量。这在概念上类似于在应用程序的其他部分设置变量，并在 `port.cfg` 文件中引用该变量名。有关如何设置间接值的详细信息，请参阅[数据目录](#数据目录)。

#### 输入消息

**交易选项卡**文件夹存放输入消息，即排队等待端口处理的消息。

在每个时钟滴答（默认每半秒）处，{siteNameShort} 检查每个端口的 Send 文件夹是否有更改，并向任何有可用消息的端口分派工作线程。处理消息时，{siteNameShort} 会向该消息附加一个包含处理尝试时间戳的标头。

{siteNameShort} 根据最后修改时间对输入消息进行排序，以便优先处理较旧的文件。由于 {siteNameShort} 在每次尝试期间都会附加标头，这确保了导致错误的消息不会因重复重试而不必要地阻塞端口。

请注意，端口必须启用 *Send* 自动化，才能在每个时钟滴答处处理输入消息。

#### 输出消息

Receive 文件夹存放输出消息，即已被端口接收、下载和/或处理的消息。

某些端口在完成输入消息处理后立即写入输出消息（例如翻译数据格式的端口）。其他端口在未先读取输入消息的情况下写入输出消息。示例包括轮询远程服务器以下载文件的 SFTP 端口，以及被动监听传入文件的 AS2 端口。

当端口在工作流中连接到另一个端口时，输出消息不会留在 Receive 文件夹中。它们会被传递到下一个端口的 Send 文件夹。

#### 日志文件

端口处理的每个事务都会生成一组日志文件。有关事务的元数据会被添加到日志中，[详细日志](#详细日志文件)信息以文件形式存储在磁盘上。日志文件始终包含 `.eml` 格式的消息本身以及任何端口特定的日志文件。

默认情况下，所有端口日志文件按周组织在文件夹中，如下面的文件夹结构所示：

<img src="https://mintcdn.com/qiao/U-KEZ9JbQY4Wqs1D/public/images/architecture_logs_folder_hierarchy.png?fit=max&auto=format&n=U-KEZ9JbQY4Wqs1D&q=85&s=57e58a4fb885a3539eadd90f41a7faee" alt="Log folder hierarchy" width="400" data-path="public/images/architecture_logs_folder_hierarchy.png" />

要更改默认的每周文件夹组织方式，请将任何端口的**日志子文件夹方案**字段设置为不同的时间间隔（如\_每日\_或\_每月\_）。这意味着在该时间间隔内生成的所有日志都存放在一个子文件夹中。这可以通过减少单个子文件夹的大小来提高磁盘 I/O 性能。

可以使用[消息选项卡](./administration/activity#messages-tab)查找相应的日志文件夹，可以通过查找 MessageId 或使用**下载日志**。

#### 已发送文件

除了详细日志文件外，端口还在 Sent 文件夹中保留所有成功发送和处理的消息的数据有效载荷副本（处理不成功的消息不会被添加）。文件根据生成时间命名，并按周组织在文件夹中。要更改默认的每周文件夹组织方式，请将任何端口的**已发送文件夹方案**字段设置为不同的时间间隔（如\_每日\_或\_每月\_）。这意味着在该时间间隔内生成的所有文件都存放在一个子文件夹中。这可以通过减少单个子文件夹的大小来提高磁盘 I/O 性能。

<Note>此 Sent 文件夹是端口文件夹的直接子文件夹，与上述 Logs 文件夹中的 Sent 文件夹不同。</Note>

#### 其他配置文件

根据端口类型，某些端口文件夹包含其他配置文件。这些额外文件包括：

* `map.json`
* `script.rsb`
* 模板 XML 文件

这些文件存储映射关系、自定义脚本行为以及端口输入和输出的结构。手动编辑这些文件等同于编辑相关的端口 UI 设置。

<Warning>手动编辑这些文件可能存在风险。虽然布局易于理解且透明，但不正确地修改这些配置文件可能会导致意外后果。</Warning>

### 端口实现背后的设计决策

我们希望工作流完全模块化，这意味着每个端口都应以可预测且直观的方式提供直接的功能。{siteNameShort} 执行复杂任务的能力来自于组合任意端口集的能力，而端口接口保持简单。由于端口链被分解为离散的步骤，复杂的工作流仍然易于理解。

我们希望与端口相关的所有数据（配置数据、应用程序数据、日志数据等）都易于访问。因为数据都存储在特定于端口的文件夹中，访问数据只需知道在何处找到该文件夹即可。配置数据以透明的 INI 格式存储，因此它与消息数据一样，可以使用简单的工具轻松查看和编辑。

这种基于文件夹的端口方法还使理解数据如何在端口之间传递变得容易：对消息文件进行简单的文件移动操作，即可将一个端口的输出变为另一个端口的输入。{siteNameShort} 包含内置工具来自动建立这些文件移动关系。

<Warning>为确保 {siteNameShort} 运行可靠，请勿在应用程序运行时直接与任何配置文件交互。外部程序对这些文件加锁可能会导致性能和可靠性问题。</Warning>

## 工作流和工作区实现

[工作流](/26.2/self-hosted/zh/flows)在文件系统上由一个 `flow.json` 文件表示，该文件包含工作流中每个端口的位置和连接关系。有关此文件的位置，请参阅[文件夹层级](#文件夹层级)。

工作流中端口的位置纯粹是装饰性的，仅在 UI 中配置工作流时使用。端口之间的连接在数据处理级别是相关的：端口写入输出消息后，它会查询应用程序引擎以查看是否需要将输出消息传递给另一个端口的 Send 文件夹。应用程序使用 `flow.json` 文件来确定将文件交给哪个端口（如果有）。

可以在同一个工作流画布上配置多个工作流，{siteNameShort} UI 允许拖动画布在工作流之间导航。这类似于在线导航地理地图（如 Google Maps）。

[工作区](/26.2/self-hosted/zh/flows/workspaces)提供了工作流之间的逻辑分离。每个工作区提供一个新的画布，用于在其中将端口配置为逻辑工作流。延续 Google Maps 的类比，工作区相当于独立的\_星球\_。

按交易伙伴或集成项目分离工作区是常见的做法。然而，是否在独立的工作区配置新工作流取决于个人偏好。有关更多信息，请参阅[将工作流组织到工作区中](/26.2/self-hosted/zh/flows/designing-a-flow#organize-flows-into-workspaces)。

#### 文件系统上的工作区

引入新的（非默认）工作区时，{siteNameShort} 会在文件夹层级中添加一组新文件夹。`workspaces` 目录包含在非默认工作区中配置的所有端口的文件夹。`workspaces` 文件夹是[数据目录](#数据目录)的同级文件夹。

### 工作流和工作区背后的设计决策

我们认为，保持工作流中端口之间简单模块化关系的最好方法是将工作流视为纯粹的逻辑概念。确定逻辑数据处理序列所需的所有信息都已包含在端口实现中。

我们希望工作区能够提供在更实质层面上分离端口的能力。独立的工作区使用独立的文件夹来存放端口，以便文件系统级别的操作（如权限和目录列表）可以轻松地与特定工作区隔离。

## 文件夹层级

由于所有 {siteNameShort} 资源都可在文件系统上访问，从底层理解 {siteNameShort} 需要学习应用程序的文件夹结构以及文件和文件夹在磁盘上的组织方式。

为了理解该层级，查看 {siteNameShort} 安装的目录视图会很有帮助。以下是文件夹结构的视觉呈现。结构的详细信息将在以下部分中解释。

<img src="https://mintcdn.com/qiao/U-KEZ9JbQY4Wqs1D/public/images/architecture_folder_hierarchy.png?fit=max&auto=format&n=U-KEZ9JbQY4Wqs1D&q=85&s=02191726cb97e29de91ffab1c612deb5" alt="Folder hierarchy" width="400" data-path="public/images/architecture_folder_hierarchy.png" />

<Note>
  * 此层级结构假设工作流仅在默认工作区中配置。有关其他工作区的详细信息，请参阅[工作流和工作区](#工作流和工作区实现)。
  * 如果**设置 > 高级**页面的[清理设置](./administration/settings/cleanup-settings)部分中的**本地存档文件夹**为空，则每个端口还包含一个 **Archive** 文件夹。
</Note>

### 根安装目录

所有 {siteNameShort} 资源都在安装目录中，默认位置如下：

* **Windows**: `C:\Program Files\CData\CData Arc`
* **Linux**: `/opt/arc`

对于 Java 版安装，{companyName} 提供了一个 zip 文件，可以将其解压到选择的安装目录（例如 `/opt/arc`）。

当 Java 版 {siteNameShort} 托管在 Tomcat 等外部 Java Servlet 上时，{siteNameShort} 资源驻留在 `~/cdata/arc` 中。在此路径中，`~` 解析为托管 Java Servlet 的用户的家目录。

在上面的[文件夹层级](#文件夹层级)中，根安装目录是树顶部的 `Arc` 文件夹。

### 数据目录

`data` 目录包含以下内容：

* 为在[工作流](/26.2/self-hosted/zh/flows)页面上配置的每个端口（在默认工作区中）准备的一个子文件夹
* 一个 [profile.cfg](#profile-cfg) 文件
* 一个 [flow.json](#flow-json) 文件
* 一个 [roles.json](#roles-json) 文件
* 一个 [settings.json](#settings-json) 文件
* 一个 [users.json](#users-json) 文件
* 所有[证书](#证书)文件

#### Profile.cfg

`profile.cfg` 文件包含应用程序范围的设置，例如配置的本地[个人设置](./administration/profiles)（例如 AS2 个人设置）。该文件为 INI 格式：应用程序设置以 `SettingName = SettingValue` 语法列出，每行一个设置。

`profile.cfg` 设置分为若干部分：用于常规应用程序设置的 `Application` 部分，以及为每个个人设置准备的专用部分（例如，AS2 个人设置有一个 `AS2` 部分，本地 SFTP Server 设置有一个 `SFTPServer` 部分）。

在 UI 的**个人设置**页面上编辑应用程序设置在功能上等同于直接在 `profile.cfg` 文件中编辑设置。

#### Flow\.json

`flow.json` 文件包含已配置工作流的结构：每个端口实例的位置和连接关系。直接编辑 `flow.json` 与在**工作流**页面上移动或重新连接端口的效果相同。

#### Roles.json

`roles.json` 文件包含与所有自定义[用户角色](./administration/settings/user-roles#user-roles)相关的详细信息。直接编辑 `roles.json` 与在**角色**页面上添加和配置角色的效果相同。

#### Settings.json

`settings.json` 文件包含一系列设置，可以通过使用引用名称而非具体值在应用程序的其他位置引用这些设置。这使得能够以不在应用程序中显示的方式存储安全值（如密码）。还可以使用引用名称来集中配置跨多个实例部署的工作流。

支持这种集中引用语法的设置在 UI 中有一个钥匙图标，可以点击它来查看 `settings.json` 文件中定义的引用列表。有关更多信息，请参阅[全局设置库](./administration/settings/global-settings-vault)。

#### Users.json

`users.json` 文件包含与所有 {siteNameShort} [用户](./administration/settings/user-roles#users)相关的详细信息。直接编辑 `users.json` 与在**用户**页面上添加或编辑用户的效果相同。

#### 证书

在应用程序中创建或上传的所有证书都存储在 `data` 目录中。通常，证书以公钥/私钥对的形式出现，文件名相同但文件扩展名不同：`.pfx` 为私钥，`.cer` 为公钥。上传到应用程序的其他格式证书会按原样存储。

{siteNameShort} 枚举 `data` 目录中的证书，以确定在 UI 中配置证书时的可用选项。将证书文件添加到 `data` 目录与在 UI 中上传证书的效果相同。

### 端口文件夹

每个配置的端口实例在 `data` 目录中都有一个专用文件夹。文件夹名称与工作流中每个端口的 ConnectorId 值（显示名称）匹配。在上述示例文件夹结构中，两个配置的端口是 AS2\_Amazon 和 Database\_MySQL。

端口文件夹的内容在[端口文件和文件夹](#端口文件和文件夹)中进行了说明。以下是端口文件夹中子文件夹结构的概述：

* Logs：由端口处理的每条消息的详细日志文件
  * Received：端口接收的消息日志；每条消息都有自己的文件夹，与 MessageId 匹配
  * Sent：端口发送的消息日志；每条消息都有自己的文件夹，与 MessageId 匹配
* Receive：端口已接收或处理的消息
* Send：端口应发送或处理的消息
* Sent：成功处理的消息副本（原始数据文件格式）

根据端口类型，某些端口可能具有其他子文件夹：

* Pending：等待另一方确认的已处理消息
* Public：应作为应用程序中公共端点发布的文件
* Schemas：特定于特定端口的架构文件（如 EDI 架构）
* Templates：端口输入和输出数据的 XML 表示

### 文件夹层级背后的设计决策

由于我们希望 {siteNameShort} 中的数据透明且易于访问，应用程序中的特定文件应当易于查找。简单的分层文件夹结构有助于确保用户和外部系统知道在何处查找 {siteNameShort} 数据文件。

我们希望 {siteNameShort} UI 为配置和使用应用程序提供便捷的界面，但同时也希望应用程序保持完全可嵌入到其他解决方案中。了解 {siteNameShort} 文件夹结构是将这些其他解决方案指向任何相关 {siteNameShort} 数据所需的全部内容。

## 自动化

{siteNameShort} 自动化服务处理每个端口**交易选项卡**文件夹中的文件。自动化服务以半秒一个\_时钟滴答\_的频率运行，消息在每个滴答时在工作流中向前推进一步。

{siteNameShort} 通过向每个端口分配多个线程来支持并行处理，每个线程可以处理该端口中的多个文件。分配的工作线程具体数量和每个工作线程处理的文件数由[个人设置](./administration/profiles)和特定端口设置中的性能设置决定。

### 时钟滴答 (Clock Ticks)

以预定义的时间间隔（默认 500 毫秒），{siteNameShort} 检查每个配置端口的 Send 文件夹内容，如果发现新文件，则根据端口设置分配工作线程来处理它们。

应用程序不保证首先枚举哪个端口的输入。当单个端口的 Send 文件夹中有多个文件时，它们根据最后修改时间排序处理（最早修改的文件优先处理）。

当 {siteNameShort} 尝试处理文件时，它会添加一个包含处理时间戳的消息标头，这会更改文件的最后修改时间。这意味着如果文件处理失败（导致错误），与 Send 文件夹中的其他文件相比，它将变成优先级最低的文件。这防止了单个文件因重复抛错并立即重试而阻塞端口的运行。

### 并行处理

启用并行处理后，{siteNameShort} 可以在单个时钟滴答期间向同一个端口分配多个工作线程。这些工作线程的数量和行为由**设置**页面的**高级**选项卡上的三个设置决定（其中一些可以在特定端口的**高级**选项卡中为单个端口覆盖）：

* **工作线程池 (Worker Pool)**：建立应用程序可以同时分配给所有端口（总计）的全局最大线程数。当线程完成在特定端口中的分配任务后，它会被回收回线程池。主机上可用的硬件资源决定了此设置的上限。
* **每个端口最大工作线程数 (Max Workers per Connector)**：建立同时分配给单个端口的最大线程数。分配给端口的每个线程会逐个处理该端口 Send 文件夹中的文件，直到文件夹为空（或达到**每个端口最大文件数**）。达到此条件后，分配给端口的线程在完成处理后会被回收回工作线程池。可以在单个端口的**高级**选项卡上覆盖此设置。
* **每个端口最大文件数 (Max Files per Connector)**：建立在单个时钟滴答内，单个端口处理的文件数量限制。例如，如果此设置设为 5，那么分配给端口的线程在（共同）处理了 5 个文件后将被回收回工作线程池，即使该端口的 Send 文件夹中仍有文件。可以在单个端口的**高级**选项卡上覆盖此设置。当设置为 0 时，端口会尝试处理分配线程时端口中存在的所有文件。

线程以轮询方式分派给各个端口，因此调整这些值（全局或针对特定端口）可以帮助缓解吞吐量问题，或防止某些端口占用过多系统资源。下图展示了并行处理设置是如何协同工作的。

<img src="https://mintcdn.com/qiao/U-KEZ9JbQY4Wqs1D/public/images/architecture_parallel_processing.png?fit=max&auto=format&n=U-KEZ9JbQY4Wqs1D&q=85&s=c1ac41e26e35904544117bbfec5b2b97" alt="Parallel processing settings diagram" width="800" data-path="public/images/architecture_parallel_processing.png" />

#### 最大化性能

可以在单个端口中调整**每个端口最大工作线程数**和**每个端口最大文件数**设置，以在某些端口需要比其他端口更多或更少资源时，帮助最大化 {siteNameShort} 性能。

增加特定端口的**每个端口最大工作线程数**会告诉应用程序在处理该端口的输入文件时分配更多系统资源。当特定端口成为工作流吞吐量的瓶颈时，这非常有用。然而，由于线程是以轮询方式分配的，为许多不同的端口增加此设置可能会导致应用程序耗尽**工作线程池**中的线程。发生这种情况时，应用程序必须等待其他线程完成并被回收，然后才能将它们分配给剩余的端口。

减小特定端口的**每个端口最大工作线程数**可以防止该端口在处理文件时严重消耗工作线程池。这有助于避免应用程序在轮询分配期间耗尽可分派线程的问题。但是，如果端口的 Send 文件夹有很多文件，那么较少数量的线程可能需要很长时间才能完成文件处理并回收回池中（除非同时调整了**每个端口最大文件数**，如下文所述）。

增加特定端口的**每个端口最大文件数**（或设置为 `0` 以处理所有文件）有助于确保文件不会在端口的 Send 文件夹中停留多个时钟滴答。这有助于提高高业务量端口的吞吐量。然而，这也可能增加分配给该端口的线程长时间不被回收回工作线程池的可能性（可能会导致线程短缺）。

减小特定端口的**每个端口最大文件数**有助于确保分配给该端口的线程能够及时回收回池中。然而，如果 Send 文件夹中的文件数量超过了每滴答处理的最大值，这可能意味着文件并不总是在单个时钟滴答内被处理。

最大化性能取决于具体环境和用例。通常，需要处理或发送大量文件的端口应当分配更多工作线程，并且应当允许这些工作线程在回收前处理更多文件。为了防止线程池耗尽，其他端口应当分配较少的工作线程，并限制这些工作线程处理较少的文件。

### 接收自动化

在 {siteNameShort} 中，上述对输入文件的自动处理称为 *Send* 自动化。{siteNameShort} 还支持 *Receive* 自动化，它描述了端口根据预定间隔自动将文件拉取到 {siteNameShort} 工作流中的过程。

接收操作分为两类：

* 从远程主机/服务器（如 FTP、SFTP 或 S3）下载文件
* 从后端系统（如数据库、ERP 系统或 CRM）提取数据并将其作为 XML 写出

接收自动化始终与调度间隔挂钩，该间隔决定了端口尝试下载文件或从外部系统提取数据的频率。

每个时钟滴答，自动化服务都会检查是否有任何端口的接收间隔已到期。如果是，端口会立即建立出站连接并根据端口设置提取数据。

某些端口（如 AS2 端口）被动监听传入数据以进行接收。这些端口不支持接收自动化，因为它们无法主动轮询外部系统以获取数据。

## 投入使用

开始使用 {siteNameShort} 并不需要完全理解其底层架构。然而，剥开应用程序的层层外衣可以带来一系列重要的好处：

* [评估](#评估-arc-技术特性) {siteNameShort} 的方法是否符合更具体的技术要求
* 以更透彻的理解和控制力来[操作](#充满信心操作-arc)和配置应用程序
* 了解如何将 {siteNameShort} [嵌入](#将-arc-嵌入到更大的解决方案中)到更大的数据处理解决方案中

#### 评估知行之桥技术特性

{siteNameShort} 是消息驱动集成框架的轻量级实现。对其底层的了解有助于工程师判断这种方法是否适合其特定的业务需求。

阅读本文档后，我们希望指导设计决策的原则已清晰明了，因为这些原则将继续塑造应用程序的成长和发展。了解应用程序设计背后的“为什么”有助于用户在决定其是否适合自己时做出明智的选择。

#### 充满信心操作知行之桥

{siteNameShort} UI 提供了一个易于操作和配置应用程序的界面。对底层架构更好的理解可以帮助用户进行更高级的“引擎盖下”的工作，例如在特定文件夹上设置权限，以实现对用户访问的细粒度控制。

此外，我们相信对工作流、端口及其与应用程序数据之间关系的概念性掌握，可以帮助用户快速轻松地配置最佳业务流程。我们优先考虑让用户能够以最小的配置开销利用 {siteNameShort} 的功能集。

#### 将知行之桥嵌入到更大的解决方案中

一旦了解了 {siteNameShort} 的文件夹结构，将 {siteNameShort} 嵌入到另一个数据处理系统的过程就会变得简单。由于 {siteNameShort} 通过磁盘上一组定义明确的文件夹与系统交互，任何读写指定文件夹的应用程序都可以无缝地与 {siteNameShort} 交换数据。{companyName} 建议在与外部系统交互时使用 [File 端口](/26.2/self-hosted/zh/connectors/file)。有关配置详情，请参阅[与本地文件系统交互](/26.2/self-hosted/zh/flows/designing-a-flow#interacting-with-the-local-file-system)。

#### 轻松使用知行之桥

最后，我们相信工程师普遍渴望了解他们所使用系统的底层机制。即使上述好处都不适用于实际实现，我们也希望本文档能提供额外的舒适感和熟悉感，帮助你使用 {siteNameShort} 构建自己的数据集成工作流。如果对本文档内容有任何疑问或需要进一步指导，请联系专门的支持团队 **[support@kasoftware.cn](mailto:support@kasoftware.cn)**，我们将很乐意为你提供帮助。
