Chronicle 队列 POC 返回意外延迟

Chronicle queue POC returned unexpected latency

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

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

目前我们的需求是每秒处理 10 t运行 次操作 (TPS),负载测试正在执行 20 TPS,但随着系统的发展和添加更多功能,我们知道我们将达到需求将达到 500TPS 的阶段,所以我们开始担心我们是否可以使用 Kafka 实现这一点。

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

开始,按照 avro 示例很容易迁移
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 message/second.

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

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

提前感谢您的意见和/或建议。

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

你能创建一个预定义的消息 -> avro 序列化程序并使用它来提供队列吗?

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


更一般的建议:

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

查看它们是您的对象还是 Chronicle Queue 对象。

您的代码是否使内存或 cpu(或网络)达到极限?