Pull to refresh

Symfony2. Подводные камни кэширования

Reading time 3 min
Views 9.3K

Прошло уже 3 месяца с тех пор, как я, в качестве хобби, начал писать проект на новом Symfony 2. Далее в статье я постараюсь поделиться с хабрасообществом проблемами, с которыми может столкнуться разработчик. Статья ориентирована на людей уже знакомых с архитектурой Symfony и Doctrine.


Проблема 1. Doctrine 2. Result Cache. Serializing Entities.

Doctrine 2 позволяет нам кэшировать запросы, но при этом не рекомендует это делать с Entity.
Serializing entities can be problematic and is not really recommended, at least not as long as an entity instance still holds references to proxy objects or is still managed by an EntityManager… (пруф)

В любом случае, если мы решаем кэшировать запрос, то для каждой Entity необходимо реализовать интерфейс Serializable. При этом объекты, которые пришли из кэша не могут корректно обработаться менеджером. Он их считает новыми и пытается заново вставить в базу. Чтобы все работало корректно, необходимо или заново загрузить объект или не использовать в данном случае кэширование.

Пример.
//массив объектов из кэша
$blogs = $this->getDoctrine()
        ->getRepository('BlogBundle:Blog')
        ->getBlogs();

if ($request->getMethod() == 'POST') {
    $form->bindRequest($request);

    if ($form->isValid()) {
        $data = $form->getData();


        // создаем или обновляем пост
        // забиваем данные
        // ...
        
        // так работать не будет
        foreach ($blogs as $blog) {
            if ($blog->getId() == $data->blog_id) {
                $blog = $blog;
                break;
            }
        }

        //а так будет
        //$blog = $this->getDoctrine()
        //        ->getRepository('BlogBundle:Blog')
        //        ->findOneById($blog->getId());


        //указываем блог для поста
        $post->setBlog($blog);

        //сохраняем
        $em = $this->getDoctrine()->getEntityManager();
        $em->persist($post);
        $em->flush();
    }
}


Проблема 2. Symfony2. HTTP Cache и Security Component.

Идеология кэширования фреймворка основана на спецификации HTTP, что позволяет использовать проксирующие кэши. Например, Varnish. Плюс большой, т.к. страница отдаётся клиенту без загрузки самого фреймворка.

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

Решение данной проблемы я пока не нашел. Возможно, хабрасообщество поможет.

Также, исходя из идеологии кэширования, Symfony2 лучше не использовать в проектах, где контент меняется в зависимости от авторизации пользователя. Например, голосование за топик на хабре, где существуют следующие состояния: можно голосовать, я проголосовал положительно, отрицательно, голосование закончилось и т.д. Или, например, форма добавления комментария к публикации, где есть возможность комментирования и анонимными пользователями.

Тест на нагрузку.

По счастливой случайности я имею два проекта схожие по функционалу. Один написан на Symfony 1.4, а другой на Symfony2.
И как ни странно простой нагрузочный тест главных страниц показал, что проект на Symfony 1.4 работает быстрее:
  1. Symfony 1.4 примерно 2550 запросов за 30 секунд при конкуренции 10.
  2. Symfony2 примерно 1750 запросов за 30 секунд при конкуренции 10.

Проекты хостятся на выделеном сервере с четырех ядерным процессором (Intel Core2 Quad CPU Q9550) и 8G оперативной памяти.

Сайты на которых проводились тесты:
  1. http://dreamiech.ru — Symfony 1.4
  2. http://dvjournal.ru — Symfony 2
Tags:
Hubs:
+16
Comments 25
Comments Comments 25

Articles