Подтвердить что ты не робот

Как структурировать приложение Symfony2 с ESI?

В новом проекте с большим количеством трафика мы думаем о том, как структурировать наше приложение Symfony2, чтобы использовать кеши и быть готовым к более агрессивному в будущем. Я хотел бы узнать ваше мнение.

Скажем, пользователь запрашивает страницу со списком мест. На этой странице:

- list
   - common data (title, author, description)
   - user data (the user likes the list + other data)
- first 20 places
   - common data (title, photo of each place)
   - user data (the rates of the user for those places)

HTML может выглядеть как:

<html>...
<body>
  <header>
  ...
  <!-- Embed the top user menu -->
  <esi:include src="http://example.com/profile/menu" />
  ...
  </header>

  <content>
  ...
  common data of the list
  ...
  <!-- Embed the common data of the first 20 places, the same for everyone -->
  <esi:include src="http://example.com/lists/17/places" />
  ...
  <!-- Embed the user data of the list (used in JS) -->
  <esi:include src="http://example.com/lists/17/user" />
  ...
  <!-- Embed the user data of the list of places (used in JS) -->
  <esi:include src="http://example.com/lists/17/places/user" />
  ...
  </content>
</body>       
</html>

HTML будет кэшироваться на шлюзе (Symfony или Varnish). Список мест будет кэшироваться большую часть времени на шлюзе. Запросы пользовательских данных будут теми, которые вызываются и не кэшируются (по крайней мере не изначально).

Вопросы

  • Как вы относитесь к этой структуре?
  • Если пользователь анонимен, могу ли я избежать использования esi-include для пользовательских данных? Также, если у меня есть cookie для пользователя anon? Как?
  • Имеет ли смысл esi-include для пользовательского меню?
  • Или мы должны забыть об ESI и всегда идти через контроллер (например, кэширование визуализированного представления общих данных)?
  • Должны ли мы переместить 2 ESI-запроса, которые запрашивают данные пользователя, как AJAX-вызовы, а не ждать на сервере?
  • Это хороший подход к масштабированию, если нам нужно сделать это быстро? Что было бы лучше?

Большое спасибо!

4b9b3361

Ответ 1

Мы использовали Varnish на одном сайте для кэширования всей страницы, и я использую Symfony2 в течение нескольких лет, но имейте в виду, что я не использовал Varnish + Symfony2 + ESI в любой производственной среде.

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

    Жесткая часть делает эти запросы ESI кэшированными, если пользователь вошел в систему. Как я знаю, в конфигурации по умолчанию Varnish запросы с Cookie в них никогда не кэшируются. Если вы предпочитаете передавать файлы cookie в ESI-запросы, эти ответы ESI не будут использоваться между пользователями.

    Вы можете попробовать сделать некоторые правила из URL-адреса, но если вы используете помощники по умолчанию для Symfony по умолчанию, сгенерированные URL-адреса являются /_internal/..., поэтому может быть сложно различать публичные и частные.

    Также вы можете настроить, чтобы всегда игнорировать любые файлы cookie, если Cache-Control: public передан. Это делается по умолчанию в Symfony:

    if ($this->isPrivateRequest($request) && !$response->headers->hasCacheControlDirective('public')) {
        $response->setPrivate(true);
    }
    

    Как вы видите из кода, если у вас есть директива public, ответ никогда не будет закрытым.

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

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

    Я предполагаю, что JS требуется для ваших зарегистрированных пользователей (а не для поисковых роботов), поэтому я бы предложил использовать Javascript для различения загрузки пользовательских данных.

    Javascript-код может посмотреть, есть ли у пользователя cookie session-id и т.д. и сделать запрос на получение данных только в этом случае. Также может быть хорошей идеей установить некоторые другие файлы cookie, например _loggedin, чтобы код Javascript не получал идентификатор сеанса.

    Неавторизованные пользователи могут также иметь некоторые данные в файлах cookie, например _likedPost:1,2,132. Javascript может получить этот файл cookie и внести некоторые исправления HTML, даже не сделав дополнительный запрос.

    Как и в случае с этими куки файлами: мы отделили JS файлы cookie от куки файлов приложений. Мы сделали это по некоторому шаблону, например _\w для JS файлов cookie. Затем мы изменили настройку Varnish, чтобы разделить заголовок Cookie и удалить эти JS файлы cookie. Затем, если нет другого файла cookie, ответ будет передан всем. Приложение (Symfony) не получает эти файлы cookie, поскольку они лишены.

  • Я думаю, что это так, если на каждой странице одно и то же.

  • Я думаю, что ESI хорош, так как Varnish может хранить кеш в памяти. Таким образом, возможно, он даже не выполнил никаких запросов на ваш жесткий диск для контента. Поскольку ваш кеш контроллера может также быть в памяти, я думаю, что Varnish будет искать кеш быстрее, чем инфраструктура Symfony, со всеми маршрутизациями, кодом PHP, инициализацией сервисов и т.д.

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

    Возможно, лучше подобрать загруженные места на javascript, например, найти некоторый атрибут HTML, например data-list-item-id, а затем сделать запрос ajax, запрашивая данные об этих элементах. В этом случае ваши пользовательские данные будут синхронизироваться с текущим кэшированным списком, и вы можете сделать 1 ajax-запрос для обоих списков вместо 2.

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