Я пытаюсь использовать Redis в качестве кеша, который находится перед базой данных SQL. На высоком уровне я хочу реализовать эти операции:
- Прочитайте значение из Redis, если его там нет, сгенерируйте значение с помощью запроса SQL и вставьте его в Redis, чтобы нам не пришлось вычислять его снова.
- Запишите значение в Redis, потому что мы только что внесли некоторые изменения в нашу базу данных SQL и знаем, что, возможно, мы уже кэшировали их, и теперь они недействительны.
- Удалите значение, потому что мы знаем, что значение в Redis устарело, мы подозреваем, что оно никому не понадобится, но сейчас слишком много работы, чтобы пересчитывать его. Мы можем позволить следующему клиенту, который выполнит операцию № 1, вычислить ее снова.
Моя задача — понять, как реализовать № 1 и № 3, если я попытаюсь сделать это с помощью StackExchange.Redis. Если я наивно реализую # 1 с простым чтением ключа и отправкой, вполне возможно, что между тем, как я вычисляю значение из SQL и вставляю его, может произойти любое количество других операций SQL, а также попытаться отправить свои значения в Redis. через №2 или №3. Например, рассмотрим такой порядок:
- Клиент №1 хочет выполнить операцию №1 [Чтение] сверху. Пытается прочитать ключ, видит, что его нет.
- Клиент №1 обращается к базе данных SQL для генерации значения.
- Клиент №2 что-то делает с SQL, а затем выполняет операцию №2 [Запись] выше. Он помещает некоторое новое вычисленное значение в Redis.
- Клиент № 3 приходит долго, выполняет какую-то другую операцию в SQL и хочет выполнить операцию № 3 [Удалить] в Redis, зная, что если там что-то закешировано, это больше недействительно.
- Клиент №1 отправляет свое (теперь устаревшее) значение в Redis.
Итак, как мне реализовать операцию №1? Redis предлагает примитив WATCH
, который позволяет довольно легко сделать это на голом железе, где я мог бы наблюдать другие вещи, происходящие с ключом от клиента № 1, но это не поддерживается StackExchange.Redis из-за того, как он мультиплексирует команды. Условных операций здесь недостаточно, поскольку, если я попытаюсь сказать «нажимать, только если ключ не существует», это не предотвратит гонку, как я объяснил выше. Есть ли шаблон/лучшая практика, которая используется здесь? Это кажется довольно распространенным шаблоном, который люди хотели бы реализовать.
Одна идея, которая у меня есть, заключается в том, что я могу использовать отдельный ключ, который увеличивается каждый раз, когда я выполняю какую-либо операцию с основным ключом, а затем могу использовать таким образом условные операции StackExchange.Redis, но это кажется неуклюжим.