Magento Enterprise Що таке Full Page Cache і чому він потрібен, ASTRIO

Magento Enterprise: Що таке Full Page Cache і чому він потрібний.

Для тих, хто знайомий з Magento, не секрет, що цей e-commerce двигун досить вимогливий до заліза. Але розробники цього інтернет-магазину спробували вирішити цю проблему і придумали багато різноманітних "прискорювань", без яких, мабуть, запускати магазин на движку Magento в продакшн не варто. Надто довго Magento буде віддавати кінцевому користувачеві сторінку. Серед таких "прискорювань" кеші, індекси, компіляція, об'єднання JS/CSS в один стислий файл та ін.

Однією з основних "фішок" Magento Enterprise є Full Page Cache (далі FPC). Цю "фішку" реалізує модуль Enterprise_PageCache, що входить до складу пакету Magento Enterprise.

У статті розглядається найсвіжіша на момент написання статті версія Magento Enterprise: 1.13.1.

FPC дозволяє віддавати серверу сторінку за лічені мілісекунди практично не навантажуючи сервер. Я провів виміри часу віддачі сторінки продукту сервером (в одному з проектів, над яким працював), ось результати:

magento

  • 65 ms при включеному FPC (коли всі блоки були закешовані);
  • 1250 ms при вимкненому FPC (при цьому всі інші види кешу включені);
  • 2500 ms при відключеному кеші всіх видів.

Чому різниця настільки велика? Давайте розберемося.

Що і коли кешує FPC.

У секції frontend/cache/requests тут вказується frontName контролера модуля (його значення зберігається в конфізі модуля шляхом: frontend/routers/route_name/args/frontName), потім контролер і екшен (контролер і екшен - необов'язкові параметри). А значення, що передається - процесор реквеста (запиту).

Ви можете точнотак само змусити кешувати контролери/контролер/екшен вашого модуля, достатньо додати в потрібну секцію дані аналогічно до того, як це робить модуль Enterprise_PageCache. Приклад:

При цьому є низка умов, за яких FPC не кешує сторінки. Не кешуються, наприклад, HTTPS сторінки, сторінки з GET-параметром no_cache. Методи можутьпереглянути ізастосовуються класу Enterprise_PageCache_Model_Processor:

Як працює FPC?

Якщо сторінка кешується FPC-кешем, FPC відключає стандартний кеш блоків. метод processPreDispatch класу Enterprise_PageCache_Model_Observer, який спрацьовує, коли виникає подія (event) controller_action_predispatch:

FPC використовує плейсхолдери. Вони в Magento додаються за допомогою конфігураційного файлу cache.xml в папці etc модуля. А плейсхолдер обробляється контейнером плейсхолдеру. Контейнер - це клас, який оброблятиме плейсхолдер під час рендерингу FPC (процес рендерингу блоку FPC-кешем відрізняється від звичайного рендерингу блоку). Приклад файлу cache.xml:

Коротко про конфігурацію плейсхолдера:

  • block - тип або клас блоку
  • placeholder - назва плейсхолдера
  • container - тип або клас контейнера плейсхолдера
  • cache_lifetime - час життя кешу

Під час рендерингу при включеному FPC вміст кожного блоку обертається плейсхолдером та кешується: коли спрацьовує подію core_block_abstract_to_html_after, виконується метод renderBlockPlaceholder класу Enterprise_PageCache_Model_Observer:

Тут $placeholder виходить за допомогою класу Enterprise_PageCache_Model_Config методом getBlockPlaceholder:

Конструктор класу Enterprise_PageCache_Model_Container_Placeholder:

У майбутньому вкласі контейнера можна буде отримати атрибути блоку методом getAttribute:

Методи для обгортки плейсхолдером контенту блоку:

Приклад обгортки плейсхолдером контенту блоку:

Перед тим, як надсилати відповідь на запит, спрацьовує подію controller_front_send_response_before і виконується метод cacheResponse класу Enterprise_PageCache_Model_Observer, який зберігає сторінку в кеш, якщо це необхідно. Код методу cacheResponse:

Тут метод processRequestResponse зберігає всю сторінку та потрібні дані в кеш, якщо це потрібно:

Тут дуже важливий момент полягає в тому, що перед збереженням у кеш сторінки вміст блоків із плейсхолдером замінюється на опис блоків: $content = $processor->prepareContent($response); . Метод preparateContent:

У результаті в кеші сторінки буде міститься інформація про блок замість вмісту блоку. Ця інформація допоможе відрендерити блок у майбутньому. Ось приклад такої інформації, яку FPC замінятиме на вміст блоку під час свого рендерингу:

Під час наступного завантаження цієї сторінки Magento завантажить цю сторінку з кеша (див. метод extractContent класу Enterprise_PageCache_Model_Processor). Якщо в кеші порожньо - традиційний рендеринг з ініціалізацією Magento (начебто FPC і не було) з подальшим збереженням в кеш сторінки. Якщо ж сторінка є в кеші, то FPC оброблятиме контент із цього кешу.

Методи _processContent та _processContainers класу Enterprise_PageCache_Model_Processor:

Як видно з коду цих методів, обробляються лише блоки, які мають плейсхолдери. Якщо для вашого блоку немає плейсхолдера, його вміст не змінюватиметься. Тому, якщо ви хочете виводити блоки, що динамічно змінюються, то для них необхідно створюватиплейсхолдери.

Контейнери плейсхолдерів спочатку обробляються методом applyWithoutApp. Цей метод намагається замінити вміст блоку в сторінці, що закешує, на потрібний нам вміст. Приклад методу applyWithoutApp, абстрактного для всіх контейнерів класу Enterprise_PageCache_Model_Container_Abstract:

З коду зрозуміло, що якщо ви хочете змінювати блок динамічно, вам необхідно визначити метод _getCacheId контейнера виходячи з логіки вашого блоку. Якщо хоча б один контейнер не був оброблений (applyWithoutApp повернув false), його потрібно рендерувати (див. метод _processContent класу Enterprise_PageCache_Model_Processor), а при цьому відбудеться ініціалізація Magento (виконається Mage::app() ). У цьому запит обробляється контролером Enterprise_PageCache_RequestController екшеном process. Код екшену process:

Для кожного необробленого контейнера запускається метод applyInApp, який має відрендерити блок та замінити вміст плейсхолдера у контенті. Код методу applyInApp, абстрактного для контейнерів класу Enterprise_PageCache_Model_Container_Abstract:

Тут, як бачимо, вміст виходить методом _renderBlock класу контейнера. Цей метод зазвичай унікальний для кожного контейнера і містить якусь особливу логіку. В абстрактному класі Enterprise_PageCache_Model_Container_Abstract для контейнерів цей метод повертає false. Саме він повинен повертати HTML вміст блоку.

При цьому існує проблема при рендеринг контейнерів. Для блоку контейнера батько міг не відрендеритися, та й контролер виконується інший. Це означає, що якихось даних усередині блоку може бути і треба передбачати цей випадок (наприклад, ви отримуєте продукт у такий спосіб: $product = Mage::registry('current_product') , абозадає блоком батька якусь властивість: $this->getChild('block_alias')->setProduct($_product)) .

Але, як пам'ятаємо, FPC зберігає всю інформацію, необхідну рендерингу. Тому, якщо ви передали інформацію у методі getCacheKeyInfo вашого блоку для збереження, ви зможете задати її під час FPC-рендерингу. Робити це потрібно у методі _renderBlock контейнера. Отримати в ньому екземпляр блоку можна методом _getPlaceHolderBlock:

Як видно, ми отримуємо екземпляр класу блоку із встановленим шаблоном. Приклад методу _renderBlock:

Тут, як видно з коду, ми передали блоку параметри handles та popup_ids. У самому блоці їх необхідно отримувати так:

Кеш дійсно ефективний і чудово працює, знижуючи навантаження на сервер та забезпечуючи швидку роботу електронного магазину з високою відвідуваністю.

У моїй наступній статті FPC я опишу, як задавати свої власні динамічні блоки в Magento Enterprise для коректної роботи додаткового динамічного функціоналу з включеним FPC.