Кратко
- В каждой RPC message версии 2 первым идёт 32-битный XID, а REPLY копирует XID соответствующего CALL. Поле помогает клиенту найти ожидающий вызов и даёт серверу ключ сравнения для возможной повторной передачи, но не является счётчиком или свидетельством одного эффекта.
- NFS перенёс неопределённость в файловые операции. Кэш дубликатов NFSv3 помнил недавние результаты лишь до вытеснения или сбоя; сессии NFSv4.1 ограничили число незавершённых запросов слотами, добавили последовательность на слот и сохранили ответ, сделав цену сильной гарантии явной.
Номер сообщения не был журналом действия
Клиент отправляет серверу просьбу удалить имя и не получает ответа. Запрос мог исчезнуть до сервера. Сервер мог выполнить удаление, после чего потерялся ответ. Наконец, связь могла оборваться уже после изменения состояния, но до того, как клиент успел принять подтверждение.
Во всех трёх случаях клиент видит один и тот же timeout. Повтор помогает в первом варианте и способен повторить эффект во втором. Если сервер сочтёт каждую похожую просьбу старой, он подавит единственную дошедшую копию; если каждую новой — может выполнить неидемпотентное действие дважды.
В RFC 1050, опубликованной в апреле 1988 года, эта граница не скрывалась за сходством удалённой и локальной процедуры: RPC не брал на себя обеспечение надёжности. Сменившая её в июне RFC 1057 сформулировала следствие для UDP. Ответ подтверждает как минимум одно выполнение; отсутствие ответа после повторов не сообщает, сколько их было.
Значит, наблюдение сети и история эффекта — разные объекты. Таймер говорит о знании клиента. Он не читает состояние приложения на удалённой машине.
XID давал узкую общую точку сравнения
Сообщение ONC RPC версии 2 начинается с unsigned integer длиной 32 бита. В ответе стоит XID вызова, породившего этот ответ. Когда одновременно ожидается несколько процедур, клиент возвращает результат правильному локальному контексту.
На этом стандартная власть поля заканчивается. RFC 5531 разрешает стороне сервиса проверять XID на равенство, чтобы распознать возможную retransmission, но запрещает обращаться с ним как с sequence number. Рост значения не задаёт время, расстояние между числами не означает пропущенные запросы, а совпадение само по себе не определяет срок жизни.
Базовый протокол оставляет две необходимые операции участникам. Клиент может при повторе использовать старый XID. Сервер может запомнить значение и отказаться заново выполнять совпавший вызов. Когда обе стороны так поступили и запись ещё доступна, возникает некоторая степень execute-at-most-once. Она принадлежит поведению и памяти, а не 32 битам.
Новый XID у повторного запроса разрывает сравнение. Потерянная запись сервера делает бесполезным старый XID. Позднее повторное использование числа способно связать разные события, если поиск не ограничен клиентом, RPC program, version, procedure и эпохой экземпляра сервера.
Даже подходящий ответ удостоверял не всё
Credentials и authentication verifier в RPC отделены от XID. Номер не подписывает аргументы, не устанавливает principal, не выдаёт разрешение и не подтверждает долговечный commit. Он связывает сообщения в рамках состояния участвующих систем.
В RFC 1831 и RFC 5531 сказано, что полученный ответ поверх надёжного транспорта позволяет в их модели сделать вывод exactly once. Но трудный случай сохранён рядом: если ответа нет, вызывающая сторона не знает, исполнялась ли процедура, а после сбоя сервера всё равно нужны timeout и восстановление соединения.
Надёжный поток упорядочивает байты внутри своей жизни. Он не переносит через crash журнал приложения и не определяет, относится ли запрос после reconnect к эффекту до разрыва. Как только меняется контекст восстановления, граница доказательства возникает снова.
Stateless NFS снизил один долг и обнажил другой
Ранний Network File System стремился сделать сервер как можно менее зависимым от состояния протокольного разговора. RFC 1094 объясняла выгоду: после отказа сети или сервера клиент возобновляет запросы, не восстанавливая сложную сессию.
Операции по возможности проектировались idempotent. Повторное чтение или запись тех же данных в тот же диапазон часто ведут к эквивалентной цели. Но спецификация прямо перечисляла операции, которые могут не обладать этим свойством. После успешного REMOVE имени уже нет; после первого RENAME исходное имя больше не находится там, где его ищет вторая копия.
RFC 1813 для NFSv3 показала не только другое сообщение об ошибке, но и разрушительный сценарий. Повтор запроса, похожего на truncate, способен стереть записи, появившиеся после первой копии. Соединение не устраняет риск автоматически: после обрыва и нового подключения клиент может повторить вызов, результат которого ему неизвестен.
Stateless относилось к обязанности хранить разговор, а не к отсутствию истории у файла. Идемпотентность уменьшала ущерб от незнания, но не превращала незнание в доказательство.
Кэш дубликатов хранил решение на ограниченное время
Практический ответ NFSv3 состоял в duplicate request cache. Завершив вызов, сервер оставлял его completion status. Если повтор узнавался, сервер возвращал прежний результат, не применяя операцию ещё раз.
Это был механизм корректности: свидетельство оставалось там, где был совершён эффект. Однако RFC 1813 фиксировала срок его власти. Обычный кэш находился в RAM и исчезал при crash. Конечная ёмкость означала вытеснение; долгая partition могла продлиться дольше записи, хотя клиент всё ещё имел право повторить вызов. После этого старая копия выглядела новой.
В таком случае XID не перестал быть идентификатором транзакционного обмена. Исчезла среда, которая умела превратить равенство в возврат сохранённого ответа. Поэтому называть XID долговечным idempotency key неточно: такое имя скрывает область поиска, срок хранения, эвикцию, server epoch, способ репликации при failover и связь с конкретной процедурой.
Для EXCLUSIVE CREATE в NFSv3 появилась более сильная, но локальная конструкция: verifier связывался с созданным объектом, потому что обычной летучей памяти дубликатов было недостаточно. Дополнительное свидетельство защищало одну операцию; оно не наделяло все XID новым глобальным смыслом.
Слоты превратили открытую историю в конечную обязанность
NFSv4.1 не стал хранить результат для каждого возможного значения XID. RFC 5661 ввела sessions, а действующая RFC 8881 описывает согласованный набор slots. У каждого слота есть sequence ID и кэш ответа текущего запроса.
Requester занимает свободный слот. Для нового запроса он увеличивает последовательность слота, для повторной передачи текущего сохраняет значение. Replier различает ожидаемое новое значение, повтор текущего и нарушение порядка. Если исходное выполнение завершилось, повтор получает сохранённый ответ вместо второго применения COMPOUND.
Сам слот так же важен, как последовательность. Согласованный предел ограничивает одновременно выполняющиеся запросы, а значит, и число результатов, которое сервер обязан защищать. Следующее значение последовательности сообщает, что клиент уже прошёл предыдущий результат и запись слота можно заменить.
RFC 8881 сравнивает это с непрозрачным пространством XID. Вызовы RPC могут завершаться не по порядку; одно 32-битное значение не говорит replier, сколько старых ответов ещё востребовано. Бесконечно помнить весь простор чисел невозможно. Таблица слотов локализует долг: конечное число известных текущих результатов находится под охраной.
Граница exactly once проходила через перезапуск
Если при restart исчезают таблица и reply cache, сервер не может свидетельствовать о том, чего больше не помнит. Полная EOS через перезапуск требует устойчивого хранения состояния восстановления и ответов. Летучая реализация остаётся полезной при обычных потерях пакетов, но не получает права распространять вывод на утраченную эпоху.
При этом сессии не отменили XID. Слой RPC продолжает сопоставлять CALL и REPLY, в том числе для обменов вне обычного пути SEQUENCE. Новый механизм не заменил узкий идентификатор универсальным. Он добавил состояние там, где приложению потребовалось более сильное утверждение об исполнении.
Историческая линия поэтому состоит из разных обязанностей. XID соединяет сообщение с ответом. Кэш временно связывает совпадение с прежним исходом. Слот ограничивает количество охраняемых исходов. Персистентность определяет, через какие сбои эта связь остаётся доказуемой.
Равенство не разрешало спор о прошлом
Одинаковый XID не доказывает равенство аргументов, principal, server instance или boot epoch. Cache miss не удостоверяет новизну, cache hit — устойчивость commit. Даже повторяемая сама по себе операция может быть опасна при другом порядке: RFC 8881 приводит случай, когда задержавшийся старый WRITE исполняется после нового и перезаписывает его данные.
Корректный вывод скромнее. XID позволяет работающим сторонам сравнить метки. Однократное исполнение появляется лишь тогда, когда исполнитель достаточно долго сохраняет связь между меткой, запросом, эффектом, ответом и границей восстановления.
Источники и границы доказательств
Исходная семантика RPC изложена в RFC 1050 и 1057, затем в RFC 1831 и стандартной RFC 5531. Цель stateless NFS описывает RFC 1094, поведение и предел кэша дубликатов — RFC 1813. Сессии NFSv4.1 появились в RFC 5661, их текущая форма дана в RFC 8881. Эти документы подтверждают правила протоколов и описанные модели сбоев, но не измеряют современные размеры кэшей, политику персистентности, распространённость или соответствие конкретных реализаций.
Обзор для участников
Подробный контекст профиля
Войдите с подходящим уровнем подписки, чтобы открыть полный обзор и примечания к источникам.
Только для Стратегического сообщества
Стратегическое сообщество
Открыто всем читателям. Вступите и войдите, чтобы открыть обзоры профилей.
Вступить в Стратегическое сообществоТолько для Альянса лидеров
Альянс лидеров
Для проверенных владельцев IP-активов и руководителей. Войдите, чтобы открыть обзоры Альянса.
Вступить в Альянс лидеров
