趋近智
实时推理 (inference)系统常常需要与终端用户建立同步协议。当用户执行交易或提交搜索请求时,他们希望基于最新数据获得即时结果。虽然Apache Flink和Kafka擅长高吞吐量 (throughput)的异步处理,但要连接阻塞式HTTP客户端和非阻塞式流处理拓扑,就需要一种架构模式。这包括在一个事件驱动的骨干上实现请求-响应循环,这通常被称为关联标识符模式。
主要问题在于协议的操作语义。HTTP和gRPC默认是同步的;客户端打开一个套接字并等待字节返回。Kafka则是严格异步的;生产者将数据推送到日志后就断开连接或移动到下一条消息,而无需等待消费者处理该特定记录。
为了通过Flink提供机器学习 (machine learning)模型,同时为客户端保持RESTful接口,API网关必须充当一个高明的协调者。它将阻塞式请求转换为消息生产事件,并有效地暂停HTTP线程,直到相应的消息在回复通道上到达。
该实现依赖于两个特定的Kafka主题:一个request-topic(请求主题)和一个reply-topic(回复主题)。工作流程遵循一个严格的事件序列,其中涉及一个关联ID,该ID在分布式系统中唯一标识了此事务。
CompletableFuture(或等效的Promise对象),将其映射到该ID。request-topic(请求主题)生产一条记录。负载包含特征向量 (vector)或原始数据,关联ID则注入到Kafka记录头部中。reply-topic(回复主题)。重要的是,它必须将关联ID从输入头部复制到输出头部。reply-topic(回复主题)消费。它提取关联ID,在其本地内存映射中查找待处理的CompletableFuture,用预测结果完成该Future,并回应HTTP客户端。API网关充当了同步HTTP协议与异步Kafka日志之间的桥梁,它使用关联ID将不同响应关联回待处理的开放连接。
上述模式的一个简单实现会在横向扩展环境中失效。如果您部署了十个API网关实例,发出请求的实例(并持有开放的HTTP连接)不能保证是消费回复的实例。如果网关A发出请求,但网关B消费了回复,网关A最终会超时,导致用户请求失败,尽管模型运行正常。
为了解决此问题,我们使用Kafka的分区机制作为路由层。这通常通过一个特定的“回复到”头部来实现,该头部不仅表明主题,还表明将消息路由回正确生产者实例所需的特定分区或元数据。
在此方法中,每个网关实例都被分配reply-topic(回复主题)的一个固定分区ID。当网关实例3生产请求时,它会包含一个头部Reply-Partition: 3。Flink任务在完成推理 (inference)后,读取此头部并将结果明确地生产到reply-topic(回复主题)的分区3。
这确保了数据局部性。网关实例3仅从分区3消费,保证它只收到与其发起的请求相关的响应。这省去了网关消费和丢弃数百万旨在发送给其他实例的无关消息的必要性。
系统可靠性可用数学方式表示。设是网关在发出504网关超时之前等待的最长时间。总处理延迟是网络传输、排队和推理时间的总和:
为了系统可行,我们必须保证总延迟的99百分位数满足:
在高吞吐量 (throughput)环境中,请求偶尔会超时。如果Flink任务因反压或垃圾回收暂停而停滞,可能会超出。网关将关闭HTTP连接并从内存中移除CompletableFuture。
然而,消息仍在Kafka中。Flink最终会处理它并生产回复。当网关收到这个“迟到”的回复时,它在其待处理映射中找不到匹配的ID。这种被称为“幽灵响应”的情况,需要细致处理。网关必须悄悄丢弃具有未知关联ID的消息,以避免内存泄漏或日志泛滥。
此外,存放待处理请求的映射必须采用自动淘汰策略。如果Kafka消费者线程崩溃或回复消息丢失,待处理的Future理论上会永久保留在内存中。为了避免网关层出现OutOfMemoryError,实现一个带有基于时间淘汰机制的ConcurrentHashMap(或使用Caffeine等库)是强制性的。
这种分布显示出长尾延迟的风险。红色虚线右侧曲线下方的区域表示将导致超时错误的请求比例,即使计算最终成功。
此模式的效率要求元数据应保留在头部中,将负载严格用于特征向量 (vector)或模型输入。Kafka头部本质上是字节数组的键值对。
在实现Flink的SerializationSchema时,您必须从传入的ConsumerRecord中提取头部并将其传递到ProducerRecord。Flink的KafkaRecordSerializationSchema允许直接访问传输头部。
一个典型的AI推理 (inference)请求的头部协议可能如下所示:
X-Correlation-ID: 550e8400-e29b-41d4-a716-446655440000 (UUID)X-Reply-Topic: inference.replies.v1X-Reply-Partition: 4 (网关实例的整数ID)X-Creation-Timestamp: 1678886400000 (用于计算传输时间)通过标准化这些头部,您可以将Flink任务与特定网关实现解耦。Flink任务成为一个纯函数:它接收数据,处理数据,并将其返回到头部中指定的地址,不关心调用方是REST API、WebSocket服务器还是其他内部微服务。
这部分内容有帮助吗?
© 2026 ApX Machine LearningAI伦理与透明度•