4. 流编排核心组件:数据源(Source)、处理节点(Processor)、数据汇(Sink)的职责与生命周期

流编排应用的本质是将数据采集、处理与输出拆解为三个可独立部署、可组合的组件。理解 Source、Processor、Sink 的职责边界与生命周期管理,是构建可靠边缘计算管线的第一步。本章从职责定义、状态转换、生命周期回调三个维度展开,并给出典型边缘场景下的组件协作示例。

4.1 三大组件的职责定义

在流编排运行时,每个组件都是一个独立的执行单元,通过连接器(Connector)与上下游通信。下表从输入、输出、核心行为三个维度对比三者的职责差异:

组件类型 输入 输出 核心职责
Source(数据源) 外部系统(HTTP API、MQTT、文件、数据库) 内部数据流(Record / Event) 连接外部、拉取/监听数据、反序列化、生成带时间戳的原始记录
Processor(处理节点) 上游 Source 或其他 Processor 下游 Processor 或 Sink 过滤、转换、聚合、富化、规则判断;可产生零到多条输出
Sink(数据汇) 上游 Processor 或 Source 外部系统(HTTP POST、数据库、文件、边缘存储) 序列化、批量写入、事务提交、失败重试与死信处理
边缘场景提示: 在边缘节点上,Source 通常需要支持断网缓存(offline buffering),Processor 应保持无状态以方便热更新,Sink 必须实现幂等写入以避免网络抖动导致的数据重复。

4.2 组件生命周期状态机

每个组件在流编排引擎内部都经历统一的状态转换。状态机确保组件在启动、运行、停止、故障恢复等阶段行为可预测。下图展示了完整的生命周期状态流转:

组件生命周期状态机 CREATED INITIALIZED RUNNING PAUSED FAILED CLOSED init() start() pause() resume() restart() fail() close() close() 生命周期关键点: • CREATED → INITIALIZED:分配资源、建立连接、校验配置 • RUNNING → PAUSED:暂停消费/输出,保留状态;PAUSED → RUNNING:恢复数据流

4.3 生命周期回调方法

每个组件必须实现以下四个核心回调方法,编排引擎在状态转换时自动调用:

// Source 示例:HTTP API 轮询数据源
public class HttpPollingSource implements Source {

    private HttpClient client;
    private String endpoint;

    @Override
    public void init(SourceContext ctx) {
        // 1. 解析配置(URL、间隔、认证)
        this.endpoint = ctx.getConfig().getString("endpoint");
        this.client = HttpClient.newBuilder()
            .connectTimeout(Duration.ofSeconds(5))
            .build();
        // 2. 预校验:测试连接是否可达
        if (!healthCheck()) {
            throw new SourceInitException("Endpoint unreachable: " + endpoint);
        }
    }

    @Override
    public void start(SourceCollector<Record> collector) {
        // 进入事件循环:定时拉取 HTTP API
        while (isRunning()) {
            HttpRequest req = HttpRequest.newBuilder()
                .uri(URI.create(endpoint))
                .GET()
                .build();
            client.sendAsync(req, BodyHandlers.ofString())
                .thenAccept(response -> {
                    List<Record> records = parseResponse(response.body());
                    records.forEach(collector::collect);
                });
            Thread.sleep(pollIntervalMs);
        }
    }

    @Override
    public void pause() {
        // 暂停拉取,保留连接池
        setPaused(true);
    }

    @Override
    public void close() {
        // 释放连接、关闭线程池
        client.close();
    }
}
Processor 与 Sink 的差异:
  • Processor.init():加载 UDF(用户自定义函数)、初始化状态存储(如去重缓存)。
  • Processor.process():接收上游记录,返回零到多条输出记录;支持异步回调。
  • Sink.init():创建数据库连接池或文件句柄,校验目标表/路径是否存在。
  • Sink.write():批量写入,实现事务性提交;失败时根据重试策略决定是否进入死信队列。

4.4 组件协作流程:一次完整的流处理

下图展示了一个边缘 HTTP API 采集场景下,三个组件如何协作完成一次数据流转:

组件协作流程:HTTP API 采集 → 过滤 → 边缘存储 外部 HTTP API HttpPollSource 轮询 /api/v1/sensors FilterProcessor 温度 > 50°C 过滤 FileSink 写入边缘 CSV HTTP GET Record 流 过滤后数据 一次完整请求的生命周期时序: 1. Source.init() → 创建 HTTP 客户端,校验 API 端点 2. Source.start() → 发起 GET 请求,反序列化 JSON 为 Record 列表 3. Processor.process() → 逐条过滤,丢弃温度 ≤ 50°C 的记录 4. Sink.write() → 将有效记录追加到边缘节点本地 CSV 文件,每 10 条 flush 一次 5. 编排停止时:Sink.close() → Processor.close() → Source.close()(逆序关闭)

4.5 组件生命周期管理最佳实践

  • 资源隔离: 每个 Source 独占一个连接池,避免一个组件故障拖垮整个引擎。
  • 优雅关闭: 在 close() 中等待正在处理的记录完成(drain),设置超时防止永久阻塞。
  • 状态持久化: Processor 的中间状态(如窗口聚合结果)应在 pause() 时快照到本地存储,resume() 时恢复。
  • 故障恢复: 组件从 FAILED 状态只能通过 close() 进入 CLOSED,然后重新 init();不允许直接从 FAILED 跳回 RUNNING。
常见陷阱:
  • 在 init() 中启动线程或定时器 → 应推迟到 start() 中执行,否则 pause/resume 无法正确控制。
  • Sink 的 write() 抛出异常后未标记组件为 FAILED → 导致数据丢失且引擎无法触发恢复策略。
  • Source 的 close() 未关闭网络连接 → 边缘节点内存泄漏,长期运行后 OOM。

4.6 小结