Коли використовувати актори замість обміну повідомленнями, такими як WebSphere MQ або Tibco Rendezvous?


106

Я вже читав питання та відповіді на те, які дизайнерські рішення віддають перевагу акторам Scala замість JMS? .

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

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

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

І коли я повинен уникати Акки? Чи пропонує вона таку ж високу доступність та продуктивність, що й інші рішення? Або це погана ідея навіть порівнювати Акку з іншими посередницькими повідомленнями?

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


Відповіді:


92

По-перше, "старіші" системи повідомлень (MQ) старші у впровадженні, але вони новіші в інженерній ідеї: стійкі транзакційні черги . Scala Actors та Akka, можливо, новіша реалізація, але побудовані на старій моделі одночасності Actors.

Обидві моделі, однак, на практиці дуже схожі, тому що обидві вони базуються на повідомленні про події: Дивіться мою відповідь на RabbitMQ vs Akka .

Якщо ви збираєтеся кодувати лише JVM, то Akka, ймовірно, хороший вибір. Інакше я б використав RabbitMQ.

Крім того, якщо ви розробник Scala, то Акка повинен бути непродуманим. Однак прив'язки Java до Java не є дуже Java-ish і вимагають лиття завдяки системі типу Scala.

Також на Java люди зазвичай не роблять незмінних об'єктів, які я рекомендую робити для обміну повідомленнями. Отже, в Java дуже просто випадково зробити щось, використовуючи Akka, що не змінює масштаб (використовуючи змінні об’єкти для повідомлень, спираючись на дивний стан зворотного виклику закриття). З MQ це не проблема, оскільки повідомлення завжди серіалізуються ціною швидкості. З Аккою вони взагалі ні.

Akka також краще масштабує велику кількість споживачів, ніж більшість MQ. Це тому, що для більшості клієнтів MQ (JMS, AMQP) для кожного з'єднання черги потрібна нитка ... таким чином, безліч черг == безліч постійно працюючих потоків. В основному це питання клієнта. Я думаю, що ActiveMQ Apollo має незаблокувальний диспетчер, який нібито виправляє цю проблему для AMQP. Клієнт RabbitMQ має канали, які дозволяють об'єднати декількох споживачів, але все ще існують проблеми з великою кількістю споживачів, які потенційно можуть спричинити відмирання тупиків або з’єднань, тому, як правило, додано більше потоків, щоб уникнути цієї проблеми.

Але, скажімо, видалення Акки є доволі новим і, ймовірно, все ще не пропонує всіх надійних гарантій повідомлень та QoS, які надають традиційні черги повідомлень (але це змінюється щодня). Її також взагалі одноранговий, але я думаю, що підтримує сервер-до-одноранговий, що, як правило, робить більшість MQ-систем (тобто, одна точка відмови), але є системи MQ, які є одноранговими (RabbitMQ - це сервер- to-peer).

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

Коли вибрати Акку

  • Мають багато споживачів (думають мільйони).
  • Потрібна низька затримка
  • Відкрийте модель паралельної гри Actor

Приклад системи: інтерактивна система чату в режимі реального часу

Коли вибрати MQ

  • Необхідність інтеграції з великою кількістю різних систем (тобто, не JVM)
  • Надійність повідомлення важливіша затримка
  • Хочеться більше інструментів та інтерфейсу адміністратора
  • Через попередні бали краще для тривалих виконання завдань
  • Хотіли б використовувати іншу модель одночасності, ніж Актори

Приклад системи: Планова транзакційна система пакетної обробки

EDIT на основі заклопотаних коментарів

Я зробив припущення, що ОП стосується розподіленої обробки, з якою можуть працювати і Акка, і Черги повідомлень. Тобто я припускаю, що він говорив про розподілену Акку . Використання Akka для локальної паралельності - це яблуко-помаранчеве порівняння з більшістю черг повідомлень . Я кажу найбільше, тому що ви можете застосувати модель черги повідомлень локально як модель одночасності (тобто тему, черги, обміни), що і бібліотека Reactor, і проста реакція .

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

Як ви бачите, тема розподіленого програмування та паралельного програмування є досить великою і щодня змінюється, тому мій початковий задум не був переплутаним, а зосереджений на одній конкретній області розподіленої обробки повідомлень, що я хоч і стосувався ОП. З точки зору одночасності можна сфокусувати свої пошуки на "реактивному" програмуванні (RFP / потоки), що є "більш новою", але подібною моделлю до акторської моделі та моделі черги повідомлень, з якою всі ці моделі можуть бути об'єднані, оскільки вони на основі подій.


3
Я думаю, що відповідь на неправильне запитання не може бути правильним. Ви не можете порівняти чергу повідомлень та модель одночасності. Вони побудовані для вирішення ЦІЛЬКО різних завдань і мають спільне лише слово "повідомлення".
Ігор С.

2
Ну так і ні. Akka підтримує розподілене обмін повідомленнями, і ви можете дуже легко створити модель паралельності поза парадигмою черги повідомлень (google Spring's Reactor). Дійсно єдиною відмінністю зараз є те, що RabbitMQ має міцні повідомлення. Він може сказати "Актор" у назві, але прямо вказує на Акку, який має величезне перекриття з багатьма системами на основі повідомлень (як паралельними, так і розподіленими).
Адам Гент

4
BTW @IgorS. типова модель одночасності, яка використовується з чергами повідомлень, називається SEDA (поетапна архітектура, керована подіями). Окрім використання черг, тем і обмінів, сама по собі є модель паралельності (що, звичайно, також поширюється модель .. так само, як і модель актора). Я також дуже зневажаю, коли хтось каже "неправильне запитання" .. окрім невідповідних питань, коли питання може бути неправильним? Її химерно і елітарно сказати щось подібне.
Адам Гент

1
Я ніколи не говорив, що вони взаємозамінні. Я навіть кажу, що вони чудово працюють разом і чому. Але він явно говорить про розподілену акку тут, а не на акку бібліотеку актора. Ось як я це прочитав. Не соромтесь редагувати мою публікацію, оскільки ваша думка є дійсною і може заплутати інших, хто натикається на цю публікацію.
Адам Гент

1
Один API Akka Java - він зараз дуже чистий, особливо з лямбдами JDK 8. Я підозрюю, що стане краще, якщо / коли вони введуть цінні об’єкти з JDK 10.
Роб Кроуфорд

4

Я не є експертом у системах обміну повідомленнями, але ви можете комбінувати їх із Akka у своїх додатках, отримуючи найкращі з обох верств. Ось приклад, який може бути корисним для експериментів із Akka та системами обміну повідомленнями, в даному випадку ZeroMQ:

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


6
ZeroMQ - це не зовсім система обміну повідомленнями. Це скоріше якісь вдосконалені розетки. Повноцінні системи обміну повідомленнями набагато складніші, ніж ZeroMQ. Проект за вашим посиланням здається лише тонкою обгорткою навколо ZeroMQ з Akka.
Володимир Матвєєв

1

Akka-Camel був би кращим прикладом, ніж ZeroMQ - ZeroMQ є прямим tcp для зв'язку tcp (отже, нуль - немає черги повідомлень).

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

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

У Akka є кілька ключових випадків використання основних процесів:

1) стан, що змінюється

Простіше обробити спільний стан, сховавши його в актора. Оскільки актори обробляють повідомлення синхронно, ви можете утримувати стан в акторі та виставляти це поле з високою послідовністю за допомогою API актора

2) Поширення

Конкурс в акці безкоштовний, тому ви кажете, що це дійсно стосується вирішення проблем з розподілом. Розподіл по машинах і кернам. 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);

    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.