Одна из наших систем имеет микросервисную архитектуру, использующую Apache Kafka в качестве служебной шины. Низкая задержка — очень важный фактор, но еще важнее надежность и согласованность (ровно один раз).
Когда мы проводили некоторые нагрузочные тесты, мы заметили значительное снижение производительности, и все исследования указывали на значительное увеличение задержек производителя и потребителя тем Kafka. Сколько бы мы не меняли конфигурацию и не добавляли больше ресурсов, мы не могли избавиться от симптомов.
На данный момент наши потребности обрабатывают 10 транзакций в секунду (TPS), а нагрузочный тест выполняет 20 TPS, но по мере развития системы и добавления дополнительных функций мы знаем, что достигнем стадии, когда потребность будет составлять 500TPS, поэтому мы начали волнуюсь, сможем ли мы добиться этого с Кафкой.
В качестве доказательства концепции я попытался переключиться на один из наших микросервисов, чтобы использовать хронику-очередь вместо темы 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();
}
}
}
После настройки этого приложения мы запустили цикл для создания 100_000 сообщений в очередь хроники. Каждое сообщение имеет одинаковый размер, а окончательный размер файла составил 621 МБ. Для обработки записи всех сообщений потребовалось 22 минуты 20 секунд и 613 миллисекунд (~ 1341 секунда), поэтому в среднем около 75 сообщений в секунду.
Это было определенно не то, на что мы рассчитывали, и так далеко от задержек, рекламируемых в документации хроники, что заставило меня поверить, что мой подход был неправильным. Я признаю, что наши сообщения не маленькие, около 6,36 КБ на сообщение, но я не сомневаюсь, что хранить их в базе данных было бы быстрее, поэтому я все еще думаю, что делаю это неправильно.
Важно, чтобы наши сообщения обрабатывались одно за другим.
Заранее благодарим вас за ваш вклад или предложения.