Что такое Apache Kafka?

Ответ

Apache Kafka — это распределённый, отказоустойчивый потоковый брокер сообщений, изначально созданный в LinkedIn. В контексте Node.js-приложений он часто используется для построения высоконагруженных, масштабируемых пайплайнов данных в реальном времени, связывая микросервисы.

Ключевые концепции:

  • Топик (Topic): Именованный поток данных (например, user-events).
  • Партиция (Partition): Топик делится на партиции для параллельной обработки и масштабирования.
  • Производитель (Producer): Приложение (например, наш Node.js-сервис), публикующее сообщения в топик.
  • Потребитель (Consumer): Приложение, подписанное на топик и читающее сообщения. Потребители объединяются в Consumer Groups для распределения нагрузки.
  • Брокер (Broker): Сервер Kafka, хранящий данные.

Пример использования с библиотекой kafkajs в Node.js:

// producer.js
const { Kafka } = require('kafkajs');

const kafka = new Kafka({
  clientId: 'my-node-app',
  brokers: ['kafka-server1:9092', 'kafka-server2:9092']
});

const producer = kafka.producer();

async function sendEvent() {
  await producer.connect();
  await producer.send({
    topic: 'order-created',
    messages: [
      {
        key: 'order-123', // Ключ определяет партицию
        value: JSON.stringify({ orderId: 123, amount: 99.99, userId: 'user-1' })
      }
    ]
  });
  console.log('Событие отправлено в Kafka');
  await producer.disconnect();
}

sendEvent().catch(console.error);
// consumer.js
const { Kafka } = require('kafkajs');

const kafka = new Kafka({
  clientId: 'my-node-consumer',
  brokers: ['kafka-server1:9092']
});

const consumer = kafka.consumer({ groupId: 'notification-service' });

async function runConsumer() {
  await consumer.connect();
  await consumer.subscribe({ topic: 'order-created', fromBeginning: false });

  await consumer.run({
    eachMessage: async ({ topic, partition, message }) => {
      const event = JSON.parse(message.value.toString());
      console.log(`Получено событие для заказа ${event.orderId}`);
      // Здесь логика обработки: отправить email, уведомление и т.д.
    }
  });
}

runConsumer().catch(console.error);

Почему Kafka, а не RabbitMQ для Node.js? Kafka лучше подходит для сценариев с очень высокой пропускной способностью, долгосрочным хранением логов событий и потоковой обработкой через Kafka Streams или библиотеки вроде node-rdkafka.

Ответ 18+ 🔞

Давай разберем эту штуку, которая у всех на слуху, но от которой у многих мозг вскипает, как чайник у бабки в деревне. Apache Kafka, блядь. Представь себе не просто очередь сообщений, а такой промышленный конвейер, который жрёт данные, как дракон, и плюётся ими во все стороны с такой скоростью, что глаза слипаются. Изначально его в LinkedIn высидели, ну, там, где все друг на друга смотрят и связи наращивают, так что масштабы им были знакомы не понаслышке.

Суть, если на пальцах:

  • Топик (Topic): Это как канал на ютубе, куда ты стримишь. Название, допустим, user-events. Все твои действия туда летят.
  • Партиция (Partition): А это когда один хитрый канал делят на несколько потоков, чтобы не создавать очередь из овердохуища сообщений и чтобы несколько потребителей могли одновременно хавать данные. Гениально и просто.
  • Производитель (Producer): Это твой Node.js-сервис, который, подгорев от какого-то события, начинает орать в этот топик: «Эй, все, слушайте, у нас тут заказ создался!».
  • Потребитель (Consumer): Это другой сервис, который сидит, уши развесил, и слушает этот топик. А чтобы не один мучился, их объединяют в Consumer Groups — стаю таких потребителей, которые делят работу. Один упал — другие подхватят.
  • Брокер (Broker): Ну, это сам сервер Кафки, где всё это безобразие физически лежит.

Смотри, как это в коде выглядит, на примере библиотеки kafkajs:

// producer.js – тот, кто кричит
const { Kafka } = require('kafkajs');

// Подключаемся к нашим брокерам. Если один накроется медным тазом – пойдём к другому.
const kafka = new Kafka({
  clientId: 'my-node-app',
  brokers: ['kafka-server1:9092', 'kafka-server2:9092']
});

const producer = kafka.producer();

async function sendEvent() {
  await producer.connect();
  // А вот и наш крик в топик 'order-created'
  await producer.send({
    topic: 'order-created',
    messages: [
      {
        key: 'order-123', // Ключ – чтобы понять, в какую партицию пихать
        value: JSON.stringify({ orderId: 123, amount: 99.99, userId: 'user-1' }) // Само сообщение
      }
    ]
  });
  console.log('Событие отправлено в Kafka. Дело сделано.');
  await producer.disconnect();
}

sendEvent().catch(console.error); // Ловим ошибки, а то будет нам хиросима
// consumer.js – тот, кто слушает
const { Kafka } = require('kafkajs');

const kafka = new Kafka({
  clientId: 'my-node-consumer',
  brokers: ['kafka-server1:9092']
});

// Создаём потребителя и говорим, к какой группе он принадлежит
const consumer = kafka.consumer({ groupId: 'notification-service' });

async function runConsumer() {
  await consumer.connect();
  // Подписываемся на топик. 'fromBeginning: false' – слушаем только новое, старое не надо.
  await consumer.subscribe({ topic: 'order-created', fromBeginning: false });

  // А вот тут начинается магия – обработка каждого сообщения
  await consumer.run({
    eachMessage: async ({ topic, partition, message }) => {
      const event = JSON.parse(message.value.toString()); // Выковыриваем данные
      console.log(`Получено событие для заказа ${event.orderId}, ёпта!`);
      // Тут твоя логика: слать письмо, пинать другой сервис – делай что хочешь.
    }
  });
}

runConsumer().catch(console.error);

И главный вопрос: нахуя это, если есть RabbitMQ? Вот смотри, RabbitMQ — это как надёжный, умный почтальон, который гарантированно доставит письмо из рук в руки. А Kafka — это, блядь, гигантский ленточный транспортёр на заводе, который непрерывным потоком гонит тонны сырья (данных), и ты можешь в любом месте этого конвейра поставить своего работника (потребителя), чтобы он что-то с этим сырьём делал. Кафка рулит, когда тебе нужно:

  1. Обрабатывать овердохуища событий в секунду.
  2. Хранить эти события долго (он же по сути лог).
  3. Строить сложную потоковую обработку (через Kafka Streams или node-rdkafka), где данные непрерывно текут и преобразуются.

Короче, если у тебя не просто фантики между сервисами перекидывать, а реально мощный data pipeline в реальном времени — то это твой выбор. А если задача простая — не выёбывайся, бери RabbitMQ и живи спокойно.