Когда использовать актеров вместо решений для обмена сообщениями, таких как WebSphere MQ или Tibco Rendezvous?

Я уже прочитал вопрос и ответы на Какие дизайнерские решения понравятся Scala Актерам вместо JMS?.

Обычно мы используем решения для обмена сообщениями, которые существовали уже много лет: для обмена сообщениями "точка-точка" используется реализация JMS, такая как WebSphere MQ или Apache ActiveMQ, или Tibco Rendevous для многоадресной рассылки.

Они очень стабильны, проверены и обеспечивают высокую доступность и производительность. Тем не менее конфигурация и настройка кажутся намного более сложными, чем в Akka.

Когда и почему я должен использовать Akka для некоторых случаев использования, когда вышеупомянутые продукты - WebSphere MQ или ActiveMQ - были успешно использованы до сих пор? Почему я должен использовать Akka вместо WebSphere MQ или Tibco RV в моем будущем проекте?

И когда мне следует избегать Акки? Имеет ли он такую ​​же высокую доступность и производительность, что и другие решения? Или это плохая идея, чтобы сравнить Akka с другими посредниками обмена сообщениями?

Возможно, есть и другое решение для обмена сообщениями в среде JVM, которое я должен рассмотреть помимо JMS (Point-to-Point), TibcoRV (Multicast) и Akka?

Ответ 1

Сначала "старые" системы сообщений (MQ) старше в реализации, но они новее в технической идее: постоянных очередей транзакций. Scala Актеры и Акка могут быть более новой реализацией, но построены на более старой модели актеров concurrency.

Две модели, однако, на самом деле очень похожи на практике, потому что оба они основаны на событиях: см. мой ответ на RabbitMQ vs Akka.

Если вы собираетесь кодировать только для JVM, то Akka, вероятно, является хорошим выбором. В противном случае я бы использовал RabbitMQ.

Кроме того, если вы разработчик Scala, то Akka должен быть без проблем. Однако привязки Java Akka не очень Java-иш и требуют кастинга из-за системы типа Scala.

Также в Java люди обычно не создают неизменяемые объекты, которые я рекомендую вам делать для обмена сообщениями. Следовательно, очень просто в Java случайно сделать что-то, используя Akka, который не будет масштабироваться (используя изменяемые объекты для сообщений, полагаясь на странное состояние обратного вызова). С MQ это не проблема, потому что сообщения всегда сериализуются за счет скорости. С Аккой, как правило, нет.

Akka также масштабируется лучше с большим количеством потребителей, чем большинство MQ. Это связано с тем, что для большинства клиентов MQ (JMS, AMQP) для каждого соединения в очереди требуется поток... таким образом, много очередей == много постоянно работающих потоков. Это, в основном, проблема с клиентами. Я думаю, что у ActiveMQ Apollo есть неблокирующий диспетчер, который якобы исправляет эту проблему для AMQP. У клиента RabbitMQ есть каналы, которые позволяют объединять несколько потребителей, но по-прежнему возникают проблемы с большим количеством потребителей, потенциально вызывающих блокировки или соединения, чтобы убить, поэтому, как правило, больше потоков добавляются, чтобы избежать этой проблемы.

Говоря, что Akka remoting является довольно новым и, вероятно, все еще не предлагает все надежные гарантии сообщений и QoS, которые предоставляют традиционные очереди сообщений ( но это меняется каждый день). Он также, как правило, является одноранговым, но я думаю, что он поддерживает сервер-точка, что обычно является большинством систем MQ (т.е. единственной точкой отказа), но есть системы MQ, которые являются одноранговыми (RabbitMQ - равный).

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

Когда выбрать Akka

  • Имейте много потребителей (думайте миллионы).
  • Требуется низкая латентность
  • Открыть для модели Actor concurrency

Пример системы: интерактивная чат-система реального времени

Когда выбрать MQ

  • Нужно интегрировать с множеством разных систем (то есть без JVM).
  • Надежность сообщения важнее задержки
  • Вам нужны дополнительные инструменты и пользовательский интерфейс администратора
  • Из-за предыдущих пунктов лучше для длительных задач
  • Хотелось бы использовать другую concurrency модель, чем Actors

Пример системы: запланированная система пакетной обработки транзакций

РЕДАКТИРОВАТЬ на основе соответствующих комментариев

Я сделал предположение, что OP был связан с распределенной обработкой, которую могут обрабатывать как Akka, так и очереди сообщений. То есть я предполагал, что он говорил о распределенном Akka. Использование Akka для локального concurrency - это сравнение яблок с апельсинами для большинства очередей сообщений. Я говорю больше всего, потому что вы можете применить модель очереди сообщений локально как модель concurrency (т.е. тема, очереди, обмены), которые как Reactor library и simple-react do.

Выбор правильной модели/библиотеки concurrency очень важен для приложений с малой задержкой. Распределенное решение обработки, такое как очередь сообщений, как правило, не идеально, потому что маршрутизация почти всегда выполняется по проводу, который, очевидно, медленнее, чем в приложении, и, таким образом, Akka будет лучшим выбором. Однако я считаю, что некоторые собственные технологии MQ позволяют локальную маршрутизацию. Кроме того, как я уже упоминал ранее, большинство клиентов MQ довольно глупы в отношении потоковой обработки и не полагаются на неблокирующий IO и имеют поток на соединение/очередь/канал... по иронии судьбы неблокирующий io не всегда имеет низкую задержку, но, как правило, больше ресурсов эффективным.

Как вы можете видеть, тема распределенного программирования и параллельного программирования довольно велика и меняется каждый день, поэтому мое первоначальное намерение не смущало, а скорее фокусировалось на одной конкретной области обработки распределенных сообщений, что и было связано с тем, что я имел в виду OP. В терминах concurrency можно сосредоточить свои поиски на "реактивном" программировании (RFP/streams), который является "более новой", но подобной моделью для модели актера и модели очереди сообщений, из которой все эти модели могут быть в целом объединены потому что они основаны на событиях.

Ответ 2

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

https://github.com/zcox/akka-zeromq-java

Ответ 3

Akka-Camel будет лучшим примером, чем ZeroMQ. ZeroMQ - это прямая связь tcp с tcp (следовательно, нуль - очереди сообщений нет).

С помощью AkkaCamel вы можете абстрагироваться от очереди и создавать/потреблять сообщения прямо от актера без какого-либо кода, чтобы справиться с нажатием/выводом сообщения очереди сообщений.

Вы можете отказаться от akka-zeromq и использовать Akka непосредственно с удалением. Я думаю, что akka-zeromq удаляется из основной библиотеки, но мы создали хорошую библиотеку zeromq для akka под названием scala -zeromq (https://github.com/mDialog/scala-zeromq)

В Akka есть несколько ключевых случаев использования ядра:

1) Mutable state

Легче обрабатывать совместное состояние, скрывая его в актере. Поскольку субъекты обрабатывают сообщения синхронно, вы можете удерживать состояние в актере и выставлять это поле с высокой согласованностью через API-интерфейс actor

2) Распространение

Concurrency является бесплатным в akka, поэтому вы действительно говорите об устранении проблем с дистрибуцией. Распределение по машинам и ядрам. Akka построила "прозрачность местоположения" для отправки сообщений по проводу. Он имеет кластеризацию и паттеры, связанные с масштабированием одной службы. Это делает его очень хорошим решением для распространения (например, архитектура микросервиса).

Вот пример использования Akka с ActiveMQ с Akka-Camel (с использованием Java8)

import akka.actor.Props;
import akka.camel.Camel;
import akka.camel.CamelExtension;
import akka.testkit.TestActorRef;
import akka.testkit.TestProbe;
import org.junit.Ignore;
import org.junit.Test;
import akka.camel.javaapi.UntypedProducerActor;
import akka.camel.javaapi.UntypedConsumerActor;
import static com.rogers.totes.TotesTestFixtures.*;
import org.apache.activemq.camel.component.*;

public class MessagingTest {
    @Test @Ignore
    public void itShouldStoreAMessage() throws Exception{
        String amqUrl = "nio://localhost:61616";
        Camel camel = (Camel) CamelExtension.apply(system);
        camel.context().addComponent("activemq", ActiveMQComponent.activeMQComponent(amqUrl));

        TestProbe probe = TestProbe.apply(system);
        TestActorRef producer = TestActorRef.create(system, Props.create((Producer.class)));
        TestActorRef consumer = TestActorRef.create(system, Props.create((Consumer.class)));
        producer.tell("Produce", probe.ref());

        Thread.sleep(1000);
    }
}

class Producer extends UntypedProducerActor{

    @Override
    public String getEndpointUri() {
        return "activemq:foo.bar";
    }
}

class Consumer extends UntypedConsumerActor{

    @Override
    public String getEndpointUri() {
        return "activemq:foo.bar";
    }

    @Override
    public void onReceive(Object message) throws Exception {
        System.out.println("GOT A MESSAGE!" + message);

    }
}