SlideShare a Scribd company logo
1 of 40
Download to read offline
Расширенное
кеширование в Doctrine
Ильяс Салихов
Intaro, CTO
retailCRM, CTO
О докладчике
Ильяс Салихов
• Интаро – веб-интегратор http://intaro.ru
• retailCRM – cпециализированная CRM-система
для интернет-торговли http://www.retailcrm.ru
2
Инструменты кеширования в Doctrine
Doctrine предоставляет:
1. Компонент doctrine/cache с большим
набором драйверов
2. 3 уровня кеширования в ORM
3. First-level-cache + Second-level-cache (с
Doctrine >=2.5)
Очумелые ручки:
4. Taggable caching
3
3 уровня кеширования
1. Metadata Cache
• Описание модели данных
2. Query Cache
• Результирующий SQL
3. Result Cache
• Результаты SQL-запроса
4
Metadata и Query Cache
5
Metadata и Query Cache
1. Снижают нагрузку на app-, но не db-
сервера
2. Занимают мало места
3. Много запросов в кеш
4. Простота и удобство использования
Можно целиком очищать и перегенерировать
4. Всегда включаем в production
6
Metadata и Query Cache
На странице может легко быть 100+
обращений за metadata и query
Держим в APC
На порядок быстрее, чем в memcached, особенно,
если memcached на другой машине
doctrine:
orm:
entity_managers:
default:
metadata_cache_driver:
type: apc
query_cache_driver:
type: apc 7
Metadata и Query Cache
В CLI нет APC, поэтому приходится
держать в memcache/redis/…
Как совместить разные конфигурации
кеша?
8
Metadata и Query Cache
Разные конфигурации для cli и web
Вариант 1. Разные env
# file app/config/config_prod.yml
doctrine:
orm:
entity_managers:
default:
metadata_cache_driver:
type: apc
query_cache_driver:
type: apc
# file app/config/config_cli.yml
doctrine:
orm:
entity_managers:
default:
metadata_cache_driver:
type: memcache
host: 127.0.0.1
query_cache_driver:
type: memcache
host: 127.0.0.1 9
Metadata и Query Cache
Разные конфигурации для cli и web
Вариант 2. Разнести выполнение cli и web на разные сервера
# file app/config/parameters.yml
parameters:
doctrine_cache.meta.type: apc # or memcache
doctrine_cache.query.type: apc # or memcache
memcache.host: 127.0.0.1
# file app/config/config_prod.yml
doctrine:
orm:
entity_managers:
default:
metadata_cache_driver:
type: %doctrine_cache.meta.type%
host: %memcache.host%
query_cache_driver:
type: %doctrine_cache.query.type%
host: %memcache.host%
10
Автосброс Metadata и Query Cache
<?php
class AppKernel extends Kernel
{
public function registerContainerConfiguration(LoaderInterface $loader)
{
$loader->load(function ($container) {
$environment =
$container->getParameter('kernel.root_dir') .
$container->getParameter('kernel.environment');
$key = 'apc_actual_check_' . hash('sha256', $environment);
$value = $container->getParameter('cache.prefix');
if (apc_fetch($key) !== $value) {
apc_clear_cache();
apc_clear_cache('user');
apc_store($key, $value);
}
});
}
}
1. Заводим параметр cache.prefix в parameters.yml
2. Изменяем его в момент деплоя (например, текущая дата-время)
11
First-level cache &
Second-level cache
12
First-level cache
Кеширует объекты в памяти в рамках
одного Request
<?php
// будут выполнены запросы в БД
$city = $em->getRepository('AppBundleEntityCity')->find(5);
$country = $em->getRepository('AppBundleEntityCountry')->find(1);
// НЕ будет запроса в БД, first-level-cache
$country = $em->getRepository('AppBundleEntityCountry')->find(1);
$city->getCountry();
13
Second-level cache (since Doctrine 2.5)
Request 1
Request 2
<?php
// запросы в БД
$city = $em->getRepository('AppBundleEntityCity')->find(5);
$country = $em->getRepository('AppBundleEntityCountry')->find(1);
// НЕ будет запроса в БД, first-level-cache
$country = $em->getRepository('AppBundleEntityCountry')->find(1);
$city->getCountry();
<?php
// НЕ будет запроса в БД, second-level-cache
$city = $em->getRepository('AppBundleEntityCity')->find(5);
$country = $em->getRepository('AppBundleEntityCountry')->find(1);
// НЕ будет запроса в БД, first-level-cache
$country = $em->getRepository('AppBundleEntityCountry')->find(1);
$city->getCountry();
14
Second-level cache (since Doctrine 2.5)
Плюсы:
1. Меньше обращений к БД
2. Кеширование Lazy Fetch методов
НЕ НАДО рассчитывать на second-level cache для
Lazy Fetch. Выбирайте связные данные заранее.
// Request 1
// ---------
$city = $em->getRepository('AppBundleEntityCity')->find(5);
// Будет запрос в БД
$city->getCountry();
// Request 2
// ---------
$city = $em->getRepository('AppBundleEntityCity')->find(5);
// НЕ будет запроса в БД, second-level-cache
$city->getCountry();
15
Second-level cache (since Doctrine 2.5)
Минусы:
1. Большое количество запросов в кеш вместо
единоразовой выборки коллекции
<?php
// Выполняет запрос (выбирает 100 записей),
// сохраняет кеш запроса и entity cache
$result1 = $em->createQuery('SELECT c FROM Country c ORDER BY c.name')
->setCacheable(true)
->getResult();
$em->clear();
// 1 запрос в кеш за result-cache + 100 запросов в second-level cache
// за объектами
$result2 = $em->createQuery('SELECT c FROM Country c ORDER BY c.name')
->setCacheable(true)
->getResult();
16
Result Cache
17
Классический Result Cache
Для чего кешировать запросы:
1. Неэффективность HTTP-кеша при
большой плотности данных на странице
(бизнес-приложения)
2. Недопустимость отображения данных из
устаревшего кеша
3. Снижение нагрузки БД
18
Result Cache
Cотни и тысячи разных выборок данных из
разных таблиц
Классическая проблема сброса кеша при
изменении данных
19
Taggable Cache
20
Taggable Cache. Принцип работы
Хранение кеша
21
cache1
tag1, tag2, tag3
cache2
tag2, tag4
cache3
tag3, tag5
cache4
tag1, tag5
Удаление кеша по тегу tag3
cache1
tag1, tag2, tag3
cache2
tag2, tag4
cache3
tag3, tag5
cache4
tag1, tag5
Taggable Cache
Первый подход к снаряду:
memcached-tags
https://code.google.com/p/memcached-tags/
(форк memcached)
22
Taggable Cache: memcached-tags
Пример использования:
<?php
$memcache = new Memcache();
$memcache->connect("127.0.0.1", 11211);
$memcache->set("key1", "val1");
$memcache->set("key2", "val2");
$memcache->tag_add("tag_1", ["key1", "key2"]);
$memcache->tag_add("tag_2", "key1");
// будет удален кеш key1
$memcache->tag_delete("tag_2");
23
Taggable Cache: memcached-tags
Плюсы:
1. Нативные методы в memcached
Минусы:
1. Зависимость от нестандартной сборки
2. Недостаточно стабильная реализация
3. Проект не поддерживается
24
Taggable Cache
Второй подход к снаряду:
Redis + форк Doctrine2
http://redis.io
25
Taggable Cache: Redis
memcached:
• Простое key-value хранилище, где
value – только строка
Redis:
• Кроме значений типа strings
предоставляет набор разных типов
данных: lists, sets, hashes, sorted sets и др.
26
Taggable Cache: принцип работы
cache1
cache2
cacheN
Query result cache
Redis Strings
Сache tags
Redis Sets
Tag1
- cache1
- cache2
Tag2
- cache2
- cacheN
В Redis есть нужные для реализации методы:
• sAdd – добавление элемента в коллекцию (пометить кеш
тегом)
• sMembers – получение элементов коллекции (ключи
кешей, помеченных тегом)
• delete – поддержка мультиудаления за один запрос 27
Taggable Cache: принцип работы
<?php
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$key = 'hash_123sf1';
$data = [/* коллекция элементов */];
$tags = ['tag1', 'tag2'];
// сохраняем данные
$redis->set($key, $data);
// фиксируем, что эти данные помечены тегами
foreach ($tags as $tag) {
$redis->sAdd($tag, $key);
}
Сохранение кеша
28
Taggable Cache: принцип работы
<?php
$tag = 'tag1';
/**
* CAS-behavior
*/
$redis->watch($tag);
$keys = $redis->sMembers($tag);
$redis->multi()
->delete($tag) // удаляем тега
->delete($keys) // уделяем ключей кеша по тегу
->exec();
Удаление кеша по тегу
29
Taggable Cache: чем пришлось жертвовать
Свой форк Doctrine2…, который отличается
двумя строчками:
30
Taggable Cache: чем пришлось жертвовать
{
"require": {
"doctrine/dbal": "2.5.0",
"doctrine/common": "2.5.0",
"doctrine/orm": "dev-final-keyword-fix-25 as 2.5.0",
// ...
},
"repositories": [
{
"type": "vcs",
"url": "https://github.com/retailcrm/doctrine2"
}
]
}
Свой форк Doctrine2
31
Taggable Cache: чем пришлось жертвовать
Для чего форкали
32
<?php
class Query extends DoctrineORMQuery
{
protected function _doExecute()
{
//...
// выполнение запроса и кеширование результатов
$result = parent::_doExecute();
// помечаем кеш результатов тегами
if ($queryCacheDriver && $queryCacheDriver instanceof TaggableCache) {
if ($tags = $this->getCacheTags()) {
$queryCacheDriver->tagAdd($tags, $queryId);
}
}
return $result;
}
}
Taggable Cache: чем пришлось жертвовать
Свой форк Doctrine2
+
Бандл IntaroTaggableCacheBundle
1. Свой CacheDriver с поддержкой тегов
2. Наследованные EntityRepository, Query,
NativeQuery, QueryBuilder с поддержкой тегов
3. Listener для удаления по тегу при
добавлении/изменении записей
33
Taggable Cache: выборка через QueryBuilder
<?php
namespace IntaroCRMBundleEntityRepository;
use IntaroTaggableCacheBundleDoctrineORMEntityRepository;
class OrderRepository extends EntityRepository
{
public function getCustomerLastOrder(Customer $customer)
{
$qb = $this->createQueryBuilder('o')
->select('o, s')
->leftJoin('o.status', 's')
->where('o.customer = :customer')
->setParameter('customer', $customer)
->orderBy('o.id', 'DESC')
->setMaxResults(1)
->addCacheTags([
Order::class,
Status::class,
])
;
return $qb->getQuery()->getOneOrNullResult();
}
} 34
Taggable Cache: выборка через NativeQuery
<?php
use IntaroTaggableCacheBundleDoctrineORMNativeQuery;
use DoctrineORMQueryResultSetMapping;
$rsm = new ResultSetMapping();
$rsm->addScalarResult('cnt', 'cnt');
$q = new NativeQuery($em);
$q->setResultSetMapping($rsm)
;$q->setSql('
SELECT
COUNT(o.id) AS cnt
FROM
i_crm_order o
WHERE
fetchval(o.custom_fields, ?) <= ?
');
$q->setParameters(['date_of_sending', '2015-07-01']);
$q->addCacheTag(Order::class);
$count = $q->getSingleScalarResult();
35
Taggable Cache: сброс кеша, изменение записей
<?php
$order = new Order();
$em->persist($order);
// здесь будет выполнен сброс кеша запросов с тегом Order
$em->flush();
$order2 = $em->getRepository(Order::class)->find(5);
$order2->setPhone('+7926-123-45-67');
// здесь тоже будет выполнен сброс кеша запросов с тегом Order
$em->flush();
Сброс при добавлении или изменении записей
36
Taggable Cache: сброс кеша, массовое обновление
<?php
use IntaroTaggableCacheBundleDoctrineORMEntityRepository;
class OrderRepository extends EntityRepository
{
public function updateIndexNumber()
{
$q = '
WITH calc_data (id, n) AS (
-- ...
)
UPDATE
i_crm_order o
SET
index_number = cd.n
FROM
calc_data as cd
WHERE
o.id = cd.id
';
$this->getEntityManager()->getConnection()->executeUpdate($q);
// сбрасываем кеш запросов с тегом Order
$this->clearEntityCache();
}
}
37
Taggable Cache
Плюсы Taggable Cache:
1. Почти нет ручной работы по сбросу кеша
(только при DELETE или UPDATE на SQL)
2. Всегда актуальный кеш данных
3. В боевом режиме проверено
на 1500 req/s к кешу
38
Taggable Cache
Минусы Taggable Cache:
1. Форк Doctrine2 (хотя в силу малых
изменений легко поддерживается)
2. Есть узкое место по памяти при сбросе
кеша по тегу
~40 mb на 200 тысяч ключей
<?php
$tag = 'tag1';
$keys = $redis->sMembers($tag);
$redis->delete($keys);
39
Спасибо за внимание.
• http://docs.doctrine-project.org/projects/doctrine-
orm/en/latest/reference/caching.html
• http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/second-
level-cache.html
• https://github.com/retailcrm/doctrine2
• https://code.google.com/p/memcached-tags/
• http://redis.io
• http://smira.ru/posts/20081029web-caching-memcached-5.html
Мои контакты:
twitter.com/salikhov
github.com/muxx
habrahabr.ru/users/muxx/
40

More Related Content

What's hot

Ice Php Framework Preview Release
Ice Php Framework Preview ReleaseIce Php Framework Preview Release
Ice Php Framework Preview ReleaseDenis Shestakov
 
Web осень 2013 лекция 3
Web осень 2013 лекция 3Web осень 2013 лекция 3
Web осень 2013 лекция 3Technopark
 
Scala, Play Framework и SBT для быстрого прототипирования и разработки веб-пр...
Scala, Play Framework и SBT для быстрого прототипирования и разработки веб-пр...Scala, Play Framework и SBT для быстрого прототипирования и разработки веб-пр...
Scala, Play Framework и SBT для быстрого прототипирования и разработки веб-пр...Magneta AI
 
Web осень 2013 лекция 1
Web осень 2013 лекция 1Web осень 2013 лекция 1
Web осень 2013 лекция 1Technopark
 
MariaDB 10.1 - что нового.
MariaDB 10.1 - что нового.MariaDB 10.1 - что нового.
MariaDB 10.1 - что нового.Sergey Petrunya
 
Yandex Tank - Арсений Фомченко
Yandex Tank - Арсений ФомченкоYandex Tank - Арсений Фомченко
Yandex Tank - Арсений ФомченкоAvitoTech
 
XML Native Database на примере SednaXML
XML Native Database на примере SednaXMLXML Native Database на примере SednaXML
XML Native Database на примере SednaXMLSlach
 
Оптимизация работы с данными в мобильных приложениях / Святослав Иванов, Артё...
Оптимизация работы с данными в мобильных приложениях / Святослав Иванов, Артё...Оптимизация работы с данными в мобильных приложениях / Святослав Иванов, Артё...
Оптимизация работы с данными в мобильных приложениях / Святослав Иванов, Артё...Ontico
 
Web осень 2013 лекция 5
Web осень 2013 лекция 5Web осень 2013 лекция 5
Web осень 2013 лекция 5Technopark
 
SharePoint Virtualization "Виртуальный SharePoint 2010"
SharePoint Virtualization "Виртуальный SharePoint 2010" SharePoint Virtualization "Виртуальный SharePoint 2010"
SharePoint Virtualization "Виртуальный SharePoint 2010" Michael Noel
 
Эффективная отладка репликации MySQL
Эффективная отладка репликации MySQLЭффективная отладка репликации MySQL
Эффективная отладка репликации MySQLSveta Smirnova
 
Производительность запросов в PostgreSQL - шаг за шагом / Илья Космодемьянски...
Производительность запросов в PostgreSQL - шаг за шагом / Илья Космодемьянски...Производительность запросов в PostgreSQL - шаг за шагом / Илья Космодемьянски...
Производительность запросов в PostgreSQL - шаг за шагом / Илья Космодемьянски...Ontico
 
Open Source SQL-базы данных вступили в эру миллионов запросов в секунду / Фед...
Open Source SQL-базы данных вступили в эру миллионов запросов в секунду / Фед...Open Source SQL-базы данных вступили в эру миллионов запросов в секунду / Фед...
Open Source SQL-базы данных вступили в эру миллионов запросов в секунду / Фед...Ontico
 
Sphinx: распределяя индексы.
Sphinx: распределяя индексы.Sphinx: распределяя индексы.
Sphinx: распределяя индексы.MageCloud
 
Web осень 2013 лекция 2
Web осень 2013 лекция 2Web осень 2013 лекция 2
Web осень 2013 лекция 2Technopark
 
Web осень 2013 лекция 9
Web осень 2013 лекция 9Web осень 2013 лекция 9
Web осень 2013 лекция 9Technopark
 
Hacking PostgreSQL. Локальная память процессов. Контексты памяти.
Hacking PostgreSQL. Локальная память процессов. Контексты памяти.Hacking PostgreSQL. Локальная память процессов. Контексты памяти.
Hacking PostgreSQL. Локальная память процессов. Контексты памяти.Anastasia Lubennikova
 
Service Discovery. More that it seems
Service Discovery. More that it seemsService Discovery. More that it seems
Service Discovery. More that it seemsAleksandr Tarasov
 
Загрузка, обработка, хранение и отдача статики
Загрузка, обработка, хранение и отдача статикиЗагрузка, обработка, хранение и отдача статики
Загрузка, обработка, хранение и отдача статикиKirill Mokevnin
 

What's hot (20)

Ice Php Framework Preview Release
Ice Php Framework Preview ReleaseIce Php Framework Preview Release
Ice Php Framework Preview Release
 
Web осень 2013 лекция 3
Web осень 2013 лекция 3Web осень 2013 лекция 3
Web осень 2013 лекция 3
 
Scala, Play Framework и SBT для быстрого прототипирования и разработки веб-пр...
Scala, Play Framework и SBT для быстрого прототипирования и разработки веб-пр...Scala, Play Framework и SBT для быстрого прототипирования и разработки веб-пр...
Scala, Play Framework и SBT для быстрого прототипирования и разработки веб-пр...
 
Web осень 2013 лекция 1
Web осень 2013 лекция 1Web осень 2013 лекция 1
Web осень 2013 лекция 1
 
MariaDB 10.1 - что нового.
MariaDB 10.1 - что нового.MariaDB 10.1 - что нового.
MariaDB 10.1 - что нового.
 
Yandex Tank - Арсений Фомченко
Yandex Tank - Арсений ФомченкоYandex Tank - Арсений Фомченко
Yandex Tank - Арсений Фомченко
 
XML Native Database на примере SednaXML
XML Native Database на примере SednaXMLXML Native Database на примере SednaXML
XML Native Database на примере SednaXML
 
Оптимизация работы с данными в мобильных приложениях / Святослав Иванов, Артё...
Оптимизация работы с данными в мобильных приложениях / Святослав Иванов, Артё...Оптимизация работы с данными в мобильных приложениях / Святослав Иванов, Артё...
Оптимизация работы с данными в мобильных приложениях / Святослав Иванов, Артё...
 
Web осень 2013 лекция 5
Web осень 2013 лекция 5Web осень 2013 лекция 5
Web осень 2013 лекция 5
 
SharePoint Virtualization "Виртуальный SharePoint 2010"
SharePoint Virtualization "Виртуальный SharePoint 2010" SharePoint Virtualization "Виртуальный SharePoint 2010"
SharePoint Virtualization "Виртуальный SharePoint 2010"
 
Эффективная отладка репликации MySQL
Эффективная отладка репликации MySQLЭффективная отладка репликации MySQL
Эффективная отладка репликации MySQL
 
Производительность запросов в PostgreSQL - шаг за шагом / Илья Космодемьянски...
Производительность запросов в PostgreSQL - шаг за шагом / Илья Космодемьянски...Производительность запросов в PostgreSQL - шаг за шагом / Илья Космодемьянски...
Производительность запросов в PostgreSQL - шаг за шагом / Илья Космодемьянски...
 
Open Source SQL-базы данных вступили в эру миллионов запросов в секунду / Фед...
Open Source SQL-базы данных вступили в эру миллионов запросов в секунду / Фед...Open Source SQL-базы данных вступили в эру миллионов запросов в секунду / Фед...
Open Source SQL-базы данных вступили в эру миллионов запросов в секунду / Фед...
 
Sphinx: распределяя индексы.
Sphinx: распределяя индексы.Sphinx: распределяя индексы.
Sphinx: распределяя индексы.
 
Web осень 2013 лекция 2
Web осень 2013 лекция 2Web осень 2013 лекция 2
Web осень 2013 лекция 2
 
Web осень 2013 лекция 9
Web осень 2013 лекция 9Web осень 2013 лекция 9
Web осень 2013 лекция 9
 
Hacking PostgreSQL. Локальная память процессов. Контексты памяти.
Hacking PostgreSQL. Локальная память процессов. Контексты памяти.Hacking PostgreSQL. Локальная память процессов. Контексты памяти.
Hacking PostgreSQL. Локальная память процессов. Контексты памяти.
 
Service Discovery. More that it seems
Service Discovery. More that it seemsService Discovery. More that it seems
Service Discovery. More that it seems
 
2017-03-11 01 Игорь Родионов. Docker swarm vs Kubernetes
2017-03-11 01 Игорь Родионов. Docker swarm vs Kubernetes2017-03-11 01 Игорь Родионов. Docker swarm vs Kubernetes
2017-03-11 01 Игорь Родионов. Docker swarm vs Kubernetes
 
Загрузка, обработка, хранение и отдача статики
Загрузка, обработка, хранение и отдача статикиЗагрузка, обработка, хранение и отдача статики
Загрузка, обработка, хранение и отдача статики
 

Viewers also liked

Speed up your Symfony2 application and build awesome features with Redis
Speed up your Symfony2 application and build awesome features with RedisSpeed up your Symfony2 application and build awesome features with Redis
Speed up your Symfony2 application and build awesome features with RedisRicard Clau
 
Кластеры баз данных делаем сложные вещи просто / Андрей Тихонов (Avito)
Кластеры баз данных делаем сложные вещи просто / Андрей Тихонов (Avito)Кластеры баз данных делаем сложные вещи просто / Андрей Тихонов (Avito)
Кластеры баз данных делаем сложные вещи просто / Андрей Тихонов (Avito)Ontico
 
Rationally boost your symfony2 application with caching tips and monitoring
Rationally boost your symfony2 application with caching tips and monitoringRationally boost your symfony2 application with caching tips and monitoring
Rationally boost your symfony2 application with caching tips and monitoringGiulio De Donato
 
Дизайн REST API для высокопроизводительных систем / Александр Лебедев (Новые ...
Дизайн REST API для высокопроизводительных систем / Александр Лебедев (Новые ...Дизайн REST API для высокопроизводительных систем / Александр Лебедев (Новые ...
Дизайн REST API для высокопроизводительных систем / Александр Лебедев (Новые ...Ontico
 

Viewers also liked (6)

Speed up your Symfony2 application and build awesome features with Redis
Speed up your Symfony2 application and build awesome features with RedisSpeed up your Symfony2 application and build awesome features with Redis
Speed up your Symfony2 application and build awesome features with Redis
 
Devconf15
Devconf15Devconf15
Devconf15
 
pgconf.ru 2015 avito postgresql
pgconf.ru 2015 avito postgresqlpgconf.ru 2015 avito postgresql
pgconf.ru 2015 avito postgresql
 
Кластеры баз данных делаем сложные вещи просто / Андрей Тихонов (Avito)
Кластеры баз данных делаем сложные вещи просто / Андрей Тихонов (Avito)Кластеры баз данных делаем сложные вещи просто / Андрей Тихонов (Avito)
Кластеры баз данных делаем сложные вещи просто / Андрей Тихонов (Avito)
 
Rationally boost your symfony2 application with caching tips and monitoring
Rationally boost your symfony2 application with caching tips and monitoringRationally boost your symfony2 application with caching tips and monitoring
Rationally boost your symfony2 application with caching tips and monitoring
 
Дизайн REST API для высокопроизводительных систем / Александр Лебедев (Новые ...
Дизайн REST API для высокопроизводительных систем / Александр Лебедев (Новые ...Дизайн REST API для высокопроизводительных систем / Александр Лебедев (Новые ...
Дизайн REST API для высокопроизводительных систем / Александр Лебедев (Новые ...
 

Similar to Расширенное кеширование в Doctrine2

PHP Tricks
PHP TricksPHP Tricks
PHP TricksBlackFan
 
Страх и ненависть в исходном коде
Страх и ненависть в исходном кодеСтрах и ненависть в исходном коде
Страх и ненависть в исходном кодеKolya Korobochkin
 
Easy authcache 2 кэширование для pro. Родионов Игорь
Easy authcache 2   кэширование для pro. Родионов ИгорьEasy authcache 2   кэширование для pro. Родионов Игорь
Easy authcache 2 кэширование для pro. Родионов ИгорьPVasili
 
Building the Enterprise infrastructure with PostgreSQL as the basis for stori...
Building the Enterprise infrastructure with PostgreSQL as the basis for stori...Building the Enterprise infrastructure with PostgreSQL as the basis for stori...
Building the Enterprise infrastructure with PostgreSQL as the basis for stori...PavelKonotopov
 
PHP 5.4: Что нового?
PHP 5.4: Что нового?PHP 5.4: Что нового?
PHP 5.4: Что нового?phpdevby
 
Интеграция Яндекс Сервер
Интеграция Яндекс СерверИнтеграция Яндекс Сервер
Интеграция Яндекс СерверPVasili
 
"Деплой кода процедур" Мурат Кабилов (Avito)
"Деплой кода процедур" Мурат Кабилов (Avito)"Деплой кода процедур" Мурат Кабилов (Avito)
"Деплой кода процедур" Мурат Кабилов (Avito)AvitoTech
 
MODX 3: Что нового?
MODX 3: Что нового?MODX 3: Что нового?
MODX 3: Что нового?Ivan Klimchuk
 
Caching on highload Drupal site - Alexander Shumenko
Caching on highload Drupal site - Alexander ShumenkoCaching on highload Drupal site - Alexander Shumenko
Caching on highload Drupal site - Alexander ShumenkoDrupalCampDN
 
CodeFest 2012. Рычков Д. — Почему перед написанием кеша вам стоит поговорить ...
CodeFest 2012. Рычков Д. — Почему перед написанием кеша вам стоит поговорить ...CodeFest 2012. Рычков Д. — Почему перед написанием кеша вам стоит поговорить ...
CodeFest 2012. Рычков Д. — Почему перед написанием кеша вам стоит поговорить ...CodeFest
 
О безопасном использовании PHP wrappers
О безопасном использовании PHP wrappersО безопасном использовании PHP wrappers
О безопасном использовании PHP wrappersPositive Hack Days
 
Database (Lecture 14 – database)
Database (Lecture 14 – database)Database (Lecture 14 – database)
Database (Lecture 14 – database)Noveo
 
MySQL 5.7 - NoSQL - JSON, Protocol X, Document Store / Петр Зайцев (Percona)
MySQL 5.7 - NoSQL - JSON, Protocol X, Document Store / Петр Зайцев (Percona)MySQL 5.7 - NoSQL - JSON, Protocol X, Document Store / Петр Зайцев (Percona)
MySQL 5.7 - NoSQL - JSON, Protocol X, Document Store / Петр Зайцев (Percona)Ontico
 
Толстая модель. История разработки ORM
Толстая модель. История разработки ORMТолстая модель. История разработки ORM
Толстая модель. История разработки ORMMikhail Shamin
 
ZFConf 2011: Толстая модель: История разработки собственного ORM (Михаил Шамин)
ZFConf 2011: Толстая модель: История разработки собственного ORM (Михаил Шамин)ZFConf 2011: Толстая модель: История разработки собственного ORM (Михаил Шамин)
ZFConf 2011: Толстая модель: История разработки собственного ORM (Михаил Шамин)ZFConf Conference
 
Взломать сайт на ASP.NET
Взломать сайт на ASP.NETВзломать сайт на ASP.NET
Взломать сайт на ASP.NETPositive Hack Days
 

Similar to Расширенное кеширование в Doctrine2 (20)

PHP Tricks
PHP TricksPHP Tricks
PHP Tricks
 
UWDC 2013, Yii2
UWDC 2013, Yii2UWDC 2013, Yii2
UWDC 2013, Yii2
 
Страх и ненависть в исходном коде
Страх и ненависть в исходном кодеСтрах и ненависть в исходном коде
Страх и ненависть в исходном коде
 
Easy authcache 2 кэширование для pro. Родионов Игорь
Easy authcache 2   кэширование для pro. Родионов ИгорьEasy authcache 2   кэширование для pro. Родионов Игорь
Easy authcache 2 кэширование для pro. Родионов Игорь
 
Building the Enterprise infrastructure with PostgreSQL as the basis for stori...
Building the Enterprise infrastructure with PostgreSQL as the basis for stori...Building the Enterprise infrastructure with PostgreSQL as the basis for stori...
Building the Enterprise infrastructure with PostgreSQL as the basis for stori...
 
PHP 5.4: Что нового?
PHP 5.4: Что нового?PHP 5.4: Что нового?
PHP 5.4: Что нового?
 
Интеграция Яндекс Сервер
Интеграция Яндекс СерверИнтеграция Яндекс Сервер
Интеграция Яндекс Сервер
 
"Деплой кода процедур" Мурат Кабилов (Avito)
"Деплой кода процедур" Мурат Кабилов (Avito)"Деплой кода процедур" Мурат Кабилов (Avito)
"Деплой кода процедур" Мурат Кабилов (Avito)
 
MODX 3: Что нового?
MODX 3: Что нового?MODX 3: Что нового?
MODX 3: Что нового?
 
Caching on highload Drupal site - Alexander Shumenko
Caching on highload Drupal site - Alexander ShumenkoCaching on highload Drupal site - Alexander Shumenko
Caching on highload Drupal site - Alexander Shumenko
 
CodeFest 2012. Рычков Д. — Почему перед написанием кеша вам стоит поговорить ...
CodeFest 2012. Рычков Д. — Почему перед написанием кеша вам стоит поговорить ...CodeFest 2012. Рычков Д. — Почему перед написанием кеша вам стоит поговорить ...
CodeFest 2012. Рычков Д. — Почему перед написанием кеша вам стоит поговорить ...
 
бегун
бегунбегун
бегун
 
Yserver
YserverYserver
Yserver
 
бегун
бегунбегун
бегун
 
О безопасном использовании PHP wrappers
О безопасном использовании PHP wrappersО безопасном использовании PHP wrappers
О безопасном использовании PHP wrappers
 
Database (Lecture 14 – database)
Database (Lecture 14 – database)Database (Lecture 14 – database)
Database (Lecture 14 – database)
 
MySQL 5.7 - NoSQL - JSON, Protocol X, Document Store / Петр Зайцев (Percona)
MySQL 5.7 - NoSQL - JSON, Protocol X, Document Store / Петр Зайцев (Percona)MySQL 5.7 - NoSQL - JSON, Protocol X, Document Store / Петр Зайцев (Percona)
MySQL 5.7 - NoSQL - JSON, Protocol X, Document Store / Петр Зайцев (Percona)
 
Толстая модель. История разработки ORM
Толстая модель. История разработки ORMТолстая модель. История разработки ORM
Толстая модель. История разработки ORM
 
ZFConf 2011: Толстая модель: История разработки собственного ORM (Михаил Шамин)
ZFConf 2011: Толстая модель: История разработки собственного ORM (Михаил Шамин)ZFConf 2011: Толстая модель: История разработки собственного ORM (Михаил Шамин)
ZFConf 2011: Толстая модель: История разработки собственного ORM (Михаил Шамин)
 
Взломать сайт на ASP.NET
Взломать сайт на ASP.NETВзломать сайт на ASP.NET
Взломать сайт на ASP.NET
 

Расширенное кеширование в Doctrine2

  • 2. О докладчике Ильяс Салихов • Интаро – веб-интегратор http://intaro.ru • retailCRM – cпециализированная CRM-система для интернет-торговли http://www.retailcrm.ru 2
  • 3. Инструменты кеширования в Doctrine Doctrine предоставляет: 1. Компонент doctrine/cache с большим набором драйверов 2. 3 уровня кеширования в ORM 3. First-level-cache + Second-level-cache (с Doctrine >=2.5) Очумелые ручки: 4. Taggable caching 3
  • 4. 3 уровня кеширования 1. Metadata Cache • Описание модели данных 2. Query Cache • Результирующий SQL 3. Result Cache • Результаты SQL-запроса 4
  • 6. Metadata и Query Cache 1. Снижают нагрузку на app-, но не db- сервера 2. Занимают мало места 3. Много запросов в кеш 4. Простота и удобство использования Можно целиком очищать и перегенерировать 4. Всегда включаем в production 6
  • 7. Metadata и Query Cache На странице может легко быть 100+ обращений за metadata и query Держим в APC На порядок быстрее, чем в memcached, особенно, если memcached на другой машине doctrine: orm: entity_managers: default: metadata_cache_driver: type: apc query_cache_driver: type: apc 7
  • 8. Metadata и Query Cache В CLI нет APC, поэтому приходится держать в memcache/redis/… Как совместить разные конфигурации кеша? 8
  • 9. Metadata и Query Cache Разные конфигурации для cli и web Вариант 1. Разные env # file app/config/config_prod.yml doctrine: orm: entity_managers: default: metadata_cache_driver: type: apc query_cache_driver: type: apc # file app/config/config_cli.yml doctrine: orm: entity_managers: default: metadata_cache_driver: type: memcache host: 127.0.0.1 query_cache_driver: type: memcache host: 127.0.0.1 9
  • 10. Metadata и Query Cache Разные конфигурации для cli и web Вариант 2. Разнести выполнение cli и web на разные сервера # file app/config/parameters.yml parameters: doctrine_cache.meta.type: apc # or memcache doctrine_cache.query.type: apc # or memcache memcache.host: 127.0.0.1 # file app/config/config_prod.yml doctrine: orm: entity_managers: default: metadata_cache_driver: type: %doctrine_cache.meta.type% host: %memcache.host% query_cache_driver: type: %doctrine_cache.query.type% host: %memcache.host% 10
  • 11. Автосброс Metadata и Query Cache <?php class AppKernel extends Kernel { public function registerContainerConfiguration(LoaderInterface $loader) { $loader->load(function ($container) { $environment = $container->getParameter('kernel.root_dir') . $container->getParameter('kernel.environment'); $key = 'apc_actual_check_' . hash('sha256', $environment); $value = $container->getParameter('cache.prefix'); if (apc_fetch($key) !== $value) { apc_clear_cache(); apc_clear_cache('user'); apc_store($key, $value); } }); } } 1. Заводим параметр cache.prefix в parameters.yml 2. Изменяем его в момент деплоя (например, текущая дата-время) 11
  • 13. First-level cache Кеширует объекты в памяти в рамках одного Request <?php // будут выполнены запросы в БД $city = $em->getRepository('AppBundleEntityCity')->find(5); $country = $em->getRepository('AppBundleEntityCountry')->find(1); // НЕ будет запроса в БД, first-level-cache $country = $em->getRepository('AppBundleEntityCountry')->find(1); $city->getCountry(); 13
  • 14. Second-level cache (since Doctrine 2.5) Request 1 Request 2 <?php // запросы в БД $city = $em->getRepository('AppBundleEntityCity')->find(5); $country = $em->getRepository('AppBundleEntityCountry')->find(1); // НЕ будет запроса в БД, first-level-cache $country = $em->getRepository('AppBundleEntityCountry')->find(1); $city->getCountry(); <?php // НЕ будет запроса в БД, second-level-cache $city = $em->getRepository('AppBundleEntityCity')->find(5); $country = $em->getRepository('AppBundleEntityCountry')->find(1); // НЕ будет запроса в БД, first-level-cache $country = $em->getRepository('AppBundleEntityCountry')->find(1); $city->getCountry(); 14
  • 15. Second-level cache (since Doctrine 2.5) Плюсы: 1. Меньше обращений к БД 2. Кеширование Lazy Fetch методов НЕ НАДО рассчитывать на second-level cache для Lazy Fetch. Выбирайте связные данные заранее. // Request 1 // --------- $city = $em->getRepository('AppBundleEntityCity')->find(5); // Будет запрос в БД $city->getCountry(); // Request 2 // --------- $city = $em->getRepository('AppBundleEntityCity')->find(5); // НЕ будет запроса в БД, second-level-cache $city->getCountry(); 15
  • 16. Second-level cache (since Doctrine 2.5) Минусы: 1. Большое количество запросов в кеш вместо единоразовой выборки коллекции <?php // Выполняет запрос (выбирает 100 записей), // сохраняет кеш запроса и entity cache $result1 = $em->createQuery('SELECT c FROM Country c ORDER BY c.name') ->setCacheable(true) ->getResult(); $em->clear(); // 1 запрос в кеш за result-cache + 100 запросов в second-level cache // за объектами $result2 = $em->createQuery('SELECT c FROM Country c ORDER BY c.name') ->setCacheable(true) ->getResult(); 16
  • 18. Классический Result Cache Для чего кешировать запросы: 1. Неэффективность HTTP-кеша при большой плотности данных на странице (бизнес-приложения) 2. Недопустимость отображения данных из устаревшего кеша 3. Снижение нагрузки БД 18
  • 19. Result Cache Cотни и тысячи разных выборок данных из разных таблиц Классическая проблема сброса кеша при изменении данных 19
  • 21. Taggable Cache. Принцип работы Хранение кеша 21 cache1 tag1, tag2, tag3 cache2 tag2, tag4 cache3 tag3, tag5 cache4 tag1, tag5 Удаление кеша по тегу tag3 cache1 tag1, tag2, tag3 cache2 tag2, tag4 cache3 tag3, tag5 cache4 tag1, tag5
  • 22. Taggable Cache Первый подход к снаряду: memcached-tags https://code.google.com/p/memcached-tags/ (форк memcached) 22
  • 23. Taggable Cache: memcached-tags Пример использования: <?php $memcache = new Memcache(); $memcache->connect("127.0.0.1", 11211); $memcache->set("key1", "val1"); $memcache->set("key2", "val2"); $memcache->tag_add("tag_1", ["key1", "key2"]); $memcache->tag_add("tag_2", "key1"); // будет удален кеш key1 $memcache->tag_delete("tag_2"); 23
  • 24. Taggable Cache: memcached-tags Плюсы: 1. Нативные методы в memcached Минусы: 1. Зависимость от нестандартной сборки 2. Недостаточно стабильная реализация 3. Проект не поддерживается 24
  • 25. Taggable Cache Второй подход к снаряду: Redis + форк Doctrine2 http://redis.io 25
  • 26. Taggable Cache: Redis memcached: • Простое key-value хранилище, где value – только строка Redis: • Кроме значений типа strings предоставляет набор разных типов данных: lists, sets, hashes, sorted sets и др. 26
  • 27. Taggable Cache: принцип работы cache1 cache2 cacheN Query result cache Redis Strings Сache tags Redis Sets Tag1 - cache1 - cache2 Tag2 - cache2 - cacheN В Redis есть нужные для реализации методы: • sAdd – добавление элемента в коллекцию (пометить кеш тегом) • sMembers – получение элементов коллекции (ключи кешей, помеченных тегом) • delete – поддержка мультиудаления за один запрос 27
  • 28. Taggable Cache: принцип работы <?php $redis = new Redis(); $redis->connect('127.0.0.1', 6379); $key = 'hash_123sf1'; $data = [/* коллекция элементов */]; $tags = ['tag1', 'tag2']; // сохраняем данные $redis->set($key, $data); // фиксируем, что эти данные помечены тегами foreach ($tags as $tag) { $redis->sAdd($tag, $key); } Сохранение кеша 28
  • 29. Taggable Cache: принцип работы <?php $tag = 'tag1'; /** * CAS-behavior */ $redis->watch($tag); $keys = $redis->sMembers($tag); $redis->multi() ->delete($tag) // удаляем тега ->delete($keys) // уделяем ключей кеша по тегу ->exec(); Удаление кеша по тегу 29
  • 30. Taggable Cache: чем пришлось жертвовать Свой форк Doctrine2…, который отличается двумя строчками: 30
  • 31. Taggable Cache: чем пришлось жертвовать { "require": { "doctrine/dbal": "2.5.0", "doctrine/common": "2.5.0", "doctrine/orm": "dev-final-keyword-fix-25 as 2.5.0", // ... }, "repositories": [ { "type": "vcs", "url": "https://github.com/retailcrm/doctrine2" } ] } Свой форк Doctrine2 31
  • 32. Taggable Cache: чем пришлось жертвовать Для чего форкали 32 <?php class Query extends DoctrineORMQuery { protected function _doExecute() { //... // выполнение запроса и кеширование результатов $result = parent::_doExecute(); // помечаем кеш результатов тегами if ($queryCacheDriver && $queryCacheDriver instanceof TaggableCache) { if ($tags = $this->getCacheTags()) { $queryCacheDriver->tagAdd($tags, $queryId); } } return $result; } }
  • 33. Taggable Cache: чем пришлось жертвовать Свой форк Doctrine2 + Бандл IntaroTaggableCacheBundle 1. Свой CacheDriver с поддержкой тегов 2. Наследованные EntityRepository, Query, NativeQuery, QueryBuilder с поддержкой тегов 3. Listener для удаления по тегу при добавлении/изменении записей 33
  • 34. Taggable Cache: выборка через QueryBuilder <?php namespace IntaroCRMBundleEntityRepository; use IntaroTaggableCacheBundleDoctrineORMEntityRepository; class OrderRepository extends EntityRepository { public function getCustomerLastOrder(Customer $customer) { $qb = $this->createQueryBuilder('o') ->select('o, s') ->leftJoin('o.status', 's') ->where('o.customer = :customer') ->setParameter('customer', $customer) ->orderBy('o.id', 'DESC') ->setMaxResults(1) ->addCacheTags([ Order::class, Status::class, ]) ; return $qb->getQuery()->getOneOrNullResult(); } } 34
  • 35. Taggable Cache: выборка через NativeQuery <?php use IntaroTaggableCacheBundleDoctrineORMNativeQuery; use DoctrineORMQueryResultSetMapping; $rsm = new ResultSetMapping(); $rsm->addScalarResult('cnt', 'cnt'); $q = new NativeQuery($em); $q->setResultSetMapping($rsm) ;$q->setSql(' SELECT COUNT(o.id) AS cnt FROM i_crm_order o WHERE fetchval(o.custom_fields, ?) <= ? '); $q->setParameters(['date_of_sending', '2015-07-01']); $q->addCacheTag(Order::class); $count = $q->getSingleScalarResult(); 35
  • 36. Taggable Cache: сброс кеша, изменение записей <?php $order = new Order(); $em->persist($order); // здесь будет выполнен сброс кеша запросов с тегом Order $em->flush(); $order2 = $em->getRepository(Order::class)->find(5); $order2->setPhone('+7926-123-45-67'); // здесь тоже будет выполнен сброс кеша запросов с тегом Order $em->flush(); Сброс при добавлении или изменении записей 36
  • 37. Taggable Cache: сброс кеша, массовое обновление <?php use IntaroTaggableCacheBundleDoctrineORMEntityRepository; class OrderRepository extends EntityRepository { public function updateIndexNumber() { $q = ' WITH calc_data (id, n) AS ( -- ... ) UPDATE i_crm_order o SET index_number = cd.n FROM calc_data as cd WHERE o.id = cd.id '; $this->getEntityManager()->getConnection()->executeUpdate($q); // сбрасываем кеш запросов с тегом Order $this->clearEntityCache(); } } 37
  • 38. Taggable Cache Плюсы Taggable Cache: 1. Почти нет ручной работы по сбросу кеша (только при DELETE или UPDATE на SQL) 2. Всегда актуальный кеш данных 3. В боевом режиме проверено на 1500 req/s к кешу 38
  • 39. Taggable Cache Минусы Taggable Cache: 1. Форк Doctrine2 (хотя в силу малых изменений легко поддерживается) 2. Есть узкое место по памяти при сбросе кеша по тегу ~40 mb на 200 тысяч ключей <?php $tag = 'tag1'; $keys = $redis->sMembers($tag); $redis->delete($keys); 39
  • 40. Спасибо за внимание. • http://docs.doctrine-project.org/projects/doctrine- orm/en/latest/reference/caching.html • http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/second- level-cache.html • https://github.com/retailcrm/doctrine2 • https://code.google.com/p/memcached-tags/ • http://redis.io • http://smira.ru/posts/20081029web-caching-memcached-5.html Мои контакты: twitter.com/salikhov github.com/muxx habrahabr.ru/users/muxx/ 40