Azure Service Bus 및 Event Hubs 프로토콜 가이드의 AMQP 1.0

고급 메시지 큐 프로토콜 1.0은 두 당사자 간에 메시지를 비동기적이고 안전하게 안정적으로 전송하기 위한 표준화된 프레이밍 및 전송 프로토콜입니다. 또한 Azure Service Bus 메시징 및 Azure Event Hubs의 기본 프로토콜입니다.

AMQP 1.0은 금융 서비스 산업을 대표하는 JP Morgan Chase와 같은 많은 메시징 미들웨어 사용자와 함께 Microsoft 및 Red Hat과 같은 미들웨어 공급업체를 한데 모은 광범위한 산업 협업의 결과입니다. AMQP 프로토콜 및 확장 사양에 대한 기술 표준화 포럼은 OASIS이며 ISO/IEC 19494:2014와 같은 국제 표준으로 공식 승인을 받았습니다.

목표

이 문서에서는 OASIS AMQP 기술 위원회에서 개발한 확장 사양에 따라 AMQP 1.0 메시징 사양의 핵심 개념을 요약하고 Azure Service Bus가 이러한 사양을 구현하고 빌드하는 방법을 설명합니다.

목표는 모든 플랫폼에서 기존 AMQP 1.0 클라이언트 스택을 사용하는 개발자가 AMQP 1.0을 통해 Azure Service Bus와 상호 작용할 수 있도록 하는 것입니다.

Apache Qpid Proton 또는 AMQP.NET Lite와 같은 일반적인 범용 AMQP 1.0 스택은 세션 또는 링크와 같은 모든 핵심 AMQP 1.0 프로토콜 요소를 구현합니다. 이러한 기본 요소는 경우에 따라 상위 수준 API로 래핑됩니다. Apache Proton은 명령적 Messenger API와 반응형 Reactor API인 두 가지를 제공합니다.

다음 토론에서는 AMQP 연결, 세션 및 링크의 관리와 프레임 전송 및 흐름 제어의 처리가 해당 스택(예: Apache Proton-C)에서 처리되며, 애플리케이션 개발자의 많은 주의가 필요하지 않다고 가정합니다. 연결 기능과 같은 몇 가지 API 기본 형식이 있음을 추상적으로 가정하고 특정 형식의 보낸 사람수신자 추상화 개체를 만든 다음 각각 일부 모양 send()receive() 연산을 갖습니다.

메시지 검색 또는 세션 관리와 같은 Azure Service Bus의 고급 기능을 논의할 때 이러한 기능은 AMQP 용어로 설명되지만 이 가정된 API 추상화를 기반으로 계층화된 의사 구현으로도 설명됩니다.

AMQP란?

AMQP는 프레이밍 및 전송 프로토콜입니다. 프레이밍은 네트워크 연결의 어느 방향으로든 흐르는 이진 데이터 스트림에 대한 구조를 제공한다는 것을 의미합니다. 이 구조는 프레임이라고 부르는 고유한 데이터 블록이 연결된 대상 간에 교환될 수 있도록 윤곽을 제공합니다. 전송 기능은 두 통신 당사자가 프레임을 전송해야 하는 시기와 전송이 완료된 것으로 간주될 때에 대한 공유 이해를 설정할 수 있도록 합니다.

일부 메시지 브로커에서는 아직 사용되고 있는 AMQP 작업 그룹에서 만료된 이전 초안 이전 버전과 달리 이 작업 그룹의 표준화된 최종 AMQP 1.0 프로토콜에서는 메시지 브로커의 존재 또는 메시지 브로커 내 엔터티에 대한 특정 토폴로지의 존재를 규정하지 않습니다.

이 프로토콜은 Azure Service Bus와 마찬가지로, 큐 및 게시/구독 엔터티를 지원하는 메시지 브로커와의 상호 작용을 위해 대칭 피어-투-피어 통신에 사용될 수 있습니다. Azure Event Hubs의 경우와 마찬가지로 상호 작용 패턴이 일반 큐와 다른 메시징 인프라와의 상호 작용에도 사용할 수 있습니다. 이벤트 허브는 이벤트가 전송될 때는 큐처럼 작동하지만, 이벤트가 읽힐 때 직렬 스토리지 서비스처럼 작동합니다. 따라서 테이프 드라이브와 유사한 부분이 있습니다. 클라이언트는 사용 가능한 데이터 스트림으로 오프셋을 선택한 다음 해당 오프셋에서 사용 가능한 최신 이벤트까지 모든 이벤트를 제공합니다.

AMQP 1.0 프로토콜은 확장 가능하도록 설계되어 추가 사양을 통해 기능을 향상시킬 수 있습니다. 이 문서에서 설명하는 세 가지 확장 사양은 이를 보여 줍니다. 기존 HTTPS/WebSockets 인프라를 통한 통신의 경우 네이티브 AMQP TCP 포트를 구성하는 것이 어려울 수 있습니다. 바인딩 사양은 WebSockets를 통해 AMQP를 계층화하는 방법을 정의합니다. 관리를 위해 요청/응답 방식으로 메시지 인프라와 상호 작용하거나 고급 기능을 제공하기 위해 AMQP 관리 사양은 필요한 기본적인 상호 작용 기본 형식을 정의합니다. 페더레이션된 권한 부여 모델 통합의 경우 AMQP 클레임 기반 보안 사양은 링크와 연결된 권한 부여 토큰을 연결하고 갱신하는 방법을 정의합니다.

기본 AMQP 시나리오

이 섹션에서는 연결, 세션 및 링크를 만들고 큐, 토픽 및 구독과 같은 Service Bus 엔터티와 메시지를 전송하는 것을 포함하는 Azure Service Bus에서 AMQP 1.0의 기본 사용을 설명합니다.

AMQP 작동 방식에 대해 알아보는 가장 신뢰할 수 있는 소스는 AMQP 1.0 사양이지만 사양은 프로토콜을 가르치지 않고 구현을 정확하게 안내하기 위해 작성되었습니다. 이 섹션에서는 Service Bus가 AMQP 1.0을 사용하는 방법을 설명하는 데 필요한 다양한 용어를 중점적으로 소개합니다. AMQP에 대한 보다 포괄적인 소개와 AMQP 1.0에 대한 광범위한 논의를 위해 이 비디오 과정을 검토할 수 있습니다.

커넥트 및 세션

AMQP는 통신 프로그램 컨테이너를 호출합니다. 여기에는 해당 컨테이너 내부의 통신 엔터티인 노드가 포함됩니다. 큐는 이러한 노드일 수 있습니다. AMQP는 멀티플렉싱을 허용하므로 노드 간의 많은 통신 경로에 단일 연결을 사용할 수 있습니다. 예를 들어 애플리케이션 클라이언트는 한 큐에서 동시에 수신하고 동일한 네트워크 연결을 통해 다른 큐로 보낼 수 있습니다.

Diagram showing Sessions and Connections between containers.

따라서 네트워크 연결은 컨테이너에 고정됩니다. 이러한 연결은 클라이언트 역할의 컨테이너가 인바운드 TCP 연결을 수신하고 수락하는 수신자 역할의 컨테이너에 대해 아웃바운드 TCP 소켓 연결을 설정하는 것부터 시작됩니다. 연결 핸드셰이크에는 프로토콜 버전 협상, 전송 수준 보안(TLS/SSL) 사용에 대한 선언 또는 협상, SASL을 기반으로 하는 연결 범위의 인증/권한 부여 핸드셰이크가 포함됩니다.

Azure Service Bus 또는 Azure Event Hubs는 항상 TLS를 사용해야 합니다. TCP 포트 5671을 통해 연결을 지원하므로 AMQP 프로토콜 핸드셰이크를 입력하기 전에 TCP 연결이 먼저 TLS로 오버레이되고 TCP 포트 5672를 통해 연결을 지원하므로 서버는 AMQP 규정 모델을 사용하여 TLS에 대한 필수 업그레이드를 즉시 제공합니다. AMQP WebSockets 바인딩은 TCP 포트 443을 통해 터널을 만든 다음 AMQP 5671 연결과 동일합니다.

연결 및 TLS를 설정한 후 Service Bus는 두 가지 SASL 메커니즘 옵션을 제공합니다.

  • SASL PLAIN은 일반적으로 사용자 이름 및 암호 자격 증명을 서버에 전달하는 데 사용됩니다. Service Bus에는 계정이 없지만, 권한을 부여하고 키와 연결되어 있는 공유 액세스 보안 규칙이 있습니다. 규칙의 이름은 사용자 이름으로 사용되고 키(base64로 인코딩된 텍스트)는 암호로 사용됩니다. 선택한 규칙과 연결된 권한은 연결에 허용되는 작업을 제어합니다.
  • SASL ANONYMOUS는 클라이언트가 나중에 설명하는 CBS(클레임 기반 보안) 모델을 사용하려는 경우 SASL 권한 부여를 우회하는 데 사용됩니다. 이 옵션을 사용하면 클라이언트가 CBS 엔드포인트와 상호 작용할 수 있는 정도의 짧은 시간 동안 클라이언트 연결이 익명으로 설정될 수 있으며 CBS 핸드셰이크를 완료해야 합니다.

전송 연결이 설정된 후에 각 컨테이너는 자발적으로 처리할 최대 프레임 크기를 선언하며, 유휴 시간이 초과한 후 연결에 대해 활동이 없는 경우 일반적으로 연결을 끊습니다.

또한 지원되는 동시 채널 수를 선언합니다. 채널은 연결 위에 있는 단방향 아웃바운드 가상 전송 경로입니다. 세션은 상호 연결된 각 컨테이너의 채널로 양방향 통신 경로를 구성합니다.

세션에는 기간에 따른 흐름 제어 모델이 있습니다. 세션이 만들어지면 각 상대방은 수신 기간에 수락할 프레임 수를 선언합니다. 상대방이 프레임을 교환할 때 전송된 프레임이 해당 기간을 채우고, 기간이 만료되면 기간이 다시 설정되거나 흐름 수행을 사용하여 확장될 때까지 전송이 중지됩니다(수행은 두 상대방 간에 교환되는 프로토콜 수준 제스처를 나타내는 AMQP 용어임).

이 기간 기반 모델은 TCP의 기간 기반 흐름 제어 개념과 유사하지만 소켓 내 세션 수준에서 진행됩니다. 여러 동시 세션을 허용하는 프로토콜의 개념은 고속도로 고속 차선과 같이 높은 우선 순위 트래픽이 제한된 일반 트래픽을 지나 서두를 수 있도록 존재합니다.

Azure Service Bus는 현재 각 연결에 대해 정확히 하나의 세션을 사용합니다. Service Bus 표준의 경우 Service Bus 최대 프레임 크기는 262,144바이트(256K바이트)입니다. Service Bus 프리미엄 및 Event Hubs의 경우는 1,048,576(100MB)입니다. Service Bus는 세션 수준의 특정 제한 기간을 적용하지 않지만 링크 수준 흐름 제어의 일부로 해당 기간을 정기적으로 다시 설정합니다(다음 섹션 참조).

연결, 채널 및 세션은 사용 후 삭제됩니다. 기본 연결이 축소되면 연결, TLS 터널, SASL 권한 부여 컨텍스트 및 세션을 다시 설정해야 합니다.

AMQP 아웃바운드 포트 요구 사항

TCP를 통해 AMQP 연결을 사용하는 클라이언트는 포트 5671 및 5672를 로컬 방화벽에서 열어야 합니다. 이러한 포트와 함께 EnableLinkRedirect 기능을 사용하는 경우 추가 포트를 열어야 할 수 있습니다. EnableLinkRedirect 는 메시지를 수신하는 동안 원홉을 건너뛰어 처리량을 높이는 데 도움이 되는 새로운 메시징 기능입니다. 클라이언트는 다음 이미지와 같이 포트 범위 104XX를 통해 백 엔드 서비스와 직접 통신을 시작합니다.

List of destination ports

이러한 포트가 방화벽에서 차단되는 경우 .NET 클라이언트는 SocketException("액세스 권한에 의해 숨겨진 소켓에 액세스를 시도했습니다.")을 나타내며 실패합니다. 클라이언트가 포트 5671을 통해 원격 서비스와 통신하도록 강제하는 연결 문자열 설정하여 기능을 사용하지 않도록 설정할 EnableAmqpLinkRedirect=false 수 있습니다.

AMQP WebSocket 바인딩 은 WebSocket 전송을 통해 AMQP 연결을 터널링하는 메커니즘을 제공합니다. 이 바인딩은 AMQP 5671 연결과 동일한 TCP 포트 443을 통해 터널을 만듭니다. 포트 5671, 5672를 통한 TCP 연결을 차단하지만 포트 443(https)을 통한 TCP 연결을 허용하는 방화벽 뒤에 있는 경우 AMQP WebSockets를 사용합니다.

AMQP는 링크를 통해 메시지를 전송합니다. 링크는 한 방향으로 메시지를 전송할 수 있도록 세션을 통해 만든 통신 경로입니다. 이전 상태 협상은 연결된 당사자 간의 링크와 양방향을 통해 진행됩니다.

Screenshot showing a Session carrying a link connection between two containers.

언제든지 컨테이너와 기존 세션을 통해 링크를 만들 수 있으며, 이는 전송 및 전송 경로의 시작이 소켓 연결을 만드는 당사자의 배타적 권한인 HTTP 및 MQTT를 비롯한 다른 많은 프로토콜과 AMQP를 다르게 만듭니다.

링크 시작 컨테이너는 반대쪽 컨테이너에 링크를 수락하도록 요청하고 발신자 또는 수신자의 역할을 선택합니다. 따라서 컨테이너는 단방향 또는 양방향 통신 경로 만들기를 시작할 수 있으며 후자는 링크 쌍으로 모델링됩니다.

링크의 이름이 지정되고 노드와 연결됩니다. 처음에 설명한 대로 노드는 컨테이너 내의 통신 엔터티입니다.

Service Bus에서 노드는 큐, 토픽, 구독 또는 큐 또는 구독의 배달 못 한 하위 큐와 직접 동일합니다. 따라서 AMQP에서 사용되는 노드 이름은 Service Bus 네임스페이스 내 엔터티의 상대 이름입니다. 큐 이름이 myqueue이면 AMQP 노드 이름도 같습니다. 토픽 구독은 "구독" 리소스 컬렉션으로 정렬되어 HTTP API 규칙을 따르므로 구독 sub 또는 토픽 mytopic의 AMQP 노드 이름은 mytopic/subscriptions/sub입니다.

링크를 만들기 위해서는 연결하는 클라이언트가 로컬 노드 이름을 사용해야 합니다. Service Bus는 이러한 노드 이름을 강제적으로 규정하지 않으며 해석하지 않습니다. AMQP 1.0 클라이언트 스택은 일반적으로 이러한 임시 노드 이름이 클라이언트 범위에서 고유하도록 하는 체계를 사용합니다.

전송

링크가 설정되면 해당 링크를 통해 메시지를 전송할 수 있습니다. AMQP에서는 링크를 통해 메시지를 발신자에서 수신자로 이동하는 명시적 프로토콜 제스처(전송 수행)를 통해 전송이 실행됩니다. 양도는 "정착"될 때 완료됩니다. 즉, 양 당사자가 해당 이전의 결과에 대한 공유 이해를 확립했음을 의미합니다.

A diagram showing a message's transfer between the Sender and Receiver and disposition that results from it.

가장 간단한 경우, 발신자는 “합의 전” 메시지를 보내도록 선택할 수 있습니다. 즉, 클라이언트는 결과에 관심이 없고 수신자가 작업 결과에 대한 어떤 피드백도 제공하지 않는 경우를 의미합니다. 이 모드는 AMQP 프로토콜 수준에서 Service Bus에서 지원되지만 클라이언트 API에는 노출되지 않습니다.

일반적인 경우는 메시지가 불안정하게 전송되고 수신자는 처리 수행을 사용하여 수락 또는 거부를 나타냅니다. 거부는 어떤 이유로든 수신자가 메시지를 수락할 수 없을 때 발생하며, AMQP 정의한 오류 구조에 따라, 거부 메시지에는 이유에 대한 정보가 포함됩니다. Service Bus 내의 내부 오류로 인해 메시지가 거부되면 서비스는 지원 요청을 제출할 때 지원 담당자에게 진단 힌트를 제공하는 데 사용할 수 있는 해당 구조 내부의 추가 정보를 반환합니다. 나중에 오류에 대한 자세한 내용을 알아봅니다.

거부의 특별한 형태는 해제 된 상태입니다, 이는 수신자가 전송에 대한 기술적 이의가 없음을 나타냅니다, 뿐만 아니라 전송을 정착에 관심이 없습니다. 예를 들어, 메시지 배달 자체는 오류가 아니지만 메시지 처리에 따른 작업을 수행할 수 없기 때문에 메시지가 Service Bus 클라이언트에 전달된 후에 클라이언트가 메시지를 “중단”하도록 선택하는 경우가 있습니다. 해당 상태의 변형은 메시지를 해제할 때 변경할 수 있는 수정된 상태입니다. 이 상태는 현재 Service Bus에서 사용되지 않습니다.

AMQP 1.0 사양은 수신된 추가 처리 상태를 정의하며, 이는 특히 링크 복구를 처리하는 데 도움이 됩니다. 링크 복구는 이전 연결 및 세션이 손실된 경우와 새 연결 및 세션에 앞서, 링크 및 보류 중인 배달의 상태를 다시 구성할 수 있도록 합니다.

Service Bus는 링크 복구를 지원하지 않습니다. 클라이언트가 합의되지 않은 메시지 전송이 보류 중인 상태로 Service Bus에 대한 연결이 끊어지면 해당 메시지 전송이 손실되고, 클라이언트는 다시 연결하고 연결을 다시 설정하고, 전송을 다시 시도해야 합니다.

이와 같이 Service Bus 및 Event Hubs는 메시지가 저장되고 수락되었음을 발신자에게 확인시킬 수 있는 “한 번 이상” 전송을 지원하지만, AMQP 수준에서는 “정확히 한 번” 전송을 지원하지 않으므로 시스템은 링크 복구를 시도하고 메시지 전달이 중복되지 않도록 배달 상태를 계속 협상합니다.

가능한 중복 전송을 보정하기 위해 Service Bus는 큐 및 토픽에서 선택적 기능으로 중복 검색을 지원합니다. 중복 검색 기능은 사용자 정의 기간 동안 들어오는 모든 메시지의 메시지 ID를 기록한 후 동일한 기간 동안 동일한 메시지 ID를 사용해서 전송된 모든 메시지를 자동으로 삭제합니다.

흐름 제어

이전에 설명한 세션 수준 흐름 제어 모델 외에도 각 링크에는 고유한 흐름 제어 모델이 있습니다. 세션 수준 흐름 제어는 컨테이너가 한 번에 너무 많은 프레임을 처리할 필요가 없도록 보호합니다. 링크 수준 흐름 제어는 애플리케이션이 링크에서 처리하려는 메시지의 수와 시기를 담당합니다.

Screenshot of a log showing Source, Destination, Source Port, Destination Port, and Protocol Name. In the first row the Destination Port 10401 (0x28 A 1) is outlined in black.

링크에서 전송은 보낸 사람에게 링크 크레딧이 충분한 경우에만 발생할 수 있습니다. 링크 크레딧은 발신자가 링크 범위까지의 흐름 수행을 사용하여 설정한 카운터입니다. 보낸 사람에게 링크 크레딧이 할당되면 메시지를 전달하여 해당 크레딧을 사용하려고 합니다. 각 메시지 배달은 다시 기본 링크 크레딧을 1씩 감소합니다. 링크 크레딧이 다 소모되면 배달은 중지됩니다.

Service Bus는 수신자 역할을 수행할 때 발신자에게 충분한 링크 크레딧을 즉시 제공하므로 메시지를 즉시 전송할 수 있게 됩니다. 링크 크레딧이 사용될 때 Service Bus는 종종 발신자에게 흐름 수행을 전송하여 남은 링크 크레딧을 업데이트합니다.

보낸 사람 역할에서 Service Bus는 미해결 링크 크레딧을 사용하기 위해 메시지를 보냅니다.

API 수준의 "수신" 호출은 클라이언트에 의해 Service Bus로 전송되는 흐름 성능으로 변환되며, Service Bus는 큐에서 사용 가능한 잠금 해제된 첫 번째 메시지를 가져와서 잠그고 전송하여 해당 크레딧을 사용합니다. 바로 배달할 수 있는 메시지가 없는 경우 해당 특정 엔터티와 설정된 링크의 처리되지 않은 크레딧은 도착 순서대로 기록되고, 처리되지 않은 크레딧을 사용할 수 있게 될 때 메시지가 잠긴 후 전송됩니다.

메시지 잠금은 전송이 수락, 거부 또는 해제된 터미널 상태 중 하나에 정착될 때 해제됩니다. 터미널 상태가 수락되면 메시지가 Service Bus에서 제거됩니다. Service Bus에서 다시 기본 전송이 다른 상태에 도달하면 다음 수신기로 전달됩니다. Service Bus는 반복된 거부 또는 릴리스로 인해 엔터티에 허용되는 최대 배달 횟수에 도달하면 자동으로 엔터티의 배달 못 한 큐로 메시지를 이동합니다.

Service Bus API는 현재 이러한 옵션을 직접적으로 제공하지 않지만, 하위 수준의 AMQP 프로토콜 클라이언트는 링크-크레딧 모델을 사용하여 대량의 링크 크레딧을 발행한 후 추가 상호 작용 없이 메시지를 사용할 수 있게 되면 메시지를 수신하여 각 수신 요청에 대해 크레딧 한 단위를 발행하는 “가져오기 스타일” 모델로 전환할 수 있습니다. Push는 ServiceBusProcessor.PrefetchCount 또는 ServiceBusReceiver.PrefetchCount 속성 설정을 통해 지원됩니다. AMQP 클라이언트는 0이 아닌 크레딧을 링크 크레딧으로 사용합니다.

이 컨텍스트에서 엔터티 내의 메시지 잠금 만료에 대한 시계는 메시지가 유선으로 전송되는 시점이 아니라 엔터티에서 메시지를 가져올 때 시작된다는 것을 이해하는 것이 중요합니다. 클라이언트가 링크 크레딧을 발행하여 메시지를 수신할 준비가 되었음을 나타낼 때마다 네트워크를 통해 메시지를 능동적으로 끌어와 처리할 준비가 된 것으로 간주됩니다. 그렇지 않으면 메시지가 배달되기 전에 메시지 잠금이 만료되었을 수 있습니다. 링크-신용 흐름 제어의 사용은 수신자에게 디스패치된 사용 가능한 메시지를 처리할 즉각적인 준비 상태를 직접 반영해야 합니다.

요약하자면, 다음 섹션에서는 다양한 API 상호 작용 중에 수행 흐름에 대한 개략적인 개요를 제공합니다. 각 섹션에서는 다른 논리 연산에 대해 설명합니다. 이러한 상호 작용 중 일부는 "지연"일 수 있습니다. 즉, 필요한 경우에만 수행될 수 있습니다. 메시지 발신자를 만들면 첫 번째 메시지가 전송되거나 요청될 때까지 네트워크 상호 작용이 발생하지 않을 수 있습니다.

다음 테이블의 화살표는 수행 흐름 방향을 표시합니다.

메시지 수신자 만들기

클라이언트 Service Bus
--> attach(<br/>name={link name},<br/>handle={numeric handle},<br/>role=**receiver**,<br/>source={entity name},<br/>target={client link ID}<br/>) 클라이언트가 엔터티에 수신기로 연결
Service Bus는 응답하고 링크의 해당 끝을 연결합니다. <-- attach(<br/>name={link name},<br/>handle={numeric handle},<br/>role=**sender**,<br/>source={entity name},<br/>target={client link ID}<br/>)

메시지 보낸 사람 만들기

클라이언트 Service Bus
--> attach(<br/>name={link name},<br/>handle={numeric handle},<br/>role=**sender**,<br/>source={client link ID},<br/>target={entity name}<br/>) 작업 없음
작업 없음 <-- attach(<br/>name={link name},<br/>handle={numeric handle},<br/>role=**receiver**,<br/>source={client link ID},<br/>target={entity name}<br/>)

메시지 보낸 사람 만들기(오류)

클라이언트 Service Bus
--> attach(<br/>name={link name},<br/>handle={numeric handle},<br/>role=**sender**,<br/>source={client link ID},<br/>target={entity name}<br/>) 작업 없음
작업 없음 <-- attach(<br/>name={link name},<br/>handle={numeric handle},<br/>role=**receiver**,<br/>source=null,<br/>target=null<br/>)<br/><br/><-- detach(<br/>handle={numeric handle},<br/>closed=**true**,<br/>error={error info}<br/>)

메시지 받는 사람/보낸 사람 닫기

클라이언트 Service Bus
--> detach(<br/>handle={numeric handle},<br/>closed=**true**<br/>) 작업 없음
작업 없음 <-- detach(<br/>handle={numeric handle},<br/>closed=**true**<br/>)

보내기(성공)

클라이언트 Service Bus
--> transfer(<br/>delivery-id={numeric handle},<br/>delivery-tag={binary handle},<br/>settled=**false**,,more=**false**,<br/>state=**null**,<br/>resume=**false**<br/>) 작업 없음
작업 없음 <-- disposition(<br/>role=receiver,<br/>first={delivery ID},<br/>last={delivery ID},<br/>settled=**true**,<br/>state=**accepted**<br/>)

보내기(오류)

클라이언트 Service Bus
--> transfer(<br/>delivery-id={numeric handle},<br/>delivery-tag={binary handle},<br/>settled=**false**,,more=**false**,<br/>state=**null**,<br/>resume=**false**<br/>) 작업 없음
작업 없음 <-- disposition(<br/>role=receiver,<br/>first={delivery ID},<br/>last={delivery ID},<br/>settled=**true**,<br/>state=**rejected**(<br/>error={error info}<br/>)<br/>)

수신

클라이언트 Service Bus
--> flow(<br/>link-credit=1<br/>) 작업 없음
작업 없음 < transfer(<br/>delivery-id={numeric handle},<br/>delivery-tag={binary handle},<br/>settled=**false**,<br/>more=**false**,<br/>state=**null**,<br/>resume=**false**<br/>)
--> disposition(<br/>role=**receiver**,<br/>first={delivery ID},<br/>last={delivery ID},<br/>settled=**true**,<br/>state=**accepted**<br/>) 작업 없음

다중 메시지 수신

클라이언트 Service Bus
--> flow(<br/>link-credit=3<br/>) 작업 없음
작업 없음 < transfer(<br/>delivery-id={numeric handle},<br/>delivery-tag={binary handle},<br/>settled=**false**,<br/>more=**false**,<br/>state=**null**,<br/>resume=**false**<br/>)
작업 없음 < transfer(<br/>delivery-id={numeric handle+1},<br/>delivery-tag={binary handle},<br/>settled=**false**,<br/>more=**false**,<br/>state=**null**,<br/>resume=**false**<br/>)
작업 없음 < transfer(<br/>delivery-id={numeric handle+2},<br/>delivery-tag={binary handle},<br/>settled=**false**,<br/>more=**false**,<br/>state=**null**,<br/>resume=**false**<br/>)
--> disposition(<br/>role=receiver,<br/>first={delivery ID},<br/>last={delivery ID+2},<br/>settled=**true**,<br/>state=**accepted**<br/>) 작업 없음

메시지

다음 섹션에서는 Service Bus에서 사용되는 표준 AMQP 메시지 섹션의 속성과 Service Bus API 집합에 매핑하는 방법을 설명합니다.

애플리케이션이 정의해야 하는 모든 속성은 AMQP의 application-properties 맵에 매핑되어야 합니다.

필드 이름 사용 API 이름
durable - -
priority - -
ttl 이 메시지에 대한 TTL(Time to live) Timetolive
첫 번째 인수자 - -
배달 수 - DeliveryCount

속성

필드 이름 사용 API 이름
message-id 이 메시지에 대한 애플리케이션 정의 자유 형식 식별자입니다. 중복 검색에 사용됩니다. MessageId
user-id Service Bus에서 해석되지 않는 애플리케이션 정의 사용자 식별자입니다. Service Bus API를 통해 액세스할 수 없습니다.
Service Bus에서 해석되지 않는 애플리케이션 정의 대상 식별자입니다. 받는 사람
주체 Service Bus에서 해석하지 않는 애플리케이션 정의 메시지 용도 식별자입니다. 주제
회신 Service Bus에서 해석되지 않는 애플리케이션 정의 회산 경로 식별자입니다. ReplyTo
correlation-id Service Bus에서 해석되지 않는 애플리케이션 정의 상관 관계 식별자입니다. CorrelationId
content-type Service Bus에서 해석하지 않는 본문에 대한 애플리케이션 정의 콘텐츠 형식 표시기입니다. Contenttype
content-encoding Service Bus에서 해석하지 않고 본문에 대한 애플리케이션 정의 콘텐츠 인코딩 표시기입니다. Service Bus API를 통해 액세스할 수 없습니다.
absolute-expiry-time 메시지가 만료되는 절대 인스턴트를 선언합니다. 입력(헤더 TTL이 관찰됨)에서 무시되며 출력에 대한 권한이 있습니다. Service Bus API를 통해 액세스할 수 없습니다.
생성 시간 메시지가 만들어진 시간을 선언합니다. Service Bus에서 사용되지 않습니다. Service Bus API를 통해 액세스할 수 없습니다.
group-id 관련 메시지 집합에 대한 애플리케이션 정의 식별자입니다. Service Bus 세션에 사용됩니다. Sessionid
group-sequence 세션 내 메시지의 상대 시퀀스 번호를 식별하는 카운터입니다. Service Bus에서 무시됩니다. Service Bus API를 통해 액세스할 수 없습니다.
reply-to-group-id - ReplyToSessionId

메시지 주석

AMQP 메시지 속성의 일부가 아니고, 메시지의 MessageAnnotations로 전달되는 다른 서비스 버스 메시지 속성이 몇 개 있습니다.

주석 맵 키 사용 API 이름
x-opt-scheduled-enqueue-time 메시지가 엔터티에 표시되어야 하는 시간을 선언합니다. ScheduledEnqueueTime
x-opt-partition-key 메시지가 표시되어야 하는 파티션을 지정하는 애플리케이션 정의 키입니다. PartitionKey
x-opt-via-partition-key 트랜잭션을 사용하여 전송 큐를 통해 메시지를 보내는 경우 애플리케이션 정의 파티션 키 값입니다. TransactionPartitionKey
x-opt-enqueued-time 메시지를 큐에 삽입하는 실제 시간을 나타내는 서비스 정의 UTC 시간입니다. 입력에서 무시됩니다. EnqueuedTime
x-opt-sequence-number 메시지에 할당된 서비스 정의 고유 번호입니다. SequenceNumber
x-opt-offset 메시지의 큐에 포함된 서비스 정의 시퀀스 번호입니다. EnqueuedSequenceNumber
x-opt-locked-until 서비스 정의. 큐/구독에서 메시지가 잠기기 전까지의 날짜 및 시간입니다. LockedUntil
x-opt-deadletter-source 서비스 정의. 메시지가 배달 못한 편지 큐에서 수신된 경우 원래 메시지의 원본입니다. DeadLetterSource

트랜잭션 기능

트랜잭션 그룹은 두 개 이상의 작업을 실행 범위로 그룹화합니다. 기본적으로 이러한 트랜잭션은 지정된 작업 그룹에 속한 모든 작업이 공동으로 성공하거나 실패하도록 해야 합니다. 작업은 식별자를 통해 그룹화됩니다 txn-id.

트랜잭션 상호 작용의 경우 클라이언트는 함께 그룹화해야 하는 작업을 제어하는 역할을 transaction controller 합니다. Service Bus 서비스는 역할을 transactional resource 하며 요청된 transaction controller대로 작업을 수행합니다.

클라이언트와 서비스는 클라이언트에 control link 의해 설정된 통신을 통해 통신합니다. declaredischarge 메시지는 컨트롤러가 트랜잭션을 각각 할당하고 완료하기 위해 제어 링크를 통해 전송합니다(트랜잭션 작업의 경계를 나타내지 않음). 실제 전송/수신은 이 링크에서 수행되지 않습니다. 요청된 각 트랜잭션 작업은 원하는 txn-id 것으로 명시적으로 식별되므로 커넥트 링크에서 발생할 수 있습니다. 생성된 방전되지 않은 트랜잭션이 있는 동안 컨트롤 링크가 닫혀 있으면 이러한 모든 트랜잭션이 즉시 롤백되고 추가 트랜잭션 작업을 수행하려고 하면 오류가 발생합니다. 제어 링크의 메시지를 미리 정정하면 안 됩니다.

모든 연결은 트랜잭션을 시작하고 종료할 수 있도록 자체 제어 링크를 시작해야 합니다. 서비스는 로 작동하는 특수 대상을 정의합니다 coordinator. 클라이언트/컨트롤러는 이 대상에 대한 컨트롤 링크를 설정합니다. 컨트롤 링크는 엔터티 경계 밖에 있습니다. 즉, 동일한 제어 링크를 사용하여 여러 엔터티에 대한 트랜잭션을 시작하고 방전할 수 있습니다.

트랜잭션 시작

트랜잭션 작업을 시작하려면 컨트롤러는 코디네이터에서 가져와 txn-id 야 합니다. 이 작업은 형식 메시지를 전송 declare 하여 수행합니다. 선언에 성공하면 코디네이터가 처리 결과로 응답합니다. 이 결과는 할당된 txn-id값을 전달합니다.

클라이언트(컨트롤러) 방향 Service Bus(코디네이터)
attach(
name={link name},
... ,
role=sender,
target=Coordinator
)
------>
<------ attach(
name={link name},
... ,
target=Coordinator()
)
transfer(
delivery-id=0, ...)
{ AmqpValue (Declare())}
------>
<------ disposition(
first=0, last=0,
state=Declared(
txn-id={transaction ID}
))

트랜잭션 방전

컨트롤러는 코디네이터에게 메시지를 보내 discharge 트랜잭션 작업을 완료합니다. 컨트롤러는 출력 본문에 플래그를 설정 fail 하여 트랜잭션 작업을 커밋하거나 롤백하려고 했음을 나타냅니다. 코디네이터가 출력을 완료할 수 없는 경우 메시지가 거부되고 이 결과가 전달됩니다 transaction-error.

참고: fail=true는 트랜잭션의 롤백을 의미하고 fail=false는 커밋을 참조합니다.

클라이언트(컨트롤러) 방향 Service Bus(코디네이터)
transfer(
delivery-id=0, ...)
{ AmqpValue (Declare())}
------>
<------ disposition(
first=0, last=0,
state=Declared(
txn-id={transaction ID}
))
. . .
트랜잭션 작업
트랜잭션 작업
. . .
transfer(
delivery-id=57, ...)
{ AmqpValue (
Discharge(txn-id=0,
fail=false)
)}
------>
<------ disposition(
first=57, last=57,
state=Accepted())

트랜잭션에서 메시지 보내기

모든 트랜잭션 작업은 txn-id를 전달하는 트랜잭션 배달 상태 transactional-state를 사용하여 수행됩니다. 메시지를 보내는 경우 트랜잭션 상태는 메시지의 전송 프레임에 의해 전달됩니다.

클라이언트(컨트롤러) 방향 Service Bus(코디네이터)
transfer(
delivery-id=0, ...)
{ AmqpValue (Declare())}
------>
<------ disposition(
first=0, last=0,
state=Declared(
txn-id={transaction ID}
))
transfer(
handle=1,
delivery-id=1,
state=
TransactionalState(
txn-id=0)
)
{ 페이로드 }
------>
<------ disposition(
first=1, last=1,
state=TransactionalState(
txn-id=0,
outcome=Accepted()
))

트랜잭션에서 메시지 삭제

메시지 처리에는 다음과 같은 CompleteDeadLetterDefer / Abandon / / 작업이 포함됩니다. 트랜잭션 내에서 이러한 작업을 수행하려면 처리와 transactional-state 함께 전달합니다.

클라이언트(컨트롤러) 방향 Service Bus(코디네이터)
transfer(
delivery-id=0, ...)
{ AmqpValue (Declare())}
------>
<------ disposition(
first=0, last=0,
state=Declared(
txn-id={transaction ID}
))
<------ transfer(
handle=2,
delivery-id=11,
state=null)
{ 페이로드 }
disposition(
first=11, last=11,
state=TransactionalState(
txn-id=0,
outcome=Accepted()
))
------>

고급 Service Bus 기능

이 섹션에서는 AMQP에 대한 초안 확장을 기반으로 하는 Azure Service Bus의 고급 기능에 대해 설명하며, 현재 AMQP용 OASIS 기술 위원회에서 개발 중입니다. Service Bus는 이러한 초안의 최신 버전을 구현하고 해당 초안이 표준 상태 도달함에 따라 도입된 변경 내용을 채택합니다.

참고 항목

Service Bus 메시징 고급 작업은 요청/응답 패턴을 통해 지원됩니다. 이러한 작업의 세부 정보는 Service Bus의 AMQP 1.0 문서 인 요청-응답 기반 작업에 설명되어 있습니다.

AMQP 관리

AMQP 관리 사양은 이 문서에서 설명하는 초안 확장 중 첫 번째입니다. 이 사양은 AMQP를 통해 메시지 인프라와 관리 상호 작용을 수행할 수 있도록 하는 AMQP 프로토콜 위에 계층화된 프로토콜 세트를 정의합니다. 이 사양은 메시징 인프라 및 쿼리 작업 집합 내에서 엔터티를 관리하기 위한 만들기, 읽기, 업데이트삭제와 같은 제네릭 작업을 정의합니다.

이러한 모든 제스처에는 클라이언트와 메시징 인프라 간의 요청/응답 상호 작용이 필요하므로 사양은 AMQP를 기반으로 해당 상호 작용 패턴을 모델링하는 방법을 정의합니다. 클라이언트는 메시징 인프라에 연결하고 세션을 시작한 다음 링크 쌍을 만듭니다. 한 링크에서 클라이언트는 보낸 사람 역할을 하고 다른 링크는 수신자 역할을 하므로 양방향 채널 역할을 할 수 있는 링크 쌍을 만듭니다.

논리적 연산 클라이언트 Service Bus
요청 응답 경로 만들기 --> attach(<br/>name={*link name*},<br/>handle={*numeric handle*},<br/>role=**sender**,<br/>source=**null**,<br/>target=”myentity/$management”<br/>) 작업 없음
요청 응답 경로 만들기 작업 없음 \<-- attach(<br/>name={*link name*},<br/>handle={*numeric handle*},<br/>role=**receiver**,<br/>source=null,<br/>target=”myentity”<br/>)
요청 응답 경로 만들기 --> attach(<br/>name={*link name*},<br/>handle={*numeric handle*},<br/>role=**receiver**,<br/>source=”myentity/$management”,<br/>target=”myclient$id”<br/>)
요청 응답 경로 만들기 작업 없음 \<-- attach(<br/>name={*link name*},<br/>handle={*numeric handle*},<br/>role=**sender**,<br/>source=”myentity”,<br/>target=”myclient$id”<br/>)

링크 쌍이 배치되면 요청/응답 구현은 간단합니다. 요청은 이 패턴을 파악하는 메시징 인프라 내부의 엔터티로 전송되는 메시지입니다. 해당 요청 메시지에서 속성 섹션의 회신 필드는 응답을 전달할 링크의 대상 식별자로 설정됩니다. 처리 엔터티에서는 요청을 처리한 다음 해당 대상 식별자가 지정된 회신 식별자와 일치하는 링크를 통해 회신을 전달합니다.

이 패턴을 사용하려면 회신 대상에 대한 클라이언트 컨테이너 및 클라이언트 생성 식별자가 모든 클라이언트에서 고유해야 하며 보안상의 이유로 예측하기도 어렵습니다.

관리 프로토콜 및 동일한 패턴을 사용하는 다른 모든 프로토콜에 사용되는 메시지 교환은 애플리케이션 수준에서 발생합니다. 또한 새로운 AMQP 프로토콜 수준 제스처를 정의하지 않습니다. 이러한 방식은 애플리케이션이 호환 AMQP 1.0 스택에서 이러한 확장을 즉시 활용할 수 있도록 하기 위해 의도된 것입니다.

Service Bus는 현재 관리 사양의 어떤 핵심 기능도 구현하지 않지만 관리 사양이 정의하는 요청/응답 패턴은 클레임 기반 보안 기능 및 다음 섹션에서 다룰 고급 기능 대부분의 토대가 됩니다.

클레임 기반 권한 부여

AMQP CBS(클레임 기반 권한 부여) 사양 초안은 관리 사양 요청/응답 패턴을 기반으로 하며, AMQP와 함께 페더레이션된 보안 토큰을 사용하는 방법에 대한 일반화된 모델을 설명합니다.

소개 부분에서 나오는 AMQP의 기본 보안 모델은 SASL을 기준으로 하며, AMQP 연결 핸드셰이크와 통합됩니다. SASL을 사용하면 SASL에 공식적으로 의지하는 모든 프로토콜이 이점을 얻을 수 있는 메커니즘 집합이 정의된 확장 가능한 모델을 제공한다는 이점이 있습니다. 이러한 메커니즘 중에는 사용자 이름 및 암호 전송을 위한 "PLAIN", TLS 수준 보안에 바인딩하는 "EXTERNAL", 명시적 인증/권한 부여의 부재를 표현하는 "ANONYMOUS", 인증 및/또는 권한 부여 자격 증명 또는 토큰 전달을 허용하는 다양한 추가 메커니즘이 있습니다.

AMQP의 SASL 통합에는 다음과 같은 두 가지 단점이 있습니다.

  • 모든 자격 증명 및 토큰은 연결로 범위가 지정됩니다. 메시징 인프라는 엔터티별로 차별화된 액세스 제어를 제공할 수 있습니다. 예를 들어 토큰의 전달자가 큐 A로 보낼 수 있지만 큐 B에는 보내지 않도록 허용합니다. 연결에 고정된 권한 부여 컨텍스트를 사용하면 단일 연결을 사용할 수 없으며 큐 A 및 큐 B에 대해 다른 액세스 토큰을 사용할 수 없습니다.
  • 액세스 토큰은 일반적으로 제한된 시간 동안만 유효합니다. 이 유효성을 사용하려면 사용자가 주기적으로 토큰을 다시 획득해야 하며, 사용자의 액세스 권한이 변경된 경우 토큰 발급자가 새 토큰 발급을 거부할 수 있는 기회를 제공합니다. AMQP 연결은 오랜 시간 동안 지속될 수 있습니다. SASL 모델은 연결 시 토큰을 설정할 수 있는 기회만 제공합니다. 즉, 메시징 인프라는 토큰이 만료될 때 클라이언트의 연결을 끊어야 하거나 액세스 권한이 있는 클라이언트와의 지속적인 통신이 중간에 해지될 수 있는 위험을 감수해야 합니다.

Service Bus에서 구현된 AMQP CBS 사양을 사용하면 이러한 두 가지 문제에 대해 세련된 해결 방법을 사용할 수 있습니다. 즉, 클라이언트가 액세스 토큰을 각 노드와 연결하고 메시지 흐름을 중단하지 않고 만료되기 전에 해당 토큰을 업데이트할 수 있습니다.

CBS는 메시징 인프라에서 제공할 $cbs 가상 관리 노드를 정의합니다. 관리 노드는 메시징 인프라의 다른 노드를 대신하여 토큰을 수락합니다.

프로토콜 제스처는 관리 사양에 정의된 요청/회신 교환입니다. 즉, 클라이언트는 $cbs 노드를 사용하여 링크 쌍을 설정한 다음 아웃바운드 링크에 대한 요청을 전달한 다음 인바운드 링크에서 응답을 기다립니다.

요청 메시지에는 다음과 같은 애플리케이션 속성이 있습니다.

선택 사항 값 유형 값 내용
operation 아니요 string put-token
type 아니요 string 넣을 토큰의 형식입니다.
name 아니요 string 토큰이 적용되는 "대상 그룹"입니다.
expiration timestamp 토큰의 만료 시간입니다.

이름 속성은 토큰이 연결되어야 하는 엔터티를 식별합니다. Service Bus에서 큐 또는 토픽/구독의 경로입니다. type 속성은 토큰 형식을 식별합니다.

토큰 형식 토큰 설명 본문 유형 주의
jwt JWT(JSON 웹 토큰) AMQP 값(문자열)
servicebus.windows.net:sastoken Service Bus SAS 토큰 AMQP 값(문자열) -

토큰은 권한을 부여합니다. Service Bus는 세 가지 기본 권한에 대해 알고 있습니다. "보내기"는 보내기를 사용하도록 설정하고, "수신"을 사용하도록 설정하고, "관리"를 통해 엔터티를 조작할 수 있습니다. Service Bus SAS 토큰은 네임스페이스 또는 엔터티에 구성된 규칙을 참조하며 해당 규칙은 권한으로 구성됩니다. 따라서 해당 규칙과 연결된 키로 토큰에 서명하면 토큰이 해당 권한을 나타냅니다. put-token을 사용하여 엔터티와 연결된 토큰 을 사용하면 연결된 클라이언트가 토큰 권한에 따라 엔터티와 상호 작용할 수 있습니다. 클라이언트가 발신자 역할을 맡고 있는 링크에는 "전송" 권한이 필요하고, 수신자 역할을 맡고 있는 링크에는 "수신" 권한이 필요합니다.

회신 메시지는 다음과 같은 애플리케이션 속성 값을 갖습니다.

선택 사항 값 유형 값 내용
status-code 아니요 int HTTP 응답 코드 [RFC2616]
status-description string 상태 대한 설명입니다.

클라이언트는 메시징 인프라의 모든 엔터티에 대해 반복적으로 put-token을 호출할 수 있습니다. 토큰은 현재 클라이언트로 범위가 지정되며 현재 연결에 고정됩니다. 즉, 연결이 삭제되면 서버는 보유된 토큰을 모두 삭제합니다.

현재 Service Bus 구현에서는 SASL 메서드 "ANONYMOUS"와 함께 CBS만 허용합니다. SSL/TLS 연결은 SASL 핸드셰이크 이전에 항상 존재해야 합니다.

따라서 ANONYMOUS 메커니즘은 선택한 AMQP 1.0 클라이언트에서 지원되어야 합니다. 익명 액세스는 초기 세션 만들기를 포함하여 초기 연결 핸드셰이크가 Service Bus가 연결을 만드는 사람을 알지 못하면 발생한다는 것을 의미합니다.

연결 및 세션이 설정되고 나면 링크가 $cbs 노드에 연결되고 put-token 요청이 전송될 수만 있습니다. 연결이 설정된 후 20초 이내에 일부 엔터티 노드에 대한 put-token 요청을 사용하여 유효한 토큰 을 성공적으로 설정해야 합니다. 그렇지 않으면 Service Bus에서 연결을 일방적으로 삭제합니다.

이후에 클라이언트는 토큰 만료를 추적할 책임이 있습니다. 토큰이 만료되면 Service Bus는 해당 엔터티에 대한 연결의 모든 링크를 즉시 삭제합니다. 문제가 발생하지 않도록 클라이언트는 다른 링크에서 흐르는 페이로드 트래픽을 방해하지 않고 가상 $cbs 관리 노드를 통해 언제든지 노드에 대한 토큰을 새 토큰으로 바꿀 수 있습니다.

경유 전송 기능

송신/전송 발신자 는 서비스 버스가 다른 엔터티를 통해 지정된 메시지를 대상 엔터티로 전달할 수 있는 기능입니다. 이 기능은 단일 트랜잭션에서 엔터티 간에 작업을 수행하는 데 사용됩니다.

이 기능을 사용하면 발신자를 만들고 에 대한 링크를 via-entity설정합니다. 링크를 설정하는 동안 이 링크에서 메시지/전송의 실제 대상을 설정하기 위해 추가 정보가 전달됩니다. 연결에 성공하면 이 링크에서 보낸 모든 메시지가 엔터티를 통해 대상 엔터티로 자동으로 전달됩니다.

참고: 이 링크를 설정하기 전에 via-entitydestination-entity 모두에 대해 인증이 수행되어야 합니다.

클라이언트 방향 Service Bus
attach(<br/>name={link name},<br/>role=sender,<br/>source={client link ID},<br/>target=**{via-entity}**,<br/>**properties=map [(<br/>com.microsoft:transfer-destination-address=<br/>{destination-entity} )]** ) ------>
<------ attach(<br/>name={link name},<br/>role=receiver,<br/>source={client link ID},<br/>target={via-entity},<br/>properties=map [(<br/>com.microsoft:transfer-destination-address=<br/>{destination-entity} )] )

다음 단계

AMQP에 대한 자세한 내용은 Service Bus AMQP 개요를 참조하세요.