Множественные процессы ненавидят это!

Когда вы не имеете дело с несколькими процессами, указывающими одни и те же данные, все в порядке. PHP сам по себе является однопоточным процессом и избавляет от многих проблем, связанных с параллелизмом. Вот почему использование Laravel Cache для хранения данных является разумным, особенно во избежание вещей, требующих немного слишком много, таких как сложный запрос SQL или медленный запрос HTTP-сервера.

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

Обычно это создает большую проблему.

Боб и Ана не очень хорошо поправляются

Простой пример гонки за данные - два пользователя редактируют статью. Представьте, что Боб получает черновик, который он оставил писать в 10:00, начинает его обновлять в 10:05, а затем сохраняет готовую статью в 11:00.

Ана, его редактор с другой стороны, получила свою статью в 10:30. Внеся некоторые небольшие исправления, она сохраняет его в 10:45, ожидая, что Боб заберет то, что она написала.

Что Боб сделал в 11:00, так это перезаписал исправления, которые сделала Ана, даже не подозревая об этом. Статья публикуется, и Ана кричит на Боба за игнорирование ее исправлений и комментариев.

Хотя в приложениях это происходит за секунды, есть простое решение.

Сделать недействительным и восстановить

Чтобы избежать замены более новых данных более старыми, нам нужно знать, являются ли данные в кэше «свежими», чем те, которые мы храним сейчас. Другими словами, нам нужно использовать метку времени.

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

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

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

С помощью этих двух битов информации мы теперь можем «регенерировать» данные, когда то, что мы храним, свежее, чем данные, хранящиеся в кеше:

Мы можем перевести приведенный выше код в два условия:

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

Это можно экстраполировать не только на базу данных, но и на все, куда вы можете поместить как данные, так и временные метки.

Если мы хотим пройти лишнюю милю, мы можем создать класс, который сделает это за нас.

Вышеупомянутый класс очень прост в использовании. Давайте исправим проблему Боба и Аны:

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

Вы можете найти эту черту и другие помощники в моем пакете Laratraits. Дайте ему шанс, если вы найдете что-то полезное для использования в своем проекте.