제8장 신뢰성 보장

8.1 신뢰성 모델

DTP 구현은 다음 신뢰성 보장을 제공해야 한다:

  1. 재개: 하위 연결이 중단된 후 전송을 회복하며, 이미 성공적으로 수신된 데이터를 재전송해서는 안 된다.
  2. 확인응답: 수신측은 송신측에 성공적으로 수신한 Fragment를 확인해야 한다.
  3. 재전송: 송신측은 타임아웃 내에 확인응답을 받지 못하면 미확인 Fragment를 재전송해야 한다.
  4. 세션 영속화: 하위 연결이 중단되면 세션 상태를 영속화해야 한다.

8.2 재개 메커니즘

8.2.1 재개 프로토콜

재개는 시퀀스 번호 기반으로 구현되어야 하며, 다음 흐름을 따른다:

송신측                              수신측
   |                                   |
   |-- Fragment (seq=1) -------------->|  ✓ 수신
   |-- Fragment (seq=2) -------------->|  ✓ 수신
   |-- Fragment (seq=3) -------------->|  ✓ 수신
   |-- Fragment (seq=4) ------- ✗ ----|  연결 중단
   |                                   |
   |        [연결 회복]                  |
   |                                   |
   |<-- ResumeReport (highest=3) ------|
   |                                   |
   |-- Fragment (seq=4) -------------->|  단절 지점에서 계속
   |-- Fragment (seq=5) -------------->|

8.2.2 ResumeReport

수신측은 연결 회복 후 ResumeReport를 전송해야 하며, 정의는 다음과 같다:

interface ResumeReport {
  collectionHighest: SequenceNumber;
  injectionHighest: SequenceNumber;
}
필드규범적 요구사항
collectionHighest수신측이 데이터 수집 방향에서 성공적으로 수신한 최고 시퀀스 번호여야 한다
injectionHighest수신측이 데이터 주입 방향에서 성공적으로 수신한 최고 시퀀스 번호여야 한다

특정 방향에서 아직 어떠한 Fragment도 수신하지 못한 경우, 해당 필드는 -1 또는 구현 정의의 "미수신" 식별 값이어야 한다.

8.2.3 재개 일관성

송신측은 ResumeReport를 받은 후 다음을 엄격히 준수해야 한다:

  1. 다음 시퀀스 번호부터 계속: highest + 1부터 다시 전송한다.
  2. 중복 전송 금지: 시퀀스 번호 <= highest인 Fragment를 다시 전송해서는 안 된다.
  3. 건너뜀 금지: 미확인 Fragment(즉, 캐시에서 수신 확인되지 않은 Fragment)를 건너뛰어서는 안 된다.

8.3 확인응답 메커니즘

8.3.1 확인응답 방식

구현은 Fragment 수신 확인응답을 제공해야 한다. 확인응답은 다음 방식 중 하나로 구현될 수 있다:

  1. 명시적 ACK 제어 프레임: 수신측이 ControlFrame을 전송하고 controlType = "ack", details에 확인된 최고 시퀀스 번호를 포함.
  2. 누적 ACK: 각 데이터 프레임의 확장 필드에 역방향의 최고 수신 시퀀스 번호를 포함(권장).
  3. 배치 ACK: N개의 Fragment를 수신할 때마다 한 번 ACK를 전송(N은 구현 정의, 16을 권장).

구체적 확인응답 방식은 구현이 선택할 수 있으나, 수신측과 송신측은 선택된 방식에 대해 합의해야 한다.

8.3.2 확인응답 시점

수신측은 다음을 충족해야 한다:

  1. Fragment가 복호화, Agreement 검증, DAG 검증을 통과한 후에만 확인할 수 있다.
  2. DAG가 pending 상태일 때 확인해서는 안 된다(의존 해석 후 다시 확인해야 한다).
  3. ACK의 최고 시퀀스 번호는 이미 확인된 시퀀스 번호 집합의 연속된 접두사의 최댓값이어야 한다.

8.4 재전송 메커니즘

8.4.1 재전송 정책

송신측은 다음 조건에서 재전송해야 한다:

  1. 프로토콜이 설정한 재전송 타임아웃 시간 내에 해당 시퀀스 번호의 ACK를 받지 못한 경우.
  2. ResumeReport를 받았을 때 미확인 Fragment에 대해 재전송.

8.4.2 재전송 설정

구현은 다음 설정 가능한 매개변수를 제공해야 한다(권장):

매개변수기본값(권장)설명
초기 재전송 타임아웃5초첫 번째 재전송 대기 시간
재전송 백오프 계수2재전송할 때마다 타임아웃 두 배(지수 백오프)
최대 재전송 횟수5초과 시 상위에 실패 통지
최대 재전송 타임아웃60초재전송 타임아웃 상한

구현은 지수 백오프 알고리즘을 구현해야 한다.

8.4.3 재전송 실패 처리

재전송 횟수가 상한을 초과하면:

  1. 송신측은 상위 애플리케이션에 RETRANSMISSION_TIMEOUT 오류(6002)를 통지해야 한다.
  2. 송신측은 세션 일시 중지 또는 종료를 트리거해야 한다(권장)(구현 정의).
  3. 구현은 무한 재전송해서는 안 된다.

8.5 캐시 관리

8.5.1 미확인 Fragment 캐시

송신측은 미확인 Fragment 캐시를 유지해야 하며, 다음을 충족해야 한다:

  1. 전송되었지만 확인을 받지 못한 각 Fragment는 캐시에 보관되어야 한다.
  2. 확인을 받으면 캐시에서 확인된 Fragment를 제거해야 한다.
  3. 캐시는 용량 상한을 가져야 한다(구현 정의, 권장 1024개 Fragment 또는 16 MB 이상).

8.5.2 캐시 가득 처리

캐시가 용량 상한에 도달하면 송신측은 다음을 수행해야 한다:

  1. 새 Fragment 전송을 일시 중지한다.
  2. BUFFER_FULL 오류(6001)를 통해 상위 애플리케이션에 통지한다.
  3. 캐시 공간이 해제되었음을 확인한 후 전송을 재개한다.
  4. Fragment를 조용히 폐기해서는 안 된다.

8.6 세션 관리

8.6.1 세션 수립

CAP가 신원 검증과 키 교환을 완료한 후, DTP_Engine은 DTP 세션을 수립해야 한다:

  1. RFC 4122를 따르는 고유 Session_ID(UUID v4)를 생성해야 한다.
  2. Session 데이터 구조를 초기화해야 한다(제8.6.3절 참조).
  3. 상태를 WaitingForCAP에서 SessionEstablished로 전이해야 한다.

8.6.2 세션 상태 유지

DTP_Engine은 세션 기간 동안 양방향 전송 상태를 유지해야 한다:

interface DirectionalTransferState {
  currentSequenceNumber: SequenceNumber;
  highestAcknowledgedSequenceNumber: SequenceNumber;
  unacknowledgedFragmentCache: Map<SequenceNumber, Fragment>;
}

구현은 각 전송 방향마다 독립적인 DirectionalTransferState를 유지해야 한다:

방향필드명
데이터 수집 (Terminal → Fay)collectionState
데이터 주입 (Fay → Terminal)injectionState

8.6.3 Session 데이터 구조

완전한 Session 구조는 다음을 포함해야 한다:

interface Session {
  sessionId: SessionID;
  masterIdentity: string;
  slaveIdentity: string;
  state: SessionState;
  activeAgreements: Map<AgreementID, Agreement>;
  collectionState: DirectionalTransferState;
  injectionState: DirectionalTransferState;
  createdAt: number;
  lastActivityAt: number;
  timeoutThreshold: number;
}

8.6.4 세션 영속화

하위 전송 연결이 단절되면 DTP_Engine은 다음을 수행해야 한다:

  1. 즉시 SessionState를 Transmitting에서 Suspended로 전이한다.
  2. 다음 내용을 비휘발성 저장소에 영속화한다:
    • 완전한 Session 객체(모든 active 약정 포함)
    • 양방향 DirectionalTransferState
    • 미확인 Fragment 캐시
  3. 영속화는 원자적이어야 한다(모두 성공하거나 모두 실패).

8.6.5 세션 회복

하위 연결이 다시 수립된 후, DTP_Engine은 다음 회복 흐름을 따라야 한다:

  1. CAP 재검증을 대기한다.
  2. CAP 검증이 성공하면 Resuming 상태로 진입한다.
  3. 영속화 저장소에서 Session 상태를 복구한다.
  4. 수신측이 ResumeReport를 전송한다(제8.2.2절 참조).
  5. 송신측이 ResumeReport에 따라 단절 지점부터 전송을 계속한다.
  6. 재개 핸드셰이크가 완료되면 Transmitting으로 전이한다.

회복이 실패하면 DTP_Engine은 다음을 수행해야 한다:

  1. Idle 상태로 전이한다.
  2. 모든 관련 자원을 해제한다.
  3. SESSION_RESTORE_FAILED 오류(5003)를 통해 상위에 통지한다.

8.6.6 세션 타임아웃

구현은 세션 타임아웃 메커니즘을 구현해야 한다:

  1. 마지막 활동 시점을 기록하는 lastActivityAt 필드를 유지해야 한다.
  2. now - lastActivityAt > timeoutThreshold일 때 세션을 타임아웃으로 설정해야 한다.
  3. 타임아웃된 세션은 닫혀야 하며, 관련 자원은 해제되어야 한다.
  4. 기본 timeoutThreshold는 30분(1,800,000 ms)을 권장한다.

8.7 양방향 독립성

구현은 두 전송 방향의 독립성을 엄격히 보장해야 한다:

  1. 데이터 수집 방향의 상태 변화는 데이터 주입 방향에 영향을 미쳐서는 안 된다.
  2. 한 방향의 연결 이상은 다른 방향의 상태 변경을 자동으로 트리거해서는 안 된다(하위 연결 전체가 단절되는 경우 제외).
  3. 한 방향의 시퀀스 번호는 다른 방향의 시퀀스 번호 공간으로 진입해서는 안 된다.
  4. 한 방향의 캐시는 다른 방향의 캐시 할당량을 차지해서는 안 된다.