Kiedy używać aktorów zamiast rozwiązań komunikacyjnych, takich jak WebSphere MQ lub Tibco Rendezvous?

106

Przeczytałem już pytanie i odpowiedzi na pytanie, jakie decyzje projektowe sprzyjałyby aktorom Scali zamiast JMS? .

Zwykle używamy rozwiązań komunikacyjnych, które istnieją już od lat: albo implementacja JMS, taka jak WebSphere MQ lub Apache ActiveMQ jest używana do komunikacji Point-To-Point, albo Tibco Rendevous do przesyłania wiadomości w trybie Multicast.

Są bardzo stabilne, sprawdzone i oferują wysoką dostępność i wydajność. Niemniej jednak konfiguracja i konfiguracja wydają się znacznie bardziej złożone niż w Akce.

Kiedy i dlaczego powinienem używać Akka w niektórych przypadkach użycia, w których wyżej wymienione produkty - WebSphere MQ lub ActiveMQ - były dotychczas z powodzeniem używane? Dlaczego powinienem rozważyć użycie Akka zamiast WebSphere MQ lub Tibco RV w moim przyszłym projekcie?

A kiedy powinienem unikać Akki? Czy zapewnia taką samą wysoką dostępność i wydajność, jak inne rozwiązania? A może złym pomysłem jest nawet porównywanie Akki z innymi programami pośredniczącymi do przesyłania wiadomości?

Może jest też inne rozwiązanie do przesyłania wiadomości w środowisku JVM, które powinienem wziąć pod uwagę oprócz JMS (Point-to-Point), TibcoRV (Multicast) i Akka?

Kai Wähner
źródło

Odpowiedzi:

92

Po pierwsze, „starsze” systemy komunikatów (MQ) są starsze w implementacji, ale są nowszym pomysłem inżynieryjnym na: transakcyjne trwałe kolejki . Scala Actors i Akka mogą być nowszą implementacją, ale są zbudowane na starszym modelu współbieżności Actors.

Te dwa modele są jednak w praktyce bardzo podobne, ponieważ oba są oparte na komunikatach zdarzeń: Zobacz moją odpowiedź na pytanie RabbitMQ vs Akka .

Jeśli zamierzasz kodować tylko dla JVM, Akka jest prawdopodobnie dobrym wyborem. W przeciwnym razie użyłbym RabbitMQ.

Również jeśli jesteś programistą Scala, Akka nie powinna się zastanawiać. Jednak powiązania Java Akki nie są bardzo Java-ish i wymagają rzutowania ze względu na system typów Scali.

Również w Javie ludzie zazwyczaj nie tworzą niezmiennych obiektów, co polecam do przesyłania wiadomości. W związku z tym bardzo łatwo jest w Javie przypadkowo zrobić coś za pomocą Akki, co nie będzie skalowane (używanie mutowalnych obiektów dla komunikatów, poleganie na dziwnym stanie wywołania zwrotnego zamknięcia). W przypadku MQ nie stanowi to problemu, ponieważ komunikaty są zawsze serializowane kosztem szybkości. W przypadku Akki generalnie nie są.

Akka również lepiej skaluje się przy dużej liczbie konsumentów niż większość MQ. Dzieje się tak, ponieważ w przypadku większości klientów MQ (JMS, AMQP) każde połączenie kolejki wymaga wątku ... a zatem wiele kolejek == wiele stale działających wątków. Jest to jednak głównie kwestia klienta. Myślę, że ActiveMQ Apollo ma nieblokującego dyspozytora, który rzekomo rozwiązuje ten problem dla AMQP. Klient RabbitMQ ma kanały, które umożliwiają łączenie wielu odbiorców, ale nadal występują problemy z dużą liczbą konsumentów, które mogą powodować zakleszczenia lub zanik połączeń, więc generalnie dodaje się więcej wątków, aby uniknąć tego problemu.

To powiedziawszy , komunikacja zdalna Akki jest raczej nowa i prawdopodobnie nadal nie oferuje wszystkich niezawodnych gwarancji wiadomości i QoS, które zapewniają tradycyjne kolejki wiadomości (ale to się zmienia każdego dnia). Jest to również ogólnie peer-to-peer, ale czy myślę, że obsługuje serwer-każdy, co jest generalnie tym, co robi większość systemów MQ (tj. Pojedynczy punkt awarii), ale są systemy MQ, które są równe to-peer).

Wreszcie RabbitMQ i Akka tworzą dobrą parę. Akka może służyć jako opakowanie dla RabbitMQ, zwłaszcza że RabbitMQ nie pomaga w obsłudze zużycia komunikatów i kierowaniu komunikatów lokalnie (w pojedynczej maszynie JVM).

Kiedy wybrać Akka

  • Miej wielu konsumentów (myślę, że miliony).
  • Potrzebujesz małego opóźnienia
  • Otwórz na model współbieżności aktora

Przykładowy system: interaktywny system czatu w czasie rzeczywistym

Kiedy wybrać MQ

  • Konieczność integracji z wieloma różnymi systemami (np. Innymi niż JVM)
  • Wiarygodność wiadomości jest ważniejsza niż opóźnienie
  • Chciałbym mieć więcej narzędzi i interfejsu administratora
  • Ze względu na poprzednie punkty lepiej dla długotrwałych zadań
  • Chciałby użyć innego modelu współbieżności niż Actors

Przykładowy system: zaplanowany transakcyjny system przetwarzania wsadowego

EDYCJA na podstawie odpowiednich komentarzy

Założyłem, że OP dotyczy przetwarzania rozproszonego, które mogą obsługiwać zarówno Akka, jak i Message Queues. To znaczy założyłem, że mówił o dystrybuowanej Akce . Używanie Akka do lokalnej współbieżności to porównanie jabłek do pomarańczy z większością kolejek wiadomości . Mówię najwięcej, ponieważ możesz zastosować model kolejki wiadomości lokalnie jako model współbieżności (tj. Temat, kolejki, wymiany), co robi zarówno biblioteka Reactor, jak i simple-respond .

Wybór odpowiedniego modelu / biblioteki współbieżności jest bardzo ważny w przypadku aplikacji o małych opóźnieniach. Rozproszone rozwiązanie przetwarzania, takie jak kolejka komunikatów, generalnie nie jest idealne, ponieważ trasowanie prawie zawsze odbywa się za pośrednictwem połączenia, co jest oczywiście wolniejsze niż w aplikacji, a zatem Akka byłaby lepszym wyborem. Uważam jednak, że niektóre zastrzeżone technologie MQ umożliwiają routing lokalny. Ponadto, jak wspomniałem wcześniej, większość klientów MQ jest dość głupia jeśli chodzi o wątkowanie i nie polega na nieblokujących IO i ma wątek na połączenie / kolejkę / kanał ... jak na ironię, nieblokujące operacje we / wy nie zawsze mają małe opóźnienia, ale generalnie są bardziej zasobami wydajny.

Jak widać, temat programowania rozproszonego i programowania współbieżnego jest dość obszerny i zmienia się każdego dnia, więc moim pierwotnym zamiarem nie było zamieszanie, ale raczej skupienie się na jednym konkretnym obszarze przetwarzania rozproszonych komunikatów, o którym myślałem, że dotyczył PO. Jeśli chodzi o współbieżność, można by chcieć skoncentrować swoje wyszukiwania na programowaniu „reaktywnym” (zapytania ofertowe / strumienie), które jest „nowszym”, ale podobnym modelem do modelu aktora i modelu kolejki wiadomości, z których wszystkie te modele można ogólnie łączyć, ponieważ są oparte na wydarzeniach.

Adam Gent
źródło
3
Myślę, że odpowiedź na złe pytanie nie może być dobra. Nie można porównać kolejki komunikatów i modelu współbieżności. Są zbudowane do rozwiązywania CAŁKOWICIE różnych zadań i mają wspólne tylko słowo „przesłanie”.
Igor S.
2
Cóż, tak i nie. Akka obsługuje rozproszone przesyłanie wiadomości i można bardzo łatwo zbudować model współbieżności na podstawie paradygmatu kolejki wiadomości (Google Spring's Reactor). Naprawdę jedyną różnicą jest teraz to, że RabbitMQ ma trwałe komunikaty ... o, czekaj, Akka teraz również to obsługuje. W tytule może powiedzieć „Aktor”, ale wyraźnie wskazuje na Akkę, która masowo pokrywa się z wieloma systemami opartymi na komunikatach (zarówno współbieżnych, jak i rozproszonych).
Adam Gent
4
BTW @IgorS. typowy model współbieżności używany z kolejkami komunikatów nosi nazwę SEDA (architektura sterowana zdarzeniami etapowymi). Poza tym używanie kolejek, tematów i wymian jest modelem współbieżności sam w sobie (tak się składa, że ​​jest to również model rozproszony ... podobnie jak model aktora). Naprawdę gardzę też, gdy ktoś mówi „złe pytanie”… kiedy pytanie, poza niestosownymi, może być błędne? Powiedzenie czegoś takiego jest złośliwe i elitarne.
Adam Gent
1
Nigdy nie powiedziałem, że są wymienne. Mówię nawet, że świetnie ze sobą współpracują i dlaczego. Ale on wyraźnie mówi o rozproszonej akce tutaj, a nie o akka bibliotece. Tak to przeczytałem. Zapraszam do edycji mojego postu, ponieważ Twój punkt jest ważny i może zmylić innych, którzy natkną się na post.
Adam Gent
1
Jeden z API Akka Java - jest teraz bardzo czysty, szczególnie z lambdami JDK 8. Podejrzewam, że będzie lepiej, jeśli / kiedy wprowadzą obiekty wartościowe za pomocą JDK 10.
Rob Crawford
4

Nie jestem ekspertem w systemach przesyłania wiadomości, ale możesz łączyć je z Akką w swoich aplikacjach, uzyskując to, co najlepsze z obu światów. Oto przykład, który może Ci się przydać podczas eksperymentowania z Akka i systemami przesyłania wiadomości, w tym przypadku ZeroMQ:

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

Dean Wampler
źródło
6
ZeroMQ nie jest dokładnie systemem przesyłania wiadomości. To raczej coś w rodzaju ulepszonych gniazd. Pełnoprawne systemy przesyłania wiadomości są znacznie bardziej złożone niż ZeroMQ. Projekt pod twoim linkiem wydaje się być tylko cienkim opakowaniem wokół ZeroMQ z Akka.
Vladimir Matveev
1

Akka-Camel byłby lepszym przykładem niż ZeroMQ - ZeroMQ to bezpośrednia komunikacja tcp do tcp (stąd zero - nie ma kolejki wiadomości).

Dzięki AkkaCamel możesz oddzielić kolejkę i tworzyć / konsumować wiadomości bezpośrednio od aktora bez żadnego kodu do obsługi wypychania / ściągania wiadomości w kolejce wiadomości.

Możesz zrezygnować z akka-zeromq i używać Akka bezpośrednio z obsługą zdalną. Myślę, że akka-zeromq jest usuwana z podstawowej biblioteki, ale zbudowaliśmy dobrą bibliotekę zeromq dla akka o nazwie scala-zeromq ( https://github.com/mDialog/scala-zeromq )

Akka ma kilka kluczowych podstawowych przypadków użycia:

1) Stan mutowalny

Łatwiej jest obsługiwać stan współdzielony, ukrywając go w aktorze. Ponieważ aktorzy obsługują komunikaty synchronicznie, możesz utrzymywać stan aktora i ujawniać to pole z wysoką spójnością za pośrednictwem interfejsu API aktora

2) Dystrybucja

W akka współbieżność jest bezpłatna, więc mówisz, że tak naprawdę chodzi o rozwiązywanie problemów z dystrybucją. Dystrybucja między maszynami i rdzeniami. Akka ma wbudowaną „przejrzystość lokalizacji” do wysyłania wiadomości przez sieć. Ma również powiązane z klastrami i wzorami skalowanie pojedynczej usługi. To sprawia, że ​​jest to bardzo dobre rozwiązanie do dystrybucji (np. Architektura mikroserwisów)

Oto przykład użycia Akka z ActiveMQ z Akka-Camel (przy użyciu 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);

    }
}
JasonG
źródło