Реализация кэширования Образцового уровня

Я добавлял некоторые комментарии в связанном вопросе о кэшировании MVC, и подошли некоторые вопросы о фактической реализации. Как каждый реализует кэш Образцового уровня, который работает прозрачно без разработчика, бывшего должного вручную кэшироваться, и все же остается эффективным?

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

(Источник: сообщение Jarrod)

Причина я скептически настроен, состоит в том, потому что кэширование не должно обычно делаться, если нет реальная потребность и не должна быть сделана для вещей как результаты поиска. Таким образом, так или иначе сама Модель должна знать, достойно ли заявление SELECT, сделанное к ней, того, чтобы быть кэшируемым. Разве Модель не должна была бы быть астрономически умной, и/или статистика хранилища того, что чаще всего запрашивается за длительный промежуток времени для точного принятия решения? И не был бы издержки всего этого делать кэширование бесполезным так или иначе?

Как Вы однозначно определили бы запрос от другого запроса (или более точно, набор результатов от другого набора результатов)? Что относительно того, если Вы используете подготовленные операторы только с параметрами, изменяющимися согласно вводу данных пользователем?

В другом плакате было сказано это:

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

Стоит крохотный шанс коллизии волнения о?

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


Обновление для щедрости

Я действительно использую чрезвычайно легкое несколько подобное ORM ActiveRecord, но способен к выполнению сложных соединений и подзапросов без n^2 проблема. Я создал его сам, таким образом, это гибко и не строго с точки зрения отношений или имен столбцов, и я просто хочу понять, как я должен реализовать механизм кэширования.

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

Как я знаю, когда это должно делаться недействительным? Я должен был бы проанализировать ОБНОВЛЯТЬ/УДАЛЯТЬ/ЗАПРОСЫ НА ВСТАВКУ и sub в параметрах вручную для обнаружения, какие записи изменяются? Или хуже, сделайте дополнительные запросы каждый раз, когда данные изменяются для отслеживания, которых изменились вещи и что должно делаться недействительным?

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

13
задан Community 23 May 2017 в 11:47
поделиться

7 ответов

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

Кэширование - это ответственность модели.

Как бы вы могли однозначно идентифицировать запрос из другого запроса (или, точнее, набор результатов из другого набора результатов)? Что насчет того, если вы используете подготовленные операторы с изменением только параметров в соответствии с вводом пользователя?

Но входные данные модели однозначно определяют ее выход.

Если вы используете одну и ту же модель для извлечения содержимого корзины для покупок и выполнения поиска по каталогу продуктов, то с вашим кодом что-то не так.

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

Тот факт, что вы используете тривиальную ORM из коробки, не исключает вас от использования ее в собственном коде.

Разве Модель не должна быть астрономически умной и / или хранить статистику

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

Как правило, вы должны быть в состоянии предсказать соответствующие значения TTL на основе запроса SELECT до привязки каких-либо переменных, и это необходимо реализовать во время разработки, но, очевидно, результаты должны быть проиндексированы. на основе запроса после привязки.

Должен ли я реализовывать кеширование индивидуально в классах модели, которые этого требуют, или оно должно быть частью уровня ORM?

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

С.

5
ответ дан 1 December 2019 в 23:31
поделиться

Что мы сделали, так это построили слой кэша в качестве замены функции загрузки MVC. Таким образом, будут кэшироваться только те вызовы реальной модели, которые нам нужны. Если кеширование не требуется или нежелательно, используется обычный способ вызова модели из контроллера.

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

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

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

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

2
ответ дан 1 December 2019 в 23:31
поделиться

Я настроен скептически, потому что кеширование обычно не должно выполняться если в этом нет реальной необходимости, и не следует делать для таких вещей, как результаты поиска. Так почему-то Модель сам должен знать, действительно ли Выдаваемый оператор SELECT достойны кеширования. Разве не Модель должна быть астрономически умной, и / или хранить статистику того, что чаще всего запрашиваются в течение долгого период времени, чтобы точно принимать решение? И разве накладные расходы на все это делают кеширование в любом случае бесполезны?

Кто еще лучше подходит для отслеживания всего этого? Несколько контроллеров будут использовать одну и ту же модель для получения необходимых данных. Так как же контроллер сможет принять рациональное решение?

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

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

Трудно дать более конкретный совет без контекста, но вот несколько сценариев:

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

2) У вас есть сложная формула, которая использует несколько входных данных и создает рейтинг популярности для какого-то вида «продуктов». Некоторые виджеты в макете страницы показывают 5 самых популярных объектов в сводной форме. Ваша модель продукта будет предоставлять метод getPopular (), который будет полагаться на кеш. Модель может аннулировать кеш каждые X минут, или какой-то фоновый процесс может запускаться через регулярные промежутки времени, чтобы сделать недействительным / перестроить. Независимо от того, какой части системы нужны популярные продукты, они запрашивают их через модель, которая прозрачно управляет кешем.

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

Предостережение заключается в том, что если вы злоупотребляете ActiveRecord и / или составляете SQL-запросы (или их эквиваленты) в своих контроллерах, у вас, вероятно, возникнут проблемы. Интеллектуальное кэширование намного проще, если у вас есть хороший, богатый, модельный слой, который точно моделирует ваш домен, а не хлипкие модели, которые просто обертывают таблицы базы данных.

Дело не в умных моделях, а в умении разработчика .

2
ответ дан 1 December 2019 в 23:31
поделиться

При кэшировании следует учитывать множество факторов, таких как хеширование, аннулирование и т. Д. Но цель кеширования всегда одна и та же: сократить время отклика и потребление ресурсов.

Вот пара быстрых мыслей о системах, которые не используют ORM:

  • Никогда не помешает кэшировать что-либо с помощью memcache, если у вас есть для этого память
  • Вы должны всегда кэшировать только запросы SELECT , поскольку другие типы влияют на данные
  • Все кэшированные запросы должны быть параметризованы
  • Ключ кеша должен быть md5 запроса, соединенного с serialize () 'd версия параметров (это идентифицирует уникальные запросы. Серализация параметров не является проблемой, потому что размер параметров, обычно передаваемых для выборочных запросов, обычно довольно тривиален). Сериализация не так дорого, как вы думаете. И поскольку вы хэшировали свой статический запрос, объединенный с вашими динамическими параметрами, вам никогда не придется беспокоиться о коллизиях.
  • Модификации ( INSERT / UPDATE / DELETE ) строк в модели должны сделать недействительными (или установить TTL) для всех элементов, кэшированных для этой модели
  • Модель должна быть расширена, чтобы можно было отправлять значения TTL кеша вместе с запросом
  • Ваша модель должна поддерживать пропуск кеширования (возможно, путем передачи TTL 0 вместе с запросом)
  • Даже если базовый запрос может быть кэширован, обычно более эффективно применять операции типа ORDER BY / LIMIT в новом (измененном) запросе, чем извлекать весь набор строк из кеша и манипулировать им через PHP, чтобы добиться того же (если только между вашим веб-сервером и сервером базы данных не очень большая задержка).

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

ОБНОВЛЕНИЕ:

Если вы обнаружите, что используете несколько экземпляров одного и того же класса модели в одном потоке, я бы предложил также потенциально кэшировать вашу созданную модель в memcaching (в зависимости от вашего конструктора десериализация и пробуждение объекта иногда более эффективны, чем строительство объекта). Если у вас есть инициализированный объект (сконструированный или десериализованный), он на миров более эффективен , чтобы clone () базовый экземпляр объекта и установить его новое состояние, а не восстанавливать его объект в PHP.

6
ответ дан 1 December 2019 в 23:31
поделиться

У вас должна быть отдельная модель, которая напрямую взаимодействует с SQL, например. для таблицы «Клиенты»: $ CustomerModel-> GetCustomers (параметр $); и так далее. Затем в этих моделях вы можете прозрачно реализовать кеширование без необходимости редактировать какие-либо существующие MVC.

0
ответ дан 1 December 2019 в 23:31
поделиться

На самом деле это не ответ, но ваш вопрос напомнил мне, что я видел эту главу , в которой, я думаю, описывается, как делать то, что вы хотите, используя Doctrine ORM с Symfony. Возможно, вы захотите сравнить с этим подходом / реализацией.

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

1
ответ дан 1 December 2019 в 23:31
поделиться

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

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

У вас был бы класс, который контролировал бы все это. Функции могут включать такие вещи, как

- запуск проверки кеша
-установленный порог
-кэшировать всегда
-cache время жизни
-принудительно очистить весь кеш
-очистить этот кеш для этого запроса
-Мы были смертельно поражены смертельным лазером, и нам нужно все поймать (Ненавижу тебя wordpress Я никогда не использую тебя снова функция, я не должен был быть таким ленивым и сделал свой собственный веб-сайт функцией)

Это поможет чтобы автоматизировать большую часть вашего процесса.Также правила кеширования могут быть реализованы для каждой модели или для всего приложения в целом.

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

1
ответ дан 1 December 2019 в 23:31
поделиться
Другие вопросы по тегам:

Похожие вопросы: