Что такое Apache Kafka?

Apache Kafka - это распределенная потоковая платформа, которая позволяет:

  • Публикуйте и подписывайтесь на потоки записей, аналогичные очереди сообщений или корпоративной системе обмена сообщениями.
  • Храните потоки записей надежным и отказоустойчивым способом.
  • Обрабатывайте потоки записей по мере их появления.

Если вы раньше не использовали Kafka, вы можете перейти сюда для быстрого старта и вернуться к этой статье, как только вы познакомитесь с вариантом использования.

Kafka поддерживает высокопроизводительную, распределенную и отказоустойчивую платформу с низкой задержкой доставки сообщений. Здесь мы сосредоточимся на аспекте доставки с малой задержкой.

Низкая задержка ввода-вывода = файловая система?

Большинство традиционных систем данных используют оперативную память (RAM) в качестве хранилища данных, поскольку RAM обеспечивает чрезвычайно низкие задержки.

Хотя такой подход делает их быстрыми, стоимость ОЗУ намного больше, чем стоимость диска. Запуск таких систем обычно обходится дороже, если через систему проходят сотни данных GBPS.

Kafka полагается на файловую систему для хранения и кеширования. Проблема в том, что диски медленнее ОЗУ. Это связано с тем, что время поиска по диску велико по сравнению со временем, необходимым для фактического чтения данных.

Но если вы можете избежать поиска, то в некоторых случаях вы можете достичь таких низких задержек, как RAM. Это выполняется Kafka через Последовательный ввод-вывод.

Одним из преимуществ последовательного ввода-вывода является то, что вы получаете кеш без необходимости писать для него какую-либо логику в вашем приложении. Современные операционные системы выделяют большую часть своей свободной памяти для кэширования диска. Таким образом, если вы читаете в упорядоченном режиме, ОС всегда может выполнять упреждающее чтение и сохранять данные в кэше при каждом чтении с диска.

Это намного лучше, чем поддерживать кеш в приложении JVM. Это связано с тем, что объекты JVM «тяжелы» и могут привести к интенсивной сборке мусора, которая ухудшается по мере увеличения размера данных.

Не используйте деревья

Большинство современных баз данных используют ту или иную форму древовидной структуры данных для постоянного хранения данных. Например, MongoDB использует BTree, а Cassandra - LSM tree.

Эти структуры обеспечивают производительность поиска O (log N).

Для системы обмена сообщениями, которая требует одновременного выполнения множества операций чтения и записи, использование деревьев может привести к множеству случайных операций ввода-вывода. Это приводит к большому количеству обращений к диску, что губительно для производительности.

Очередь - это гораздо лучшая структура данных для системы обмена сообщениями. В большинстве случаев данные добавляются в систему, и чтение выполняется просто. Все такие операции выполняются за O (1), что намного эффективнее.

Не копируйте!

Одним из основных недостатков систем обработки данных является сериализация и десериализация (перевод в форматы, подходящие для хранения и передачи) данных во время передачи.

Это можно сделать быстрее, используя лучшие форматы двоичных данных, такие как буферы протокола или плоские буферы, вместо JSON.

Но как вообще избежать сериализации / десериализации?

Кафка решает эту проблему двумя способами:

  1. Используйте стандартизированный формат двоичных данных для производителей, брокеров и потребителей (чтобы данные можно было передавать без изменений)
  2. Не копируйте данные в приложении («нулевая копия»)

Первый не требует пояснений. Это второй вопрос, требующий внимания.

Обычная передача данных из файла в сокет может происходить следующим образом:

  1. ОС считывает данные с диска в кэш страниц в пространстве ядра.
  2. Приложение считывает данные из пространства ядра в буфер пространства пользователя.
  3. Приложение записывает данные обратно в пространство ядра в буфер сокета.
  4. ОС копирует данные из буфера сокета в буфер сетевого адаптера, откуда они отправляются по сети.

Однако, если у нас есть тот же стандартизированный формат для данных, который не требует модификации, тогда нам не нужно выполнять шаг 2 (копирование данных из пространства ядра в пространство пользователя).

Если мы будем хранить данные в том же формате, в котором они будут отправляться по сети, то мы можем напрямую копировать данные из кэша страниц в буфер NIC. Это можно сделать с помощью системного вызова sendfile ОС.

Подробнее о подходе с нулевым копированием можно прочитать в этой статье.

Что еще?

Kafka использует множество других методов, помимо упомянутых выше, чтобы сделать системы намного более быстрыми и эффективными:

  1. Пакетная обработка данных для уменьшения количества сетевых вызовов, а также преобразование большого количества случайных записей в последовательные.
  2. Сжатие пакетов (а не отдельных сообщений) с использованием кодеков LZ4, SNAPPY или GZIP. Большая часть данных согласована между сообщениями в пакете (например, поля сообщения и информация метаданных). Это может улучшить степень сжатия.

Чтобы узнать больше о дизайне Кафки, вы можете обратиться к их официальной статье.

Важно отметить, что все вышеперечисленные методы могут применяться в большинстве систем для достижения низких задержек. Они не связаны с вмешательством в ядро, настройкой сборки мусора, использованием собственных приложений или экстремальных структур данных.

Однако одним из недостатков является то, что некоторые из этих методов характерны для случаев, подобных платформе обмена сообщениями. Они не подходят для более общей распределенной базы данных.

Если вам интересно узнать о других подобных дизайнах или у вас есть возможность, свяжитесь со мной в LinkedIn или Facebook или напишите письмо на [email protected]