Глава 8. Надёжность
8.1 Модель надёжности
Реализация DTP MUST обеспечивать следующие гарантии надёжности:
- Возобновление: после разрыва нижележащего соединения передача возобновляется; данные, уже успешно полученные, MUST NOT повторно передаваться.
- Подтверждение: получатель MUST подтверждать отправителю Fragment, которые были успешно получены.
- Повторная передача: отправитель MUST повторно передавать неподтверждённые Fragment, если подтверждение не получено в пределах тайм-аута.
- Сохранение Session: при разрыве нижележащего соединения состояние Session MUST быть сохранено.
8.2 Механизм возобновления
8.2.1 Протокол возобновления
Возобновление MUST реализовываться на основе порядковых номеров и следовать данному рабочему процессу:
Sender Receiver
| |
|-- Fragment (seq=1) ---------------->| ✓ received
|-- Fragment (seq=2) ---------------->| ✓ received
|-- Fragment (seq=3) ---------------->| ✓ received
|-- Fragment (seq=4) -------- ✗ -----| connection lost
| |
| [connection restored] |
| |
|<-- ResumeReport (highest=3) --------|
| |
|-- Fragment (seq=4) ---------------->| resume from breakpoint
|-- Fragment (seq=5) ---------------->|
8.2.2 ResumeReport
После восстановления соединения получатель MUST отправить ResumeReport, определённый следующим образом:
interface ResumeReport {
collectionHighest: SequenceNumber;
injectionHighest: SequenceNumber;
}
| Поле | Нормативное требование |
|---|---|
collectionHighest | MUST быть наибольшим порядковым номером, успешно полученным получателем в направлении сбора данных |
injectionHighest | MUST быть наибольшим порядковым номером, успешно полученным получателем в направлении инжекции данных |
Если в каком-либо направлении ещё не получено ни одного Fragment, соответствующее поле MUST быть равно -1 или другому определяемому реализацией дозорному значению «не получено».
8.2.3 Согласованность возобновления
После получения ResumeReport отправитель MUST строго следовать следующим правилам:
- Продолжать со следующего порядкового номера: возобновить отправку, начиная с
highest + 1. - Не отправлять повторно: MUST NOT повторно отправлять любой Fragment с порядковым номером
<= highest. - Не пропускать: MUST NOT пропускать неподтверждённые Fragment (т.е. те, что не подтверждены в кэше).
8.3 Механизм подтверждения
8.3.1 Способы подтверждения
Реализация MUST обеспечивать подтверждение получения Fragment. Подтверждение MAY реализовываться через один из следующих способов:
- Явный ACK control-фрейм: получатель отправляет ControlFrame с
controlType = "ack", в которомdetailsсодержит наибольший подтверждённый порядковый номер. - Кумулятивный ACK: переносить наибольший полученный порядковый номер обратного направления в поле расширения каждого data-фрейма (RECOMMENDED).
- Пакетный ACK: отправлять один ACK на каждые N полученных Fragment (N определяется реализацией; RECOMMENDED значение 16).
Конкретный способ подтверждения MAY выбираться реализацией, но получатель и отправитель MUST прийти к согласию относительно выбранного способа.
8.3.2 Время подтверждения
Получатель MUST удовлетворять следующим требованиям:
- Подтверждать только после того, как Fragment прошёл расшифровку, валидацию Agreement и валидацию DAG.
- MUST NOT подтверждать, пока состояние DAG равно
pending(подтверждение должно быть отложено до разрешения зависимостей). - Наибольший порядковый номер в ACK MUST быть максимумом непрерывного префикса множества подтверждённых порядковых номеров.
8.4 Механизм повторной передачи
8.4.1 Стратегия повторной передачи
Отправитель MUST повторно передавать при следующих условиях:
- ACK для заданного порядкового номера не получен в пределах настроенного протоколом тайм-аута повторной передачи.
- При получении ResumeReport повторно передать неподтверждённые Fragment.
8.4.2 Конфигурация повторной передачи
Реализация SHOULD предоставлять следующие настраиваемые параметры:
| Параметр | По умолчанию (RECOMMENDED) | Описание |
|---|---|---|
| Начальный тайм-аут повторной передачи | 5 секунд | Время ожидания первой повторной передачи |
| Коэффициент отката повторной передачи | 2 | Тайм-аут удваивается после каждой повторной передачи (экспоненциальный откат) |
| Максимальное число повторных передач | 5 | По превышении этого числа уведомить верхний уровень о неудаче |
| Максимальный тайм-аут повторной передачи | 60 секунд | Верхняя граница тайм-аута повторной передачи |
Реализация MUST реализовывать алгоритм экспоненциального отката.
8.4.3 Обработка неудач повторной передачи
При превышении верхнего предела числа повторных передач:
- Отправитель MUST уведомить приложение верхнего уровня об ошибке
RETRANSMISSION_TIMEOUT(6002). - Отправитель SHOULD инициировать приостановку или прекращение Session (определяется реализацией).
- Реализация MUST NOT повторно передавать бесконечно.
8.5 Управление кэшем
8.5.1 Кэш неподтверждённых Fragment
Отправитель MUST поддерживать кэш неподтверждённых Fragment, удовлетворяющий следующим требованиям:
- Каждый Fragment, который был отправлен, но ещё не подтверждён, MUST сохраняться в кэше.
- После получения подтверждения подтверждённый Fragment MUST быть удалён из кэша.
- Кэш MUST иметь верхнюю границу ёмкости (определяется реализацией; RECOMMENDED не менее 1024 Fragment или 16 МБ).
8.5.2 Обработка переполнения кэша
При достижении кэшем верхней границы ёмкости отправитель MUST:
- Приостановить отправку новых Fragment.
- Уведомить приложение верхнего уровня через ошибку
BUFFER_FULL(6001). - Возобновить отправку после освобождения места в кэше за счёт подтверждений.
- MUST NOT молча отбрасывать Fragment.
8.6 Управление сессиями
8.6.1 Установление Session
После того как CAP завершил аутентификацию и обмен ключами, DTP_Engine MUST установить DTP-сессию:
- MUST сгенерировать уникальный Session_ID (UUID v4) в соответствии с RFC 4122.
- MUST инициализировать структуру данных Session (см. раздел 8.6.3).
- MUST перевести состояние из
WaitingForCAPвSessionEstablished.
8.6.2 Поддержка состояния Session
В течение Session DTP_Engine MUST поддерживать состояние двунаправленной передачи:
interface DirectionalTransferState {
currentSequenceNumber: SequenceNumber;
highestAcknowledgedSequenceNumber: SequenceNumber;
unacknowledgedFragmentCache: Map<SequenceNumber, Fragment>;
}
Реализация MUST поддерживать независимый DirectionalTransferState для каждого направления передачи:
| Направление | Имя поля |
|---|---|
| Сбор данных (Терминал → Fay) | collectionState |
| Инжекция данных (Fay → Терминал) | injectionState |
8.6.3 Структура данных Session
Полная структура Session MUST содержать:
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 Сохранение Session
При разрыве нижележащего транспортного соединения DTP_Engine MUST:
- Немедленно перевести SessionState из
TransmittingвSuspended. - Сохранить в энергонезависимое хранилище:
- Полный объект Session (включая все активные Agreement)
- Двунаправленные DirectionalTransferState
- Кэш неподтверждённых Fragment
- Сохранение MUST быть атомарным (либо всё успешно, либо всё неудачно).
8.6.5 Восстановление Session
После повторного установления нижележащего соединения DTP_Engine MUST следовать следующему процессу восстановления:
- Дождаться повторной верификации CAP.
- После успешной верификации CAP перейти в состояние
Resuming. - Восстановить состояние Session из персистентного хранилища.
- Получатель отправляет ResumeReport (см. раздел 8.2.2).
- На основе ResumeReport отправитель возобновляет передачу с точки прерывания.
- После завершения резюм-рукопожатия перейти в
Transmitting.
При неудачном восстановлении DTP_Engine MUST:
- Перейти в состояние
Idle. - Освободить все связанные ресурсы.
- Уведомить верхний уровень через ошибку
SESSION_RESTORE_FAILED(5003).
8.6.6 Тайм-аут Session
Реализация MUST реализовывать механизм тайм-аута Session:
- MUST поддерживать поле
lastActivityAt, фиксирующее время последней активности. - Когда
now - lastActivityAt > timeoutThreshold, Session MUST быть помечена как истёкшая по тайм-ауту. - Истёкшая по тайм-ауту Session MUST быть закрыта, и связанные ресурсы MUST быть освобождены.
- Значение
timeoutThresholdпо умолчанию RECOMMENDED равным 30 минутам (1 800 000 мс).
8.7 Двунаправленная независимость
Реализация MUST строго гарантировать независимость двух направлений передачи:
- Изменения состояния в направлении сбора данных MUST NOT влиять на направление инжекции данных.
- Аномалия соединения в одном направлении MUST NOT автоматически вызывать изменение состояния в другом направлении (если только нижележащее соединение не разорвано полностью).
- Порядковые номера одного направления MUST NOT попадать в пространство порядковых номеров другого направления.
- Кэш одного направления MUST NOT потреблять квоту кэша другого направления.
