编年史队列 POC 返回了意外的延迟

问题描述

我们的一个系统具有使用 Apache Kafka 作为服务总线的微服务架构。 低延迟是一个非常重要的因素,但可靠性和一致性(恰好一次)更为重要。

当我们执行一些负载测试时,我们注意到性能显着下降,所有调查都表明 Kafka 主题的生产者和消费者延迟大幅增加。无论我们更改多少配置或添加更多资源,我们都无法摆脱这些症状。

目前我们的需求是每秒处理 10 个事务 (TPS),负载测试执行 20 TPS,但随着系统的发展和添加更多功能,我们知道我们将达到需要 500TPS 的阶段,因此我们开始担心我们能否通过 Kafka 实现这一目标。

作为概念证明,我尝试切换到我们的一个微服务以使用编年史队列而不是 Kafka 主题。按照 avro 示例从 Chronicle-Queue-Demo git hub repo

开始迁移很容易
public class MessageAppender {
    private static final String MESSAGES = "/tmp/messages";

    private final AvroHelper avroHelper;
    private final ExcerptAppender messageAppender;

    public MessageAppender() {
        avroHelper = new AvroHelper();
        messageAppender = SingleChronicleQueueBuilder.binary(MESSAGES).build().acquireAppender();
    }

    @SneakyThrows
    public long append(Message message) {
        try (var documentContext = messageAppender.writingDocument()) {
            var paymentRecord = avroHelper.getGenericRecord();
            paymentRecord.put("id",message.getId());
            paymentRecord.put("workflow",message.getWorkflow());
            paymentRecord.put("workflowStep",message.getWorkflowStep());
            paymentRecord.put("securityClaims",message.getSecurityClaims());
            paymentRecord.put("payload",message.getPayload());
            paymentRecord.put("headers",message.getHeaders());
            paymentRecord.put("status",message.getStatus());
            avroHelper.writetoOutputStream(paymentRecord,documentContext.wire().bytes().outputStream());
            return messageAppender.lastIndexAppended();
        }
    }
}

在配置完这个 appender 之后,我们运行了一个循环来向一个编年史队列生成 100_000 条消息。每条消息的大小相同,文件的最终大小为 621MB。处理写入所有消息需要 22 分 20 秒和 613 毫秒(~1341 秒),因此平均约为 75 条消息/秒。

这绝对不是我们所期望的,而且与编年史文档中宣传的延迟相去甚远,这让我相信我的方法不是正确的方法。我承认我们的消息不小,大约 6.36KB/条,但我毫不怀疑将它们存储在数据库中会更快,所以我仍然认为我做得不对。

重要的是我们的消息是一一处理的。

预先感谢您的意见和/或建议。

解决方法

每次手动构建 Avro 对象对我来说似乎有点代码味道。

您能否创建一个预定义的消息 -> avro 序列化程序并使用它来填充队列?

或者,只是为了测试,在循环外创建一个 avro 对象并将该对象多次送入队列。这样你就可以看到瓶颈是建筑物还是排队。


更一般的建议:

也许可以附加一个分析器,看看您是否进行了过多的对象分配。如果他们被提升到更高的世代,这尤其糟糕。

看看它们是你的对象还是 Chronicle Queue 的对象。

您的代码是否使您的 ram 或 cpu(或网络)最大化?