03 lipca 2019

Varnish i Magento 2, czyli jak to wszystko się zaczęło?

Pewnego pamiętnego dnia zobaczyłem na swojej liście nowe zadanie, którym było dodanie prostej funkcjonalności dla niezalogowanych użytkowników. Miały być wyświetlane różne zawartości stron na podstawie wartości zapisanej w sesji. Wyglądało na proste zadanie, a jednak okazało się ciekawym wyzwaniem. 

Podczas wejścia na na nową stronę, wszystko działa poprawnie, lecz zmiana wartości w sesji nie przynosiła oczekiwanych rezultatów, widoczna była  stara zawartość strony. W głowie pojawia się myśl Varnish, ale co dalej?

 

Zacznijmy od początku czym jest Varnish?

Varnish Cache jest to darmowy HTTP accelerator oraz odwrotne proxy. Inaczej mówiąc zwraca zmagazynowane strony, które zostały już odwiedzone podczas korzystania z serwisu, dzięki czemu zmniejszamy obciążenie serwera, przed ponownym generowaniem tej samej zawartości.

W większości przypadków Varnish jest niewidoczny podczas jego działania, znajduje się on między użytkownikiem, a web serwerem, a jego zadaniem jest przyspieszenie działania strony. Dokumentacja mówi o przyspieszeniu rzędu od 300 do 1000 razy.

Źródło: https://image.slidesharecdn.com/introtovarnish-6-26-2012-120627120429-phpapp01/95/introduction-to-caching-with-varnish-8-728.jpg?cb=1340799005

Instalacja i konfiguracja

Na temat instalacji i konfiguracji Varnisha można znaleźć więcej informacji w tym źródle.

Jak sprawdzić czy Varnish działa?

W trybie developerskim do nagłówka dodawane jest “X-­Magento-­Cache-­Debug:” Mogą się tam znaleźć wartości HIT lub MISS.

“HIT” oznacza że zawartość znajduje się w cache i to właśnie ona jest zwrócona.

“MISS” z kolei oznacza, że zawartość zwrócona jest z web serwera.

 

Jak jest tworzony cache

Każdy obiekt przechowywany przez Varnisha ma swój identyfikator czyli hash. Domyślnie jest on tworzony na podstawie adresu url. Możemy to rozszerzyć o dodatkowe parametry.

Przyjrzyjmy się bliżej jak wygląda procedura hash z domyślnego pliku konfiguracyjnego, jaki jest generowany przez Magento 2.

 

sub vcl_hash {

    if (req.http.cookie ~ „X-Magento-Vary=”) {

        hash_data(regsub(req.http.cookie, „^.*?X-Magento-Vary=([^;]+);*.*$”, „1”));

    

    # For multi site configurations to not cache each other’s content

    if (req.http.host) {

        hash_data(req.http.host);

    } else {

        hash_data(server.ip);

   

    # To make sure http users don’t see ssl warning

    if (req.http.X-Forwarded-Proto) {

        hash_data(req.http.X-Forwarded-Proto);

}

 

Nas interesuje linia ze sprawdzeniem czy znajduje się ciastko „X-Magento-Vary=”, a funkcja hash_data dodaje wartość z ciasteczka do hash. Dzięki czemu możemy posiadać wiele wersji tej samej strony, takich jak wersja dla zalogowanych użytkowników z niemieckim adresem i zmienioną domyślna walutą.
 

“X-Magento-Vary=” czyli HTTP Context

Niektórzy z was mogli już zacząć szukać tego ciasteczka i jest duża szansa że nic takiego nie znaleźli. Zacznijmy od tego, że za generowanie wartości odpowiada klasa “MagentoFrameworkAppHttpContext”. Wartości domyślne które są do niej dodawane to:

-store

-currency 

-customer group

-customer logged in

-tax

Dodatkowo, jeżeli jest włączone zapamiętywanie paginacji dla katalogu, będą tam jeszcze parametry takie jak:

-product list order

-product list dir

-product list mode

-product list limit

Serializacja danych odbywa się przy pomocy funkcji MagentoFrameworkAppHttpContext::getVaryString. Podczas tego są pobierane wszystkie wartości, które nie są puste oraz są różne od wartości domyślnej. Zatem w przypadku, gdy nowy użytkownik wejdzie na stronę główną. Wszystkie jego wartości będą wartościami domyślnymi. Identyfikator będzie pusty, więc ciastko “X-Magento-Vary=” nie zostanie utworzone.

Jeżeli użytkownik się zaloguje, ciastko już zostanie utworzone. Na podstawie tego Varnish będzie przechowywał nowe wersje stron.

Wiemy już jak wygląda działanie Http contextu, teraz zajmijmy się naszym początkowym problemem czyli niewyświetlaniem naszej nowej zawartości.

Poniżej znajduje się prosty przykład jak wygląda dodawanie nowej wartości do HTTP Contextu:

 

etc/di.xml

<?xml version=”1.0″?>

<config xmlns_xsi=”http://www.w3.org/2001/XMLSchema-instance” xsi_noNamespaceSchemaLocation=”urn:magento:framework:ObjectManager/etc/config.xsd”>

    <type name=”MagentoFrameworkAppHttpContext”>

        <plugin name=”size_attribute_page_cache” type=”CompanyModuleNamePluginAttributeHttpContext” />

    </type>

</config>

Plugin/AttributeHttpContext.php

<?php

namespace CompanyModuleNamePlugin;

use MagentoFrameworkAppHttpContext;

/**

 * Class AttributeHttpContext

 */

class AttributeHttpContext

{

    /**

     * @param Context $subject

     * @return array

     */

    function beforeGetVaryString(Context $subject)

        $subject->setValue(’test_attribute’, ‘value’, ‘default’);

        return [];

}

 

Przykładowy kod zawsze dodaje nasz testowy atrybut z wartością ‘default’. Wystarczy teraz tylko podmienić przekazywane wartości na wybrane przez nas wartości.

 

$attribute = $model->getAttribute();

$attributeDefault = Model::ATTRIBUTE_DEFAULT_VALUE;

$subject->setValue(’test_attribute’, $attribute, $attributeDefault);

 

Dodając nowe wartości do Contextu należy pamiętać że nie powinno się używać wartości prywatnych, np. ID użytkownika.

Autor: Tomasz Błażej

 

Przydatne linki

https://varnish-cache.org/intro/
https://devdocs.magento.com/guides/v2.3/config-guide/varnish/config-varnish-install.html
https://devdocs.magento.com/guides/v2.3/config-guide/varnish/config-varnish.html