[java] WebSphere MQ 또는 Tibco Rendezvous와 같은 메시징 솔루션 대신 액터를 언제 사용해야합니까?

JMS 대신 Scala의 액터를 선호하는 디자인 결정은 무엇입니까?에 대한 질문과 답변을 이미 읽었습니다 . .

일반적으로 우리는 이미 수년 동안 존재 해 온 메시징 솔루션을 사용합니다. WebSphere MQ 또는 Apache ActiveMQ와 같은 JMS 구현은 Point-To-Point 통신에 사용되거나 Tibco Rendevous는 멀티 캐스트 메시징에 사용됩니다.

그들은 매우 안정적이고 입증되었으며 고가용 성과 성능을 제공합니다. 그럼에도 불구하고 구성 및 설정은 Akka보다 훨씬 복잡해 보입니다.

앞서 언급 한 제품 (WebSphere MQ 또는 ActiveMQ)이 지금까지 성공적으로 사용 된 일부 사용 사례에 Akka를 언제, 왜 사용해야합니까? 향후 프로젝트에서 WebSphere MQ 또는 Tibco RV 대신 Akka를 사용해야하는 이유는 무엇입니까?

그리고 언제 Akka를 피해야합니까? 다른 솔루션과 동일한 고 가용성 및 성능을 제공합니까? 아니면 Akka를 다른 메시징 미들웨어와 비교하는 것도 나쁜 생각입니까?

JVM 환경에 JMS (Point-to-Point), TibcoRV (Multicast) 및 Akka 외에 고려해야 할 또 다른 메시징 솔루션이있을 수 있습니까?



답변

먼저 “오래된”메시지 시스템 (MQ)은 구현이 오래되었지만 트랜잭션 영구 대기열 이라는 엔지니어링 아이디어의 새로운 개념입니다 . Scala Actors와 Akka는 새로운 구현 일 수 있지만 이전의 Actors 동시성 모델을 기반으로 구축되었습니다.

그러나 두 모델은 모두 이벤트 메시지 기반이기 때문에 실제로 매우 유사 합니다. RabbitMQ 대 Akka에 대한 내 대답을 참조하십시오 .

JVM 용으로 만 코딩하려는 경우 Akka가 좋은 선택 일 것입니다. 그렇지 않으면 RabbitMQ를 사용합니다.

또한 Scala 개발자라면 Akka는 생각할 필요가 없습니다. 그러나 Akka의 Java 바인딩은 Java와 같지 않으며 Scala의 유형 시스템으로 인해 캐스팅이 필요합니다.

또한 Java에서 사람들은 일반적으로 메시징을 위해 권장하는 불변 객체를 만들지 않습니다. 결과적으로 Java에서 확장되지 않는 Akka를 사용하여 실수로 작업을 수행하는 것은 매우 쉽습니다 (이상한 클로저 콜백 상태에 의존하는 메시지에 대해 변경 가능한 객체 사용). MQ에서는 메시지가 항상 속도를 희생하면서 직렬화되기 때문에 문제가되지 않습니다. Akka에서는 일반적으로 그렇지 않습니다.

Akka는 또한 대부분의 MQ보다 많은 수의 소비자에게 더 잘 확장됩니다. 대부분의 MQ (JMS, AMQP) 클라이언트의 경우 모든 큐 연결에는 스레드가 필요하기 때문입니다. 따라서 많은 큐 == 영구적으로 실행중인 스레드가 많습니다. 이것은 주로 클라이언트 문제입니다. ActiveMQ Apollo에는 AMQP에 대한 문제를 해결하는 비 차단 디스패처가 있다고 생각합니다. RabbitMQ 클라이언트에는 여러 소비자를 결합 할 수있는 채널이 있지만 많은 소비자가 잠재적으로 교착 상태 또는 연결을 중단시킬 수있는 문제가 있으므로 일반적으로이 문제를 피하기 위해 더 많은 스레드가 추가됩니다.

그 존재는 말했다 Akka의 원격이 아니라 새로운 아마도 여전히 신뢰할 수있는 메시지를 보장하고 기존의 메시지 큐가 제공하는 (그러나 매일 변경되는) 것을 QoS를 제공하지 않습니다. 또한 일반적으로 피어 투 피어이지만 일반적으로 대부분의 MQ 시스템이 수행하는 (즉, 단일 실패 지점) 서버 투 피어를 지원한다고 생각하지만 피어 투 피어 (RabbitMQ는 서버- 응시하다).

마지막으로 RabbitMQ와 Akka는 실제로 좋은 쌍을 이룹니다. Akka를 RabbitMQ에 대한 래퍼로 사용할 수 있습니다. 특히 RabbitMQ는 메시지 소비를 처리하고 메시지를 로컬 (단일 JVM에서) 라우팅하는 데 도움이되지 않기 때문입니다.

Akka를 선택하는 경우

  • 많은 소비자를 확보하십시오 (수백만을 생각하십시오).
  • 짧은 대기 시간 필요
  • Actor 동시성 모델 열기

예제 시스템 : 대화 형 실시간 채팅 시스템

MQ를 선택하는 경우

  • 다양한 시스템 (예 : 비 JVM)과 통합해야 함
  • 메시지 안정성이 대기 시간보다 더 중요합니다.
  • 더 많은 도구와 관리 UI를 원합니다.
  • 오래 실행되는 작업에 더 나은 이전 포인트 때문에
  • 액터와 다른 동시성 모델을 사용하고 싶습니다.

예제 시스템 : 예약 된 트랜잭션 일괄 처리 시스템

관련 의견을 기반으로 편집

나는 OP가 Akka 와 Message Queues가 모두 처리 할 수있는 분산 처리와 관련이 있다고 가정했습니다 . 그것은 그가 분산 Akka 에 대해 이야기하고 있다고 가정했습니다 . 로컬 동시성에 Akka를 사용하는 것은 대부분의 메시지 대기열과 비교하여 주황색을 비교하는 것 입니다. Reactor 라이브러리와 단순 반응 모두가 수행하는 동시성 모델 (예 : 주제, 대기열, 교환)로 메시지 대기열 모델을 로컬로 적용 할 수 있기 때문에 가장 많이 말합니다 .

지연 시간이 짧은 애플리케이션에서는 올바른 동시성 모델 / 라이브러리를 선택하는 것이 매우 중요합니다. 메시지 큐와 같은 분산 처리 솔루션은 일반적으로 라우팅이 거의 항상 유선을 통해 수행되기 때문에 이상적이지 않습니다. 이는 애플리케이션 내에서보다 분명히 느리므로 Akka가 우수한 선택이 될 것입니다. 그러나 일부 독점 MQ 기술은 로컬 라우팅을 허용합니다. 또한 앞서 언급했듯이 대부분의 MQ 클라이언트는 스레딩에 대해 꽤 어리 석고 비 차단 IO에 의존하지 않고 연결 / 대기열 / 채널당 스레드를 가지고 있습니다. 실력 있는.

보시다시피 분산 프로그래밍과 동시 프로그래밍의 주제는 다소 크고 매일 변하기 때문에 원래 의도는 혼란스럽지 않고 OP가 관심을 기울인 분산 메시지 처리의 특정 영역에 집중했습니다. 동시성 측면에서 검색을 “리 액티브”프로그래밍 (RFP / 스트림)에 집중하고 싶을 수 있습니다. “리 액티브”프로그래밍 (RFP / 스트림)은 “최신”이지만 액터 모델 및 메시지 큐 모델과 유사합니다. 이러한 모델은 모두 일반적으로 결합 될 수 있습니다. 이벤트 기반입니다.


답변

저는 메시징 시스템 전문가는 아니지만 앱에서 Akka와 결합하여 두 가지 장점을 모두 활용할 수 있습니다. 다음은 Akka 및 메시징 시스템 (이 경우 ZeroMQ)을 실험하는 데 유용 할 수있는 예입니다.

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


답변

Akka-Camel은 ZeroMQ보다 더 좋은 예가 될 것입니다. ZeroMQ는 직접 tcp 대 tcp 통신입니다 (따라서 0-메시지 큐가 없음).

AkkaCamel을 사용하면 큐를 추상화하고 메시지 큐 메시지 푸시 / 풀링을 처리하는 코드없이 액터에서 직접 메시지를 생성 / 소비 할 수 있습니다.

akka-zeromq를 무시하고 Akka를 원격으로 직접 사용할 수 있습니다. akka-zeromq가 코어 라이브러리에서 제거되고 있다고 생각하지만 우리는 scala-zeromq ( https://github.com/mDialog/scala-zeromq ) 라는 akka에 대한 좋은 zeromq 라이브러리를 구축했습니다.

Akka에는 몇 가지 핵심 사용 사례가 있습니다.

1) 가변 상태

공유 상태를 액터에 숨겨서 처리하는 것이 더 쉽습니다. 액터가 메시지를 동기식으로 처리하므로 액터에 상태를 유지하고 액터 API를 통해 높은 일관성으로 해당 필드를 노출 할 수 있습니다.

2) 유통

동시성은 akka에서 무료이므로 배포 문제를 해결하는 것이라고 말합니다. 머신과 코어에 배포. Akka는 유선으로 메시지를 보내기위한 “위치 투명성”을 구축했습니다. 단일 서비스를 확장하기위한 클러스터링 및 패턴도 연결되어 있습니다. 이것은 배포를위한 아주 좋은 솔루션입니다 (예 : 마이크로 서비스 아키텍처).

다음은 Akka-Camel (Java8 사용)과 함께 ActiveMQ와 함께 Akka를 사용하는 예입니다.

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);

    }
}


답변