Оптимистическое кэширование Concurrency Шаблон проектирования

У меня есть веб-служба, работающая на кластере серверов. Этот веб-сервис выполняет некоторую внутреннюю обработку, а затем может обратиться к внешней службе, которая несет плату.

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

Однако я изо всех сил пытаюсь понять, как управлять этим кэшированием, когда у меня есть следующие ограничения

  • Служба работает на нескольких веб-серверах для обеспечения высокой доступности и масштабируемости.
  • Запрос может занять до 5 секунд для ответа, но в среднем я мог получить 2 или 3 других одинаковых запроса.

Как я могу приостановить выполнение других вызовов службы до тех пор, пока первая не ответит (поэтому доступная в кеше) при работе в распределенной среде.

Я подумал о том, чтобы ввести шаблон прокси-сервера и создать очередь идентичных запросов в прокси-сервере, так что, когда первый возвращает, он также может вернуть тот же ответ другим. Это правильный шаблон или есть лучший шаблон concurrency, который имеет дело с этим сценарием?

Ответ 1

Вы могли

  • вычислить криптографический хэш запроса
  • посмотрите, есть ли результат в базе данных для этого хэша, и если да, верните его
  • сохранить хэш в базе данных с состоянием "ожидающий результат"
  • вызовите веб-службу и обновите строку в базе данных с результатом.

На шаге 2, если хэш уже находится в базе данных, с состоянием "ожидающий результат", вы можете опросить базу данных каждые X миллисекунд и, наконец, вернуть результат после ее появления.

Дьявол в деталях, конечно, потому что вам нужно будет решить, что вы делаете в случае возникновения ошибки:

  • Вы возвращаете ошибку для всех последующих идентичных запросов?
  • Вы вызываете ожидание потоков для повторения вызова веб-службы?
  • Вы возвращаете ошибку, но только на некоторое время, а затем повторите попытку?

Ответ 2

1.) Служба работает на нескольких веб-серверах для высокой доступности и масштабируемость

Рассматривайте это просто как конструктивное ограничение. Это означает, что вы не включаете имя хоста в свой метод поиска кэша. Пока результат не зависит от хоста, у вас не должно возникнуть проблемы. Я считаю, что это ошибка дизайна, если hostA возвращает что-то отличное от hostB в среде HA с той же службой и теми же параметрами.

Если вы хотите сохранить резервную систему, у вас не должно быть центрального кэша. Потому что в большинстве случаев "центральное" решение является синонимом решения "Единственная точка отказа". Блокировка также сложнее, если вы синхронизируете серверы приложений.

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

2.) Запрос может занять до 5 секунд для ответа, но в среднем время, Возможно, я получил 2 или 3 других одинаковых запроса.

Это также конструктивное ограничение. Вы разделяете свое кэширование просто двумя разными шагами.

  • Сначала вставьте ключ для вашего идентичного запроса, если первый поток входит в процедуру кэширования и блокирует доступ к его значению.
  • Вставьте значение после завершения обработки и освободите блокировку

Вам также нужно обрабатывать обработку исключений.

Механизм locking и connection может быть реализован с использованием разных стратегий

  • Синхронный - вы просто создаете Mutex/Семафор или что-то еще и блокируете доступ к критическому разделу. Которые могут в конечном итоге иметь некоторые запросы в состоянии ожидания до тех пор, пока блокировка не исчезнет.
  • Асинхронный - вы реализуете какой-то механизм опроса, который приведет к сообщению о том, что данные не готовы, если поток отвечает заблокированному критическому разделу (как в синхронной обработке). Это не приведет к большому количеству открытых подключений, но приведет к большей сложности.

Mutex/Семафор или любая другая структура, которую вы используете для блокировки доступа к критическому разделу , может зависеть от уникального ключа (если вы не хотите сериализовать доступ к вашей службе), вы рассчитали идентичный запрос.