[comment]: # ({30385a91-30385a91})
# 2 预处理详情

[comment]: # ({/30385a91-30385a91})

[comment]: # ({e20db496-67b39eda})
#### 概述

本节提供有关监控项值预处理的详细信息。通过监控项值预处理，可以为接收到的监控项值定义并应用execute [transformation
rules](/manual/config/items/preprocessing)。

预处理由预处理管理器进程以及执行预处理步骤的预处理工作进程共同管理。所有带有预处理设置的值（在Zabbix 7.0.17之前，所有值）从不同的数据收集器接收后，都会经过预处理管理器，然后才被添加到history cache中。数据收集器（轮询器、trappers等）与预处理进程之间通过基于套接字的IPC通信进行交互。无论是Zabbix server还是Zabbix proxy（用于由proxy监控的监控项），都会执行预处理步骤。

[comment]: # ({/e20db496-67b39eda})

[comment]: # ({cbc4231a-7aff5db5})
#### 监控项值处理

为了可视化从数据源到 Zabbix 数据库的数据流，我们可以使用下面这个简化图示：

![](../../../../../assets/en/manual/appendix/items/overall_pic.png)

上图仅以**简化**形式展示了与监控项值处理相关的进程、对象和操作。该图未显示条件性方向变化、错误处理或循环。预处理管理器的本地数据缓存也未显示，因为它不会直接影响数据流。此图的目的是展示参与监控项值处理的各个进程及其交互方式。

-   数据采集从数据源中的原始数据开始。此时，数据只包含 ID、时间戳和值（也可能包含多个值）。
-   无论使用哪种数据采集器，对于主动或被动检查、trapper 监控项等，原理都是相同的，因为它只会改变数据格式和通信发起方（要么数据采集器等待连接和数据，要么数据采集器发起通信并请求数据）。原始数据会被验证，监控项配置会从配置缓存中检索出来（数据会通过配置数据得到丰富）。
-   使用基于 socket 的 IPC 机制将数据从数据采集器传递到预处理管理器。此时，数据采集器会继续采集数据，而不会等待预处理管理器的响应。
-   执行数据预处理。这包括执行预处理步骤以及依赖监控项处理。

::: noteclassic
如果任何预处理步骤失败，监控项在执行预处理时可能会将其状态更改为 NOT SUPPORTED。
:::

-   预处理管理器本地数据缓存中的历史数据会被刷新到历史缓存中。
-   此时，数据流会停止，直到下一次历史缓存同步（即 history syncer 进程执行数据同步时）。
-   同步过程在将数据存储到 Zabbix 数据库之前，会先进行数据规范化。数据规范化会将数据转换为所需的监控项类型（由监控项配置中定义的类型决定），包括根据这些类型允许的[预定义大小](/manual/config/items/item#text-data-limits)截断文本数据（string 使用 HISTORY\_STR\_VALUE\_LEN，text 使用 HISTORY\_TEXT\_VALUE\_LEN，log 值使用 HISTORY\_LOG\_VALUE\_LEN）。规范化完成后，数据会被发送到 Zabbix 数据库。

::: noteclassic
如果数据规范化失败，监控项可能会将其状态更改为 NOT SUPPORTED（例如，文本值无法转换为数字时）。
:::

-   已采集的数据会被处理——会检查触发器，如果监控项变为 NOT SUPPORTED，则会更新监控项配置，等等。
-   从监控项值处理的角度来看，这被视为数据流的结束。

[comment]: # ({/cbc4231a-7aff5db5})

[comment]: # ({107e489a-44da8577})
#### 监控项 值预处理

数据预处理按以下步骤执行：

-   如果 监控项 既没有预处理步骤也没有依赖的 监控项，则其值将被添加到 history cache 或发送到 LLD 管理器。否则，监控项 的值将通过基于 UNIX 套接字的 IPC 机制传递给预处理管理器（在 Zabbix 7.0.17 之前，所有值在被添加到 history cache 或发送到 LLD 管理器之前都会经过预处理管理器）。
-   创建一个预处理任务并将其添加到队列中，同时通知预处理工作进程有新任务。
-   此时数据流暂停，直到至少有一个空闲的（即未执行任何任务的）预处理工作进程。
-   当有可用的预处理工作进程时，它将从队列中取出下一个任务。
-   预处理完成后（无论预处理步骤执行成功或失败），预处理后的值将被添加到已完成任务队列，并通知管理器有新的已完成任务。
-   预处理管理器将结果转换为所需的格式（由 监控项 的值类型定义），然后将其添加到 history cache 或发送到 LLD 管理器。
-   如果处理的 监控项 存在依赖的 监控项，则依赖的 监控项 将使用预处理后的主 监控项 值被添加到预处理队列中。依赖的 监控项 将绕过正常的值预处理请求而被入队，但仅适用于值已设置且不处于 NOT SUPPORTED 状态的主 监控项。

![](../../../assets/en/diagrams/value_preprocessing.png){width="600"}

请注意，在图中主 监控项 的预处理过程略作简化，省略了预处理缓存的步骤。

[comment]: # ({/107e489a-44da8577})

[comment]: # ({73f49808-4b6fc468})
#### 预处理队列

预处理队列的组织方式如下：

*   待处理任务列表：
    *   按接收顺序直接从值预处理请求创建的任务

*   立即任务列表（在待处理任务之前处理）：
    *   测试任务（由前端的 监控项/预处理测试请求创建）
    *   依赖的 监控项 任务
    *   序列任务（必须按严格顺序执行的任务）：
        *   包含使用最新值的预处理步骤的任务：
            *   变化
            *   节流
            *   JavaScript（字节码缓存）
        *   依赖的 监控项 预处理缓存

*   已完成任务列表

[comment]: # ({/73f49808-4b6fc468})

[comment]: # ({abb85873-c9d6405f})
#### 预处理缓存

预处理缓存的引入是为了提升多个具有相似预处理步骤的依赖 监控项（这通常是LLD的结果）的预处理性能。

缓存通过预处理一个依赖的 监控项，并为其余依赖的 监控项 重用部分内部预处理数据来实现。预处理缓存仅支持以下类型的第一步预处理：

*   Prometheus模式（通过指标索引输入）
*   JSONPath（将数据解析为 object 树并索引第一个表达式 `[?(@.path == "value")]`）

[comment]: # ({/abb85873-c9d6405f})

[comment]: # ({c79ec0eb-98589fcd})
#### 预处理工作进程

Zabbix server配置file允许用户设置预处理工作线程的数量。
应使用[startpreprocessors](/manual/appendix/config/zabbix_server#startpreprocessors)配置参数来设置预启动的预处理工作者实例数量，该数量至少应与可用CPU核心数量匹配。

如果预处理任务不是CPU密集型且涉及频繁的网络请求，则建议配置额外的工作进程。
预处理工作者的最佳数量可能由许多因素决定，包括“可预处理”监控项的数量（需要进行execute任何预处理步骤的监控项）、数据收集进程的数量、监控项预处理的平均步骤数量等。
工作者数量不足可能导致较高的memory使用率。有关解决Zabbix安装中过多memory使用率的问题，请参见[Profiling excessive memory usage with tcmalloc](/manual/installation/known_issues#profiling-excessive-memory-usage-with-tcmalloc)。

但假设不存在解析大型XML/JSON块等繁重的预处理操作，则预处理工作者的数量可以与数据收集器的总数匹配。这样，通常情况下（除了数据从收集器批量到达的情况），将至少有一个未被占用的预处理工作者来处理收集到的数据。

::: notewarning
过多的数据收集进程（轮询器、不可达轮询器、ODBC轮询器、HTTP轮询器、Java轮询器、ping器、trapper、代理轮询器）与IPMI管理器、SNMP trapper和预处理工作者一起可能会耗尽预处理管理器的每个进程file描述符限制。
<br><br>
耗尽每个进程的file描述符限制将导致Zabbix server停止，通常在启动后不久发生，但有时可能需要更长时间。
为避免此类问题，请查看[Zabbix server configuration file](/manual/appendix/config/zabbix_server)以优化并发检查和进程数量。
此外，如有必要，请确保通过检查和调整系统限制，将file描述符限制设置得足够高。
:::

[comment]: # ({/c79ec0eb-98589fcd})

[comment]: # ({a459312a-ad691011})
##### 值处理管道

监控项 值处理由多个进程分多个步骤（或阶段）执行。这可能会导致：

-   一个依赖的 监控项 可以接收值，而主值却不能。可以通过以下使用场景实现：
    -   主 监控项 的值类型为 `UINT`（可以使用 trapper 监控项），
        依赖的 监控项 的值类型为 `TEXT`。
    -   主值和依赖的 监控项 都不需要预处理步骤。
    -   应该向主 监控项 传递一个文本值（例如，"abc"）。
    -   由于没有预处理步骤需要执行，预处理管理器会检查主 监控项 是否不在 NOT SUPPORTED 状态，
        并且值是否已设置（两者都为真），然后将依赖的 监控项 与主 监控项 的相同值一起入队
        （因为没有预处理步骤）。
    -   当主值和依赖的 监控项 都进入历史数据同步阶段时，主 监控项 会因为值转换version错误
        （文本数据无法转换为无符号integer）而变为 NOT SUPPORTED 状态。

结果是，依赖的 监控项 接收到一个值，而主 监控项 改变为 NOT SUPPORTED 状态。

-   一个依赖的 监控项 接收到的值在主 监控项 历史数据中不存在。该使用场景与前一个非常相似，
    除了主 监控项 的类型不同。例如，如果主 监控项 使用 `CHAR` 类型，
    那么主 监控项 的值将在历史数据同步阶段被截断，而依赖的 监控项 将从主 监控项 的初始值
    （未截断的值）接收它们的值。

[comment]: # ({/a459312a-ad691011})
