ActiveMQ용 Amazon MQ 모범 사례
이 단원을 참조하여 Amazon MQ에서 ActiveMQ를 이용할 때 성능을 극대화하고 처리량 비용을 최소화할 수 있는 권장 방법을 신속히 찾으세요.
Amazon MQ 탄력적 네트워크 인터페이스를 수정하거나 삭제하지 않음
처음으로 Amazon MQ 브로커 생성할 때 Amazon MQ는 Virtual Private Cloud(VPC)에서 사용자 계정 아래에 탄력적 네트워크 인터페이스를 프로비저닝하므로 많은 EC2 권한이 필요합니다. 네트워크 인터페이스를 통해 클라이언트(생산자 또는 소비자)가 Amazon MQ 브로커와 통신할 수 있습니다. 네트워크 인터페이스는 사용자 계정의 VPC에 속해 있음에도 불구하고 Amazon MQ의 서비스 범위 내에 있는 것으로 간주됩니다.
주의
이 네트워크 인터페이스는 수정하거나 삭제하면 안 됩니다. 네트워크 인터페이스를 수정하거나 삭제하면 VPC와 브로커 간의 연결이 영구적으로 손실될 수 있습니다.
항상 연결 풀 사용
단일 생산자와 단일 소비자가 있는 시나리오(예: 시작하기: ActiveMQ 브로커 생성 및 연결 자습서)에서는 모든 생산자와 소비자에 대해 단일 ActiveMQConnectionFactory
// Create a connection factory.
final ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(wireLevelEndpoint);
// Pass the sign-in credentials.
connectionFactory.setUserName(activeMqUsername);
connectionFactory.setPassword(activeMqPassword);
// Establish a connection for the consumer.
final Connection consumerConnection = connectionFactory.createConnection();
consumerConnection.start();
하지만 생산자와 소비자가가 여러 개인 현실적인 시나리오에서는 여러 생산자에 대해 많은 수의 연결을 생성하려면 비용이 많이 들고 비효율적일 수 있습니다. 이러한 시나리오에서는 PooledConnectionFactory
참고
메시지 소비자는 PooledConnectionFactory
클래스를 사용하면 안 됩니다.
// Create a connection factory.
final ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(wireLevelEndpoint);
// Pass the sign-in credentials.
connectionFactory.setUserName(activeMqUsername);
connectionFactory.setPassword(activeMqPassword);
// Create a pooled connection factory.
final PooledConnectionFactory pooledConnectionFactory = new PooledConnectionFactory();
pooledConnectionFactory.setConnectionFactory(connectionFactory);
pooledConnectionFactory.setMaxConnections(10);
// Establish a connection for the producer.
final Connection producerConnection = pooledConnectionFactory.createConnection();
producerConnection.start();
항상 Failover Transport를 사용하여 여러 브로커 엔드포인트에 연결
애플리케이션이 여러 브로커 엔드포인트에 연결해야 하는 경우(예: 활성/대기 배포 모드를 사용하는 경우나 온프레미스 메시지 브로커에서 Amazon MQ로 마이그레이션하는 경우 장애 조치 전송
failover:(ssl://b-1234a5b6-78cd-901e-2fgh-3i45j6k178l9-1.mq.us-east-2.amazonaws.com:61617,ssl://b-9876l5k4-32ji-109h-8gfe-7d65c4b132a1-2.mq.us-east-2.amazonaws.com:61617)?randomize=true
메시지 선택기 사용하지 않기
JMS 선택기
일반적으로 소비자가 메시지를 라우팅하도록 두지 마세요. 소비자와 생산자를 최적으로 결합 해제하려면 소비자와 생산자가 모두 한시적이어야 하기 때문입니다.
지속 구독보다 가상 대상을 선호
지속 구독
Amazon VPC 피어링을 사용하는 경우 CIDR 범위 10.0.0.0/16
의 클라이언트 IP 사용 안 함
온프레미스 인프라와 Amazon MQ 브로커 간에 Amazon VPC 피어링을 설정하는 경우 CIDR 범위 10.0.0.0/16
의 IP와 클라이언트 연결을 구성해서는 안 됩니다.
느린 소비자를 통해 대기열 동시 저장 및 디스패치 비활성화
기본적으로 Amazon MQ는 빠른 소비자가 있는 대기열에 맞게 최적화됩니다.
-
소비자가 생산자가 생성한 메시지의 속도를 따라갈 수 있는 경우 소비자는 빠른 것으로 간주됩니다.
-
대기열이 승인되지 않은 메시지의 백로그를 작성하여 생산자 처리량의 감소를 유발할 수 있는 경우 소비자는 느린 것으로 간주됩니다.
느린 소비자가 있는 대기열에 맞게 최적화하도록 Amazon MQ에 지시하려면 concurrentStoreAndDispatchQueues
속성을 false
로 설정합니다. 구성 예제는 를 참조하세요concurrentStoreAndDispatchQueues
처리량을 최대화하기 위해 올바른 브로커 인스턴스 유형 선택
브로커 인스턴스 유형의 메시지 처리량은 애플리케이션의 사용 사례와 다음 요인에 따라 다릅니다.
-
지속 모드에서 ActiveMQ 사용
-
메시지 크기
-
생산자 수와 소비자 수
-
대상 수
메시지 크기, 대기 시간, 처리량 간의 관계 이해
용도에 따라 더 큰 브로커 인스턴스 유형이 반드시 시스템 처리량을 높여 주는 것이 아닐 수도 있습니다. ActiveMQ가 지속 가능한 스토리지에 메시지를 기록할 때 메시지 크기에 따라 시스템의 제한 요인이 결정됩니다.
-
메시지 크기가 100KB보다 작으면 영구 스토리지 지연 시간이 제한 요인입니다.
-
메시지 크기가 100KB보다 크면 영구 스토리지 처리량이 제한 요인입니다.
ActiveMQ가 지속 모드일 경우 소비자 수가 거의 없거나 소비자 속도가 느릴 때 스토리지에 대한 쓰기가 정상적으로 수행됩니다. 비지속 모드에서는 브로커 인스턴스의 힘 메모리가 가득 찰 경우 소비자 속도가 느려도 스토리지에 대한 쓰기가 수행됩니다.
애플리케이션에 가장 적합한 브로커 인스턴스를 확인하려면 다양한 브로커 인스턴스 유형을 검사하는 것이 좋습니다. 자세한 내용은 Broker instance types 단원 및 JMS Benchmark를 사용하여 Amazon MQ의 처리량 측정
더 큰 브로커 인스턴스 유형의 사용 사례
더 큰 브로커 인스턴스 유형이 처리량을 향상시킬 수 있는 세 가지 일반 사용 사례가 있습니다.
-
비지속 모드 - 애플리케이션이 브로커 인스턴스 장애 조치 중 발생하는 메시지 손실에 비교적 민감하지 않은 경우(예: 스포츠 경기 득점 결과를 방송하는 경우) 일반적으로 ActiveMQ의 비지속 모드를 사용할 수 있습니다. 이 모드에서 ActiveMQ는 브로커 인스턴스의 힙 메모리가 가득 찰 경우에만 영구 스토리지에 메시지를 기록합니다. 비지속 모드를 사용하는 시스템은 더 큰 브로커 인스턴스 유형에서 제공하는 메모리 양, CPU 속도 및 빠른 네트워크 속도를 활용할 수 있습니다.
-
빠른 소비자 - 활성 소비자가 사용 가능하고 concurrentStoreAndDispatchQueues 플래그가 활성화되면 ActiveMQ는 메시지를 스토리지로 전송하지 않고 메시지가 생산자에서 소비자로 직접 흐르도록 허용합니다(지속 모드에서도 허용). 애플리케이션이 메시지를 빨리 소비할 수 있으면(소비자가 이렇게 실행하도록 설계할 수 있으면) 애플리케이션은 더 큰 브로커 인스턴스 유형의 이점을 활용할 수 있습니다. 애플리케이션에서 메시지를 더 빠르게 소비할 수 있게 하려면 애플리케이션 인스턴스에 소비자 스레드를 추가하거나, 애플리케이션 인스턴스를 수직 또는 수평으로 확장합니다.
-
배치 트랜잭션 - 지속 모드를 사용하며 트랜잭션당 여러 개의 메시지를 전송하는 경우 더 큰 브로커 인스턴스 유형을 사용하면 전체적으로 더 많은 메시지 처리량을 달성할 수 있습니다. 자세한 내용은 ActiveMQ 설명서의 트랜잭션을 사용해야 합니까?
를 참조하세요.
처리량을 최대화하기 위해 올바른 브로커 스토리지 유형 선택
다중 가용 영역에 걸친 높은 내구성 및 복제를 활용하려면 Amazon EFS를 사용하세요. 짧은 대기 시간 및 높은 처리량을 활용하려면 Amazon EBS를 사용하세요. 자세한 정보는 Storage을 참조하세요.
브로커 네트워크를 올바로 구성
네트워크 브로커를 생성할 때 애플리케이션에 올바르게 구성합니다.
-
지속 모드를 활성화 - (피어에 비해) 각 브로커 인스턴스는 생산자 또는 소비자처럼 행동하기 때문에 브로커 네트워크는 분산된 메시지 복제를 제공하지 않습니다. 소비자로 행동하는 첫 번째 브로커가 메시지를 수신하고 스토리지에 지속시킵니다. 이 브로커는 생산자에게 승인을 전송하고 메시지를 다음 브로커에 전달합니다. 두 번째 브로커가 메시지의 지속성을 승인하고 첫 번째 브로커가 메시지를 삭제합니다.
지속 모드가 비활성화된 경우, 첫 번째 브로커가 메시지를 스토리지에 지속시키지 않고 생산자를 승인합니다. 자세한 내용은 Apache ActiveMQ 설명서에서 복제된 메시지 스토어
및 지속적 전송과 비지속적 전송의 차이점은 무엇입니까? 를 참조하세요. -
브로커 인스턴스에 대해 자문 메시지를 비활성화하지 않음 - 자세한 내용은 Apache ActiveMQ 설명서에서 자문 메시지
를 참조하세요. -
멀티캐스트 브로커 검색을 사용하지 않음 - Amazon MQ는 멀티캐스트를 사용한 브로커 검색을 지원하지 않습니다. 자세한 내용은 Apache ActiveMQ 설명서에서 검색, 멀티캐스트, zeroconf의 차이점은 무엇입니까?
를 참조하세요.
준비된 XA 트랜잭션을 복구하여 느린 재시작 방지
ActiveMQ는 분산(XA) 트랜잭션을 지원합니다. ActiveMQ에서 XA 트랜잭션을 처리하는 방식을 알면 Amazon MQ에서의 브로커 재시작 및 장애 조치에 대한 복구 시간이 느려지는 것을 방지할 수 있습니다.
해결되지 않은 준비된 XA 트랜잭션은 재시작할 때마다 재실행됩니다. 이러한 트랜잭션이 해결되지 않은 상태로 남아 있으면 시간이 지남에 따라 이들 수가 증가하여 브로커 시작에 필요한 시간이 크게 늘어납니다. 이는 재시작 및 장애 조치 시간에 영향을 미칩니다. 이러한 트랜잭션은 시간이 지남에 따라 성능이 저하되지 않도록 commit()
또는 rollback()
으로 해결해야 합니다.
해결되지 않은 준비된 XA 트랜잭션을 모니터링하기 위해 Amazon CloudWatch Logs의 JournalFilesForFastRecovery
지표를 사용할 수 있습니다. 이 숫자가 증가하고 있거나 1
보다 일관되게 높은 경우, 다음 예제와 유사한 코드를 사용하여 해결되지 않은 트랜잭션을 복구해야 합니다. 자세한 정보는 Quotas in Amazon MQ을 참조하세요.
다음 예제 코드는 준비된 XA 트랜잭션을 모두 거치고 rollback()
을 사용하여 닫습니다.
import org.apache.activemq.ActiveMQXAConnectionFactory; import javax.jms.XAConnection; import javax.jms.XASession; import javax.transaction.xa.XAResource; import javax.transaction.xa.Xid; public class RecoverXaTransactions { private static final ActiveMQXAConnectionFactory ACTIVE_MQ_CONNECTION_FACTORY; final static String WIRE_LEVEL_ENDPOINT = "tcp://localhost:61616";; static { final String activeMqUsername = "
MyUsername123
"; final String activeMqPassword = "MyPassword456
"; ACTIVE_MQ_CONNECTION_FACTORY = new ActiveMQXAConnectionFactory(activeMqUsername, activeMqPassword, WIRE_LEVEL_ENDPOINT); ACTIVE_MQ_CONNECTION_FACTORY.setUserName(activeMqUsername); ACTIVE_MQ_CONNECTION_FACTORY.setPassword(activeMqPassword); } public static void main(String[] args) { try { final XAConnection connection = ACTIVE_MQ_CONNECTION_FACTORY.createXAConnection(); XASession xaSession = connection.createXASession(); XAResource xaRes = xaSession.getXAResource(); for (Xid id : xaRes.recover(XAResource.TMENDRSCAN)) { xaRes.rollback(id); } connection.close(); } catch (Exception e) { } } }
실제 시나리오에서는 XA Transaction Manager와 비교하여 준비된 XA 트랜잭션을 확인할 수 있습니다. 그런 다음 각각의 준비된 트랜잭션을 rollback()
또는 commit()
중에서 어떤 것으로 처리할지 결정할 수 있습니다.