Оптимистическое кэширование Concurrency Шаблон проектирования
У меня есть веб-служба, работающая на кластере серверов. Этот веб-сервис выполняет некоторую внутреннюю обработку, а затем может обратиться к внешней службе, которая несет плату.
Я хочу добавить некоторое кэширование, чтобы, если я получаю одинаковые запросы к службе (что гарантировано), то мне не нужно повторять обработку, сохраняя время и мощность обработки, а также затраты, понесенные в внешняя часть служебного вызова.
Однако я изо всех сил пытаюсь понять, как управлять этим кэшированием, когда у меня есть следующие ограничения
- Служба работает на нескольких веб-серверах для обеспечения высокой доступности и масштабируемости.
- Запрос может занять до 5 секунд для ответа, но в среднем я мог получить 2 или 3 других одинаковых запроса.
Как я могу приостановить выполнение других вызовов службы до тех пор, пока первая не ответит (поэтому доступная в кеше) при работе в распределенной среде.
Я подумал о том, чтобы ввести шаблон прокси-сервера и создать очередь идентичных запросов в прокси-сервере, так что, когда первый возвращает, он также может вернуть тот же ответ другим. Это правильный шаблон или есть лучший шаблон concurrency, который имеет дело с этим сценарием?
Ответы
Ответ 1
Вы могли
- вычислить криптографический хэш запроса
- посмотрите, есть ли результат в базе данных для этого хэша, и если да, верните его
- сохранить хэш в базе данных с состоянием "ожидающий результат"
- вызовите веб-службу и обновите строку в базе данных с результатом.
На шаге 2, если хэш уже находится в базе данных, с состоянием "ожидающий результат", вы можете опросить базу данных каждые X миллисекунд и, наконец, вернуть результат после ее появления.
Дьявол в деталях, конечно, потому что вам нужно будет решить, что вы делаете в случае возникновения ошибки:
- Вы возвращаете ошибку для всех последующих идентичных запросов?
- Вы вызываете ожидание потоков для повторения вызова веб-службы?
- Вы возвращаете ошибку, но только на некоторое время, а затем повторите попытку?
Ответ 2
1.) Служба работает на нескольких веб-серверах для высокой доступности и масштабируемость
Рассматривайте это просто как конструктивное ограничение. Это означает, что вы не включаете имя хоста в свой метод поиска кэша. Пока результат не зависит от хоста, у вас не должно возникнуть проблемы. Я считаю, что это ошибка дизайна, если hostA возвращает что-то отличное от hostB в среде HA с той же службой и теми же параметрами.
Если вы хотите сохранить резервную систему, у вас не должно быть центрального кэша. Потому что в большинстве случаев "центральное" решение является синонимом решения "Единственная точка отказа". Блокировка также сложнее, если вы синхронизируете серверы приложений.
Сколько кэшей вы вводите, немного зависит от скорости попадания в кеш и ресурсов, доступных в ваших системах. Наиболее простым решением является кэширование на уровне каждого экземпляра службы.
2.) Запрос может занять до 5 секунд для ответа, но в среднем время, Возможно, я получил 2 или 3 других одинаковых запроса.
Это также конструктивное ограничение. Вы разделяете свое кэширование просто двумя разными шагами.
- Сначала вставьте ключ для вашего идентичного запроса, если первый поток входит в процедуру кэширования и блокирует доступ к его значению.
- Вставьте значение после завершения обработки и освободите блокировку
Вам также нужно обрабатывать обработку исключений.
Механизм locking
и connection
может быть реализован с использованием разных стратегий
- Синхронный - вы просто создаете Mutex/Семафор или что-то еще и блокируете доступ к критическому разделу. Которые могут в конечном итоге иметь некоторые запросы в состоянии ожидания до тех пор, пока блокировка не исчезнет.
- Асинхронный - вы реализуете какой-то механизм опроса, который приведет к сообщению о том, что данные не готовы, если поток отвечает заблокированному критическому разделу (как в синхронной обработке). Это не приведет к большому количеству открытых подключений, но приведет к большей сложности.
Mutex/Семафор или любая другая структура, которую вы используете для блокировки доступа к критическому разделу , может зависеть от уникального ключа (если вы не хотите сериализовать доступ к вашей службе), вы рассчитали идентичный запрос.