요약

  • RFC 3525는 하나의 트랜잭션 안에서는 명령이 순차적으로 처리되도록 보장했지만, 서로 다른 트랜잭션은 임의의 순서로 또는 동시에 실행될 수 있었습니다. 하나의 메시지 안에서도 마찬가지였습니다.
  • Pending 통지, 재전송 제어, 응답 확인 및 at-most-once 처리는 전달과 중복의 경계를 정했지만, 공유된 인과 시계를 만들거나 미디어 결과를 증명하지는 않았습니다.

이 프로토콜이 이 구분을 필요로 한 이유는 게이트웨이가 이미 나뉘어 있었기 때문입니다. 미디어 게이트웨이 컨트롤러(Media Gateway Controller)가 통화 제어 지능을 담당했고, 미디어 게이트웨이(Media Gateway)가 미디어 측 자원을 처리했습니다. RFC 3525는 양자 사이의 언어를 제공했습니다. 컨텍스트(Context)는 관련된 터미네이션(Termination)을 모으고, 액션(Action)은 하나의 컨텍스트를 다루며, 명령(Command)은 상태를 추가, 수정, 이동, 제거 또는 감사(audit)했습니다.

이 계층 구조는 충분히 중첩되어 보여 잘못된 추론을 유도할 수 있었습니다. 메시지(Message)는 트랜잭션(Transaction)을 담고, 트랜잭션은 액션을 담고, 액션은 명령을 담습니다. 문서를 아래로 읽어 내려가면 모든 바깥 컨테이너가 그 안의 모든 것에 순서를 부과한다고 상상하기 쉬웠습니다.

RFC 3525는 그 경계를 다른 곳에 그었습니다. 하나의 트랜잭션 안의 명령은 순차적으로 실행되었습니다. 첫 번째 실패한 필수(non-optional) 명령은 그 트랜잭션 안의 나머지 명령을 중단시켰습니다. 실패한 명령이 Optional로 표시되어 있다면 이후 명령은 계속될 수 있었습니다. 이것은 실제 순서 보장이었지만, 트랜잭션 경계에서 끝났습니다.

서로 다른 트랜잭션은 명시적으로 순서가 정해지지 않았습니다. 게이트웨이는 그것들을 임의의 순서로 또는 동시에 실행할 수 있었습니다. 트랜잭션 A, B, C를 같은 메시지에 담는다고 해서 메시지가 하나의 애플리케이션 시계를 가진 배치가 되는 것은 아니었습니다. 사양은 메시지를 본질적으로 전송 수단이라고 불렀습니다. A와 C에 대한 응답은 함께 돌아오고 B는 나중에 다른 메시지로 도착할 수 있었습니다.

이것은 누락이 아니었습니다. 병렬성 덕분에 컨트롤러는 독립적인 터미네이션에 신속히 대응할 수 있었습니다. 한 프로세스가 한 그룹의 터미네이션을 관리하는 동안 다른 프로세스가 다른 그룹을 처리할 수 있었습니다. 서로 무관한 작업을 전역적으로 직렬화하면 프로토콜은 설명하기 더 쉬워졌겠지만 실행은 더 느려졌을 것입니다.

비용은 작업이 독립적이지 않을 때 나타났습니다. 한 트랜잭션이 게이트웨이에 터미네이션을 Add하라고 요청하고, 다른 트랜잭션이 바로 그 터미네이션을 Modify하라고 요청한다고 가정해 봅시다. 전송 순서가 실행 순서를 증명하지는 못합니다. Add가 목표 상태를 확립하기 전에 Modify가 자신의 실행 차례에 먼저 도착하면, 나중에 보낸 것처럼 보이는 지시가 먼저 실패할 수 있습니다.

따라서 RFC 3525는 컨트롤러에 규율을 부여했습니다. 하나의 터미네이션에 대해서는 의존적인 명령들이 같은 트랜잭션에 배치되지 않는 한, 통상 하나의 Add, Modify 또는 Move만 미처리 상태로 남아 있어야 합니다. 애플리케이션이 자신에게 필요한 더 강한 순서를 만들어야 했습니다. 네트워크 봉투가 근접성만으로 의존성을 추론해 주지는 않았습니다.

Subtract는 이 경합을 더 두드러지게 만들었습니다. 사양은 Subtract가 언제든 발행될 수 있도록 허용했습니다. 따라서 이미 제거된 터미네이션에 대해 Modify가 도착할 수 있었습니다. 게이트웨이는 그런 Modify를 무시하고 오류를 반환해야 합니다. 깨끗한 요청 추적이 전송 순서를 보존하는 동안, 게이트웨이의 상태 이력은 전혀 다른 이야기를 들려줄 수 있었던 것입니다.

Notify에는 같은 문제의 또 다른 형태가 있었습니다. 통지가 컨트롤러가 새 EventsDescriptor를 전송한 이후로 지연될 수 있었습니다. UDP처럼 순서를 보장하지 않는 전송에서는 사양이 터미네이션별로 하나의 미처리 Notify만 두도록 권고했습니다. 수신 확인에는 패킷 위치가 아니라 트랜잭션 식별자, 터미네이션 식별자, 이벤트 요청 식별자 및 시각이 필요했습니다.

트랜잭션 안의 실패도 일상적 의미의 "트랜잭션"보다 좁았습니다. 실패한 명령은 가능한 한 그 명령의 실행 시도 이전 상태로 되돌려야 했습니다. 이 문서는 이미 성공한 이전 명령 전체에 대한 데이터베이스식 롤백을 약속하지 않았습니다. TransactionReply는 성공한 명령의 값과 실패한 명령의 오류 디스크립터를 반환했습니다.

와일드카드 실행은 부분적 증거를 피할 수 없게 만들었습니다. 와일드카드가 적용된 TerminationID를 가진 명령은 모든 일치 항목에 대해 시도되었고, 응답에는 각 항목의 결과가 포함되었습니다. 하나의 일치 항목이 실패하면 트랜잭션 안의 이후 명령은 시도되지 않았습니다. 따라서 컨트롤러는 성공한 와일드카드 인스턴스와 하나 이상의 오류, 그리고 실행되지 않은 이후 작업이 뒤섞인 결과를 받을 수 있었습니다. "트랜잭션 실패"는 현실을 재구성하기에는 너무 거친 정보였습니다.

TransactionPending도 똑같이 정밀했습니다. 이는 처리가 완료되지 않았지만 여전히 진행 중임을 뜻했고, 송신자의 애플리케이션 타이머를 재시작했습니다. 그것은 어떤 명령이 실행되었는지, 어떤 상태 변경이 유지될지, 다른 트랜잭션이 이를 앞질렀는지를 말해 주지 않았습니다.

전송 부속서는 또 다른 문제를 다루었습니다. 응답이 분실되면 요청이 반복될 수 있었습니다. 트랜잭션 식별자, 보관된 응답, 응답 확인 및 재전송 규칙이 at-most-once 동작을 지원했습니다. 이들은 재전송된 요청과 새로운 작업을 구별하는 데 도움이 되었습니다. 그러나 서로 다른 두 트랜잭션 사이의 순서를 확립하지는 않았고, at-most-once 실행은 정확히 한 번(exactly-once)의 서비스 전달이 아니었습니다.

성공적인 응답조차 사용자에게까지는 이르지 못했습니다. 그것은 게이트웨이가 명령을 처리하고 지정된 상태를 반환했다는 것을 증명할 수 있었습니다. 감사(Audit)는 컨텍스트나 터미네이션 속성을 검사할 수 있었습니다. 그러나 어떤 수신 확인 하나만으로도 패킷이 의도된 베어러 경로를 따랐는지, 오디오가 디코딩되었는지, 누군가가 통화를 들었는지는 증명되지 않았습니다.

이 문서의 제도적 역사도 이 경계를 뒷받침합니다. RFC 3525는 2003년 RFC 3015를 대체했으며, IETF Megaco 워킹 그룹과 ITU-T 제16연구그룹의 공동 작업을 반영했습니다. 2008년 RFC 5125는 ITU-T가 교정 및 이후 버전을 통해 H.248.1을 계속 발전시켰기 때문에 이를 Historic으로 이동시켰습니다. RFC 3525는 설계의 순서 모델을 설명할 수 있지만, 현재의 배포 사양으로 제시되어서는 안 됩니다.

운영 중인 IANA Megaco/H.248 레지스트리는 또 하나의 제한된 진실을 말해 줍니다. 패키지 식별자, 오류, 사유 및 프로파일은 이후 참조 문서에 따라 계속 조율되고 있습니다. 레지스트리는 그 주변의 사양이 이동한 뒤에도 공유된 이름을 보존할 수 있습니다. 그러나 어떤 게이트웨이가 어떤 버전을 실행하는지, 두 트랜잭션이 그 안에서 어떻게 경합했는지는 보여 주지 못합니다.

RFC 3525의 오래가는 교훈은 "항상 직렬화하라"가 아닙니다. 보장을 의존성을 소유한 가장 작은 계층에 두라는 것입니다. 독립적인 터미네이션은 병렬로 진행할 수 있습니다. 의존적인 명령은 함께 속하거나 이전 수신 확인을 기다려야 합니다. 공유 프로토콜은 최소한의 공통 순서를 이름 붙이고, 실행 중인 컨트롤러들은 자신에게 필요한 더 강한 인과 이야기에 대해 책임을 지는 셈입니다.

출처