제8장 신뢰성 보장
8.1 신뢰성 모델
DTP 구현은 다음 신뢰성 보장을 제공해야 한다:
- 재개: 하위 연결이 중단된 후 전송을 회복하며, 이미 성공적으로 수신된 데이터를 재전송해서는 안 된다.
- 확인응답: 수신측은 송신측에 성공적으로 수신한 Fragment를 확인해야 한다.
- 재전송: 송신측은 타임아웃 내에 확인응답을 받지 못하면 미확인 Fragment를 재전송해야 한다.
- 세션 영속화: 하위 연결이 중단되면 세션 상태를 영속화해야 한다.
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를 받은 후 다음을 엄격히 준수해야 한다:
- 다음 시퀀스 번호부터 계속:
highest + 1부터 다시 전송한다. - 중복 전송 금지: 시퀀스 번호
<= highest인 Fragment를 다시 전송해서는 안 된다. - 건너뜀 금지: 미확인 Fragment(즉, 캐시에서 수신 확인되지 않은 Fragment)를 건너뛰어서는 안 된다.
8.3 확인응답 메커니즘
8.3.1 확인응답 방식
구현은 Fragment 수신 확인응답을 제공해야 한다. 확인응답은 다음 방식 중 하나로 구현될 수 있다:
- 명시적 ACK 제어 프레임: 수신측이 ControlFrame을 전송하고
controlType = "ack", details에 확인된 최고 시퀀스 번호를 포함. - 누적 ACK: 각 데이터 프레임의 확장 필드에 역방향의 최고 수신 시퀀스 번호를 포함(권장).
- 배치 ACK: N개의 Fragment를 수신할 때마다 한 번 ACK를 전송(N은 구현 정의, 16을 권장).
구체적 확인응답 방식은 구현이 선택할 수 있으나, 수신측과 송신측은 선택된 방식에 대해 합의해야 한다.
8.3.2 확인응답 시점
수신측은 다음을 충족해야 한다:
- Fragment가 복호화, Agreement 검증, DAG 검증을 통과한 후에만 확인할 수 있다.
- DAG가
pending상태일 때 확인해서는 안 된다(의존 해석 후 다시 확인해야 한다). - ACK의 최고 시퀀스 번호는 이미 확인된 시퀀스 번호 집합의 연속된 접두사의 최댓값이어야 한다.
8.4 재전송 메커니즘
8.4.1 재전송 정책
송신측은 다음 조건에서 재전송해야 한다:
- 프로토콜이 설정한 재전송 타임아웃 시간 내에 해당 시퀀스 번호의 ACK를 받지 못한 경우.
- ResumeReport를 받았을 때 미확인 Fragment에 대해 재전송.
8.4.2 재전송 설정
구현은 다음 설정 가능한 매개변수를 제공해야 한다(권장):
| 매개변수 | 기본값(권장) | 설명 |
|---|---|---|
| 초기 재전송 타임아웃 | 5초 | 첫 번째 재전송 대기 시간 |
| 재전송 백오프 계수 | 2 | 재전송할 때마다 타임아웃 두 배(지수 백오프) |
| 최대 재전송 횟수 | 5 | 초과 시 상위에 실패 통지 |
| 최대 재전송 타임아웃 | 60초 | 재전송 타임아웃 상한 |
구현은 지수 백오프 알고리즘을 구현해야 한다.
8.4.3 재전송 실패 처리
재전송 횟수가 상한을 초과하면:
- 송신측은 상위 애플리케이션에
RETRANSMISSION_TIMEOUT오류(6002)를 통지해야 한다. - 송신측은 세션 일시 중지 또는 종료를 트리거해야 한다(권장)(구현 정의).
- 구현은 무한 재전송해서는 안 된다.
8.5 캐시 관리
8.5.1 미확인 Fragment 캐시
송신측은 미확인 Fragment 캐시를 유지해야 하며, 다음을 충족해야 한다:
- 전송되었지만 확인을 받지 못한 각 Fragment는 캐시에 보관되어야 한다.
- 확인을 받으면 캐시에서 확인된 Fragment를 제거해야 한다.
- 캐시는 용량 상한을 가져야 한다(구현 정의, 권장 1024개 Fragment 또는 16 MB 이상).
8.5.2 캐시 가득 처리
캐시가 용량 상한에 도달하면 송신측은 다음을 수행해야 한다:
- 새 Fragment 전송을 일시 중지한다.
BUFFER_FULL오류(6001)를 통해 상위 애플리케이션에 통지한다.- 캐시 공간이 해제되었음을 확인한 후 전송을 재개한다.
- Fragment를 조용히 폐기해서는 안 된다.
8.6 세션 관리
8.6.1 세션 수립
CAP가 신원 검증과 키 교환을 완료한 후, DTP_Engine은 DTP 세션을 수립해야 한다:
- RFC 4122를 따르는 고유 Session_ID(UUID v4)를 생성해야 한다.
- Session 데이터 구조를 초기화해야 한다(제8.6.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은 다음을 수행해야 한다:
- 즉시 SessionState를
Transmitting에서Suspended로 전이한다. - 다음 내용을 비휘발성 저장소에 영속화한다:
- 완전한 Session 객체(모든 active 약정 포함)
- 양방향 DirectionalTransferState
- 미확인 Fragment 캐시
- 영속화는 원자적이어야 한다(모두 성공하거나 모두 실패).
8.6.5 세션 회복
하위 연결이 다시 수립된 후, DTP_Engine은 다음 회복 흐름을 따라야 한다:
- CAP 재검증을 대기한다.
- CAP 검증이 성공하면
Resuming상태로 진입한다. - 영속화 저장소에서 Session 상태를 복구한다.
- 수신측이 ResumeReport를 전송한다(제8.2.2절 참조).
- 송신측이 ResumeReport에 따라 단절 지점부터 전송을 계속한다.
- 재개 핸드셰이크가 완료되면
Transmitting으로 전이한다.
회복이 실패하면 DTP_Engine은 다음을 수행해야 한다:
Idle상태로 전이한다.- 모든 관련 자원을 해제한다.
SESSION_RESTORE_FAILED오류(5003)를 통해 상위에 통지한다.
8.6.6 세션 타임아웃
구현은 세션 타임아웃 메커니즘을 구현해야 한다:
- 마지막 활동 시점을 기록하는
lastActivityAt필드를 유지해야 한다. now - lastActivityAt > timeoutThreshold일 때 세션을 타임아웃으로 설정해야 한다.- 타임아웃된 세션은 닫혀야 하며, 관련 자원은 해제되어야 한다.
- 기본
timeoutThreshold는 30분(1,800,000 ms)을 권장한다.
8.7 양방향 독립성
구현은 두 전송 방향의 독립성을 엄격히 보장해야 한다:
- 데이터 수집 방향의 상태 변화는 데이터 주입 방향에 영향을 미쳐서는 안 된다.
- 한 방향의 연결 이상은 다른 방향의 상태 변경을 자동으로 트리거해서는 안 된다(하위 연결 전체가 단절되는 경우 제외).
- 한 방향의 시퀀스 번호는 다른 방향의 시퀀스 번호 공간으로 진입해서는 안 된다.
- 한 방향의 캐시는 다른 방향의 캐시 할당량을 차지해서는 안 된다.
