REST ограничен только оптимистичным управлением параллелизмом?

9

контекст

Из-за отсутствия сохранения состояния архитектурного стиля REST, когда каждый запрос стоит отдельно, ведущий сервер никогда не хранит никакой информации о клиенте.

Таким образом, пессимистическое управление параллелизмом не подходит, потому что для этого требуется хранилище сервера, клиент которого получает блокировку ресурса. Затем используется оптимистичный контроль параллелизма с помощью Etagзаголовка. (кстати, как я и просил там /programming/30080634/concurrency-in-a-rest-api )

проблема

Основная проблема с оптимистичным механизмом управления параллелизмом заключается в том, что вы все время разрешаете всем клиентам выполнять любые операции.

И я хотел бы избежать этого, не нарушая принцип безгражданства REST. Я имею в виду, что все клиенты не могут выполнять какие-либо операции в любое время.

Вопрос

На мой взгляд, это было бы возможно с полуоптимистическом механизм управления параллелизмом, как этот:

  • Клиенты могут запросить токен
  • Может быть создан только один токен с ограниченным сроком действия
  • Для выполнения операций над ресурсами (такими как POST или PUT ) клиент должен предоставить этот токен как часть тела (или заголовка?) Запроса. Клиент, у которого нет токена, не может выполнять эти операции.

Это очень похоже на оптимистичное управление параллелизмом, за исключением того, что только один клиент может выполнять некоторые операции (тот, который получил токен) ... напротив "все клиенты могут выполнять все операции".

Совместим ли этот механизм с архитектурным стилем REST? Это нарушает какие-либо ограничения? Я собирался задать вопрос о SO, но это, скорее, вопрос высокого уровня, связанный с разработкой программного обеспечения.

AilurusFulgens
источник
1
На самом деле это довольно просто: вы должны Transactionявно моделировать ресурс.
Йорг Миттаг
Что это меняет? Не уверен, чтобы понять ваш комментарий. Я не делаю контроль параллелизма для транзакции, а скорее говорю клиенту: «Хорошо, теперь вы абсолютно уверены, что никто не изменит ресурс» (так как он получил уникальный токен).
AilurusFulgens
1
В чем разница? С одной стороны, вы используете Etag для проверки, кому разрешено обновлять «текущую» версию; если это конфликтует, вы должны обновить свою версию и выполнить обновление после этого. С другой стороны, у вас есть механизм блокировки: один разрешен, другие должны ждать. Звучит примерно так же. Недостаток второго подхода: 2 запроса - 1 для блокировки и 1 для обновления. В оптимальном случае у вас есть только одно обновление через Etag-подход.
Томас Джанк
Ну, вообще говоря о контроле за параллелизмом ... второго, который "проиграл гонку", всегда придется ждать (просто по разным причинам, я согласен с этим). Разница с Etag? Поскольку Etagвы никогда не уверены, что ваши операции будут завершены, у вас может возникнуть ситуация, когда вы никогда не будете выполнять никаких операций. С блокировкой вы обязательно по крайней мере выполните свою операцию. Таким образом, наличие простой блокировки - это просто середина между средой, в которой могут возникать «высокие конфликты» и «редкие конфликты».
AilurusFulgens

Ответы:

3

Вы никогда не должны (как никогда когда-либо) блокировать любой ресурс в ожидании взаимодействия с пользователем.

В какой-то момент некоторые из ваших пользователей отправятся на долгие выходные, оставив некоторые важные записи заблокированными.

Ах, но вы не позволите этому случиться, потому что у вас есть разумная схема разрешения тайм-аута / тупика; тогда в какой-то момент это пойдет ужасно неправильно, и пользователь, который получил хорошее сообщение «Ваш виджет был заказан», будет кричать в службу поддержки, требуя знать, почему его виджет не был доставлен.

Большинство людей могут иметь дело с сообщением «извините, другой пользователь только что заказал эту часть».

Джеймс Андерсон
источник
Вы хорошо это объяснили. Хотя я не совсем убежден в вашем первом предложении: в какой-то момент вы гарантируете, что никто, кроме вас, не сможет выполнить заказ. Но хорошо, ваше последнее предложение является хорошим резюме, в 99% случаев это так.
AilurusFulgens
1
Если вам нужно заблокировать запись для конкретного пользователя, сделайте это на уровне приложения. Либо будет простой атрибут «LockedBy», либо с более сложным механизмом управления версиями и рабочим процессом.
Джеймс Андерсон
Что вы подразумеваете под "на уровне приложения"? Если вы добавите атрибут «LockedBy» на свой ресурс, то вы сохраните информацию о клиенте на своем сервере. Или, может быть, я не понял ваш комментарий. Если бы вы могли предоставить некоторые детали, это было бы здорово!
AilurusFulgens
1
@AilurusFulgens - Вы добавляете атрибут LockedBy (и, возможно, метку времени LockedOn) в свою базу данных. В своем коде приложения вы задаете имя пользователя и время, когда клиент запускает взаимодействие обновления. Вы его в исходное состояние, когда клиент закончил - то вам необходимо решить некоторые бизнес - правила для разрешения конфликтов и тайм - ауты и т.д.
Джеймс Андерсон
2

Использование токенов очень распространено в API, эти токены обычно отправляются в виде заголовка и имеют четкий жизненный цикл. Подумайте, например, OAuth.

Независимо от вашего языка программирования или фреймворка, REST API одинаковы.

Я могу вспомнить несколько сценариев, в которых вы хотите ограничить параллелизм, два из них:

  1. Несколько клиентов обновляют одни и те же ресурсы, например строку базы данных. Например: два одновременных запроса, один удаляет запись, а другой пытается обновить ту же запись. В зависимости от вашей базы данных и от того, как вы ее настроили, вы можете получить блокировку записей или неверную операцию, поскольку данные будут другими или не будут существовать.

  2. Суперпользователь или администратор, выполняющий специальные действия с API.


Что делать в этих случаях?

  1. Используйте транзакции в базе данных, синглетоны, блокировки и аналогичные механизмы для синхронизации доступа к ресурсам.

  2. Токен может работать, я думаю, будет лучше, если вы не будете хранить информацию о клиенте, а только о самом токене. На одном шаге вы можете проверить пользователя и назначить токен. Затем просто подтвердите, что токен жив и действителен. Используйте токен, который можно расшифровать, чтобы получить дополнительную информацию. Вы можете хранить, если это специальный токен и разрешать только включение одновременно. Таким образом вы проверяете токен, а не пользователя.

Надеюсь, это поможет.

Пабло Гранадос
источник
Да, я ожидал ответа о сходстве токена и механизма OAuth. Хотя последний посвящен аутентификации. Я не понял смысл вашего сценария 1. Сложнее всего справиться с параллелизмом в REST API - это сохранить ограничение безгражданства ... это означает, что сервер не хранит информацию о клиенте. Ваш сценарий 2 именно то, что я делаю в настоящее время! :)
AilurusFulgens
Я ответил на ваш вопрос?
Пабло Гранадос
Нет простите. Я одобрил ваш ответ, потому что он дает хороший обзор проблемы, но, к сожалению, на самом деле, он не решает ее.
AilurusFulgens
0

Один только REST слишком примитивен, правда. Вы можете начать работу с REST, но в конечном итоге вашему многофункциональному приложению понадобятся запросы с объединениями и обновления с транзакциями. Каждый разработчик, пытающийся добавить эти вещи самостоятельно, будет подвержен ошибкам и непоследователен. К счастью, есть новый стандарт под названием OData, который делает именно это. Он размещается поверх REST и предоставляет (1) язык запросов, который допускает простые объединения с использованием навигационных свойств (без необходимости выставлять внешние ключи), и (2) пакетную обработку, которая включает в себя наборы атомарных изменений.

Смотрите здесь для (1) https://stackoverflow.com/a/3921423/471129 , и,

Смотрите здесь и для (2) https://stackoverflow.com/a/21939972/471129

Эрик Эйдт
источник