← Назад к вопросам

Что такое JMS и чем он отличается от Kafka?

2.0 Middle🔥 151 комментариев
#Брокеры сообщений

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

# JMS vs Kafka: Полное сравнение

Что такое JMS

JMS (Java Message Service) — это Java API для асинхронной обработки сообщений. Это **стандарт** (JSR-914), определяющий интерфейсы для работы с message brokers. JMS сам по себе это не сервис, а спецификация.

Типичные JMS реализации:

  • Apache ActiveMQ
  • RabbitMQ (с JMS адаптером)
  • IBM MQ
  • JBoss HornetQ

Пример использования JMS

// Producer (отправитель)
@Component
public class OrderMessageSender {
    @Autowired
    private JmsTemplate jmsTemplate;
    
    public void sendOrder(Order order) {
        // Простая отправка сообщения
        jmsTemplate.convertAndSend("orders.queue", order);
    }
}

// Consumer (получатель)
@Component
public class OrderMessageListener {
    @JmsListener(destination = "orders.queue")
    public void handleMessage(Order order) {
        System.out.println("Received order: " + order.getId());
        // Обработка заказа
    }
}

Что такое Kafka

Kafka — это конкретная реализация event streaming платформы, разработанная LinkedIn. Это не просто message broker, а распределённая система обработки событий, оптимизированная для высоких нагрузок и потоковой обработки данных.

Пример использования Kafka

// Producer (отправитель)
@Component
public class OrderEventProducer {
    @Autowired
    private KafkaTemplate<String, Order> kafkaTemplate;
    
    public void sendOrder(Order order) {
        kafkaTemplate.send("orders-topic", order.getId().toString(), order);
    }
}

// Consumer (получатель)
@Component
public class OrderEventListener {
    @KafkaListener(topics = "orders-topic", groupId = "order-service")
    public void handleMessage(Order order) {
        System.out.println("Received order: " + order.getId());
    }
}

Основные отличия

1. Архитектура

JMS:

Producer → Message Broker (ActiveMQ/RabbitMQ) → Consumer
           (Очередь/Топик)
  • Централизованный broker
  • Простая архитектура
  • Меньше узлов

Kafka:

Producer → Cluster of Brokers → Consumer Group
           (Multiple partitions)
           (Replication factor)
  • Распределённый кластер
  • Масштабируемая архитектура
  • Много узлов с репликацией

2. Модель доставки сообщений

JMS (Point-to-Point / Pub-Sub):

// Queue (Point-to-Point) - один потребитель получает
jmsTemplate.convertAndSend("orders.queue", order);
// Только ОДИН слушатель обработает

// Topic (Pub-Sub) - все подписчики получают
jmsTemplate.convertAndSend("orders.topic", order);
// ВСЕ подписчики получат копию

Kafka (только Topic с Consumer Groups):

// Один топик
kafkaTemplate.send("orders-topic", order);

// Разные consumer groups получат независимо
// group1: потребляет сообщения
// group2: потребляет те же сообщения (каждому своя копия)

3. Сохранение сообщений

JMS:

  • Сообщения обычно удаляются после доставки
  • Если потребитель упал, может потеряться
  • Есть persistent mode (сохраняет в БД/диск), но это медленнее
// Persistent message (медленнее)
jmsTemplate.convertAndSend(new MessageCreator() {
    @Override
    public Message createMessage(Session session) throws JMSException {
        Message msg = session.createObjectMessage(order);
        msg.setJMSDeliveryMode(DeliveryMode.PERSISTENT);
        return msg;
    }
});

Kafka:

  • Все сообщения по умолчанию сохраняются на диск
  • Политика хранения (по времени или размеру): retention.ms, retention.bytes
  • Потребитель может пересчитать сообщения "с начала"
// Kafka сохраняет по умолчанию
// Конфигурация
kafka:
  broker-version-fallback: 2.8.0
  properties:
    retention.ms: 604800000  // 7 дней
    retention.bytes: -1      // unlimited

4. Масштабируемость

JMS:

  • Масштабируется до тысяч сообщений в секунду
  • Один broker может стать бутылочным горлышком
  • Кластеризация сложнее

Kafka:

  • Масштабируется до миллионов сообщений в секунду
  • Партиции позволяют распределить нагрузку
  • Horizontal scaling встроен
// Kafka партиции
Topic: orders-topic
Partition 0: messages 1-1000
Partition 1: messages 1001-2000
Partition 2: messages 2001-3000

// Каждый consumer обрабатывает свою партицию
Consumer 1 → Partition 0
Consumer 2 → Partition 1
Consumer 3 → Partition 2

5. Гарантии доставки

JMS:

// Гарантии
AUTO_ACKNOWLEDGE        // Авто подтверждение (может потеряться)
CLIENT_ACKNOWLEDGE      // Ручное подтверждение
DUPS_OK_ACKNOWLEDGE     // Дубликаты допустимы
TRANSACTED             // Транзакционная доставка

@JmsListener(destination = "orders.queue", 
             containerFactory = "jmsListenerContainerFactory")
public void handleMessage(Order order, Session session) {
    try {
        processOrder(order);
        // Ручное подтверждение
    } catch (Exception e) {
        // Автоматический redelivery
    }
}

Kafka:

// Гарантии
AT_MOST_ONCE    // 0 или 1 раз (может потеряться)
AT_LEAST_ONCE   // 1+ раз (может быть дубликат)
EXACTLY_ONCE    // Ровно 1 раз (транзакции)

// Конфигурация
spring:
  kafka:
    consumer:
      auto-offset-reset: earliest  // Или latest
      enable-auto-commit: false    // Ручное подтверждение

@KafkaListener(topics = "orders-topic", groupId = "order-service")
public void handleMessage(Order order, Acknowledgment ack) {
    try {
        processOrder(order);
        ack.acknowledge();  // Ручное подтверждение
    } catch (Exception e) {
        // Сообщение остаётся в топике
    }
}

6. Скорость

JMS:

  • Задержка (latency): 10-100ms
  • Throughput: тысячи сообщений/сек

Kafka:

  • Задержка (latency): 1-10ms
  • Throughput: миллионы сообщений/сек

7. Сложность

JMS:

// Простой пример с ActiveMQ
@Configuration
@EnableJms
public class JmsConfig {
    @Bean
    public ConnectionFactory connectionFactory() {
        return new ActiveMQConnectionFactory("tcp://localhost:61616");
    }
    
    @Bean
    public JmsTemplate jmsTemplate(ConnectionFactory cf) {
        return new JmsTemplate(cf);
    }
}

// Использование
jmsTemplate.convertAndSend("myQueue", "message");

Kafka:

// Требует больше конфигурации для production
@Configuration
public class KafkaConfig {
    @Bean
    public ConsumerFactory<String, Order> consumerFactory() {
        Map<String, Object> props = new HashMap<>();
        props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
        props.put(ConsumerConfig.GROUP_ID_CONFIG, "order-service");
        props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
        props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, JsonDeserializer.class);
        return new DefaultKafkaConsumerFactory<>(props);
    }
    
    @Bean
    public ConcurrentKafkaListenerContainerFactory<String, Order> kafkaListenerContainerFactory() {
        ConcurrentKafkaListenerContainerFactory<String, Order> factory =
            new ConcurrentKafkaListenerContainerFactory<>();
        factory.setConsumerFactory(consumerFactory());
        return factory;
    }
}

Таблица сравнения

ПараметрJMSKafka
ТипAPI/СпецификацияКонкретная реализация
BrokersОдин (централизованный)Кластер
МасштабируемостьДо тысяч msg/secДо миллионов msg/sec
СохранениеОпциональноПо умолчанию
PartitioningНетВстроено
ReplicationОпциональноВстроено
Consumer GroupsНетДа (встроено)
Лучше дляТрадиционные очередиПотоковая обработка
СложностьПростой setupСложнее setup
Обработка данныхПосредственнаяОтличная (Stream API)

Когда использовать

Используй JMS когда:

✅ Простая архитектура ✅ Меньше 1000 msg/sec ✅ Нужны традиционные очереди ✅ Быстро нужен результат ✅ Команда не опытна с распределёнными системами

Примеры: отправка email, SMS уведомлений, простые задачи в очереди

Используй Kafka когда:

✅ High-load системы (> 1000 msg/sec) ✅ Потоковая обработка данных ✅ Нужно воспроизводить события ✅ Data pipelines и analytics ✅ Event sourcing ✅ Микросервисная архитектура

Примеры: логирование, аналитика в реальном времени, Event-driven архитектура, Data streaming

Практические примеры

JMS: Отправка email

@Service
public class EmailService {
    @Autowired
    private JmsTemplate jmsTemplate;
    
    public void sendOrderConfirmation(Order order) {
        jmsTemplate.convertAndSend("email.queue", 
            new EmailMessage(order.getEmail(), "Order confirmed"));
    }
}

Kafka: Event-driven архитектура

@Service
public class OrderService {
    @Autowired
    private KafkaTemplate<String, OrderEvent> kafkaTemplate;
    
    public void createOrder(Order order) {
        Order saved = repository.save(order);
        // Публикуем событие
        kafkaTemplate.send("order-events", OrderEvent.created(saved));
    }
}

// Другие сервисы слушают событие
@Component
public class NotificationService {
    @KafkaListener(topics = "order-events")
    public void onOrderCreated(OrderEvent event) {
        if (event.type == "CREATED") {
            // Отправить уведомление
        }
    }
}

@Component
public class AnalyticsService {
    @KafkaListener(topics = "order-events")
    public void onOrderCreated(OrderEvent event) {
        // Собрать метрики
    }
}

Резюме

  • JMS — это стандарт Java для message-oriented middleware, простой и понятный
  • Kafka — это распределённая event streaming платформа, оптимизирована для high-load
  • JMS лучше для простых очередей
  • Kafka лучше для современных микросервисов и потоковой обработки
  • В микросервисной архитектуре Kafka часто выигрывает благодаря масштабируемости и встроенной поддержке consumer groups