Как стать автором
Обновить

Комментарии 52

гм… а это случаем не дублирует теги? и какой оверхед при активном использовании (по памяти)?
что значит «дублирует тэги»?
по памяти все нормально, структура в любом случае получается достаточно компактной. Можно еще оптимизировать, но это уже в качестве домашнего задания :)
ну я о том, что тегами то же достигается — удаление разных сущностей (в разных местах) одной командой.
а вот вы о чем. Не спорю. Но тэги это же тоже реализация, а не стандартная фича. Я предложил свою, и только то.
Теги удобнее, как мне кажется.
теги удобнее. факт.
тесты нечитабельные. они не выполняют ту работу, которую вы на них возложили — документирование. также — они совершенно не отражают главную «фичу» топика, такую как «групповое удаление».
по факту: куда более запутанная и сложная реализация, нежели теги. сложная в понимании, в основном

ps: «Подобный подход с успехом работал на проекте photofile.ru под нагрузкой около 4-х млн хитов в сутки.» из этого не значит, что с тегами было бы хуже :-)
тесты вполне нормально отражают суть. если есть конкретные притензии а не субъетивные, слушаю.
то же самое и по запутанности реализации. помоему проще просто некуда.
$this->assertEqual($cache->get(), '1');
$this->assertNotEqual($cache->get(), '2');

$cache->delete('comments|counters');

ну или только счетчик пользователя

$cache->delete('comments|counters|user123');

Лучше всего о работе класса расскажет юнит-тест (они вообще часто лучше любой документации):

где эти ситуации описаны в тестах?

да, есть кейс:
$cache = new MemcacheCacher('key|key1');
$this->assertFalse($cache->exists());

но что будет, если удалить key? где? как догадаться? :-)

protected $header = array();
таким образом пресловутый кешхэдер хранится в памяти, пока не произойдёт перезапись. а что будет, если между этими событиями рядом работающий скрипт возьмёт и изменит хэдер? между получением кэша и его изменением — не обязательно ведь 2 строки, как в тестах. получение и изменение могут быть разделены между собой на десятки-сотню мс.
про «key» был невнимателен. остальное в силе :-)
>но что будет, если удалить key? где? как догадаться? :-)

А это что?

$cache = new MemcacheCacher('key');
$cache->del();

>а что будет, если между этими событиями рядом работающий скрипт возьмёт и изменит хэдер?

А вы подумайте что будет, ну и если обнаружите проблему, которую я не заметил, буду благодарен
эм. значение $header с устаревшими данными будет записано поверх свежих данных. м?
да, но ничего страшного не будет. в любом случае при получении данных из кеша, необходимо проверять что данные реально получены. Еще и потому что в любом случае они могут проэкспайрится или исчезнуть из-за глюка на сервере.
если данные могут быть потеряны из-за недостатков реализации — значит это повод задуматься о том, что эта реализация не айс. (мягкий намёк на теги, в миллионный раз).
данные не могут быть потеряны. с чего вы взяли?
угу. поторопился. был неправ.
дело в том, что в реализации с тэгами, всегда необходимо делать две выборки, и всегда необходимо выбирать данные из кэша. в моей же реализации мы всегда выбираем только кешхеадер, и по нему и только по нему определяем, надо ли выбирать основные данные (которые могут быть немаленькими, а это расходы памяти) или не надо. То есть, мой подход значительно менее ресурсоемкий как по использованию памяти, так и по количеству чтений из кеша, так и по количеству операций.

да, есть одна проблема. дело не в потерях данных, а в том что если вдруг два скрипта, параллельно обновляют кеш, то может случится ситуация, когда один из них удалил некую группу, а второй тут же записал данные, в которых эта группа не удалена. Но я писал выше что приведенный код несовершенен. Данная проблема решается
1. Разнесением кешхеадера. Сейчас все хранится под одним ключем 'cacheheder', но это не очень опитмально. Надо бы сделать не один корень, а несколько, по первым составным частям ключа. Тогда и запись будет более распределенной, то есть несколько скрипотов могут писать в кеш, не мешаю друг другу.

2. Можно добавить систему блокировок, которая исключит оставшийся шанс конфликта двух записей.

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

Но в любом случае, самая большая опасность состоит только в том, что в некоторых ситуациях может оказаться что некоторые данные не обновлились, хотя они были изменены. Но в реальности шанс такого стечения обстоятельств достаточно мал. В конце концов, мы не паримся насчет использования MyISAM в львиной доле наших проектов, хотя там такие ситуации тоже возможны. Но мы как то обходимся без транзакций.
>дело в том, что в реализации с тэгами, всегда необходимо делать две выборки, и всегда необходимо выбирать данные из кэша. в моей же реализации мы всегда выбираем только кешхеадер, и по нему и только по нему определяем, надо ли выбирать основные данные (которые могут быть немаленькими, а это расходы памяти) или не надо. То есть, мой подход значительно менее ресурсоемкий как по использованию памяти, так и по количеству чтений из кеша, так и по количеству операций.

1. При использовании тегов сначала проверяется, есть ли данные с такими тегами в кеше (test_tags). Если нет — ничего не читаем из кеша. Соответственно — не всегда 2 запроса.
2. У Вас тоже 2 запроса — сначала кешхеадер, потом данные. Чем отличается от того, что я написал выше?

>В конце концов, мы не паримся насчет использования MyISAM в львиной доле наших проектов, хотя там такие ситуации тоже возможны. Но мы как то обходимся без транзакций.

Меня это всегда напрягало, поэтому использую, преимущественно, InnoDB.
1. То же самое и у меня. Если в кешхеадере нет данных, из кеша не читаем.
2. Отличия в том, что в реализации с тегами может быть такая ситуация, при которой происходит чтение тэгов (1 операция), получение данных из кеша (2 операция) и после этого выясняется что данные устарели. В моем случае всегда можно определить устарели ли данные только на основе информации из кешхеадера.

>Меня это всегда напрягало, поэтому использую, преимущественно, InnoDB.

Это уже параноя.
>Отличия в том, что в реализации с тегами может быть такая ситуация, при которой происходит чтение тэгов (1 операция), получение данных из кеша (2 операция) и после этого выясняется что данные устарели. В моем случае всегда можно определить устарели ли данные только на основе информации из кешхеадера.

Вообще, при чтении тегов сразу определяется версия и «годность» данных ;)

>Это уже параноя.

Это привычка. Осталась в наследство от Delphi. И считаю, что привычка хорошая ;).
>Вообще, при чтении тегов сразу определяется версия и «годность» данных ;)

Поподробнее ка, плиз.

>Это привычка. Осталась в наследство от Delphi. И считаю, что привычка хорошая ;).

Не понимаю причем тут Дэлфи. Я тоже раньше плотно на нем писал, но почему то привычки такой нет, зато есть чувство здравого смысла, и понимание того когда оно надо а когда нет.
>Поподробнее ка, плиз.

Упс, ошибочка… Проверяется только версия. Но, думаю можно расширить на время:

причем тут время? речь то не о времени жизни кеша, а о том что данные были изменены и от этого утарели. а проверить это можно только выбрав сами данные и сравнив их версию со значением тэга. в моем же случае выбирать данные необходимости нет.
>а проверить это можно только выбрав сами данные и сравнив их версию со значением тэга.

Да не надо получать сами данные. У тегов тоже есть версии ;).

>Не понимаю причем тут Дэлфи. Я тоже раньше плотно на нем писал, но почему то привычки такой нет, зато есть чувство здравого смысла, и понимание того когда оно надо а когда нет.

Верно. Здравый смысл — это применять транзакции там, где работают несколько запросов как одно целое. На Delphi очень много работал с базами — вот и осталась привычка использовать транзакции там, где может возникнуть разрыв связей.
повторяю вопрос еще раз, как по одному только значению тэга можно понять надо ли выбирать данные?
в веб-программировании ситуаций когда несолько запросов работают как единое целое несравнимо меньше чем единичных запросов. так же как и ситуаций конкурентного доступа к ресурсам. таким образом «преимущественно, InnoDB» это параноя, ибо если исходить из реалий то необходимость использования innoDB по определению намного меньше в большинстве веб-приложений.
а да, я и не говорил что с тэгами было бы хуже, но, если не ошибаюсь, то тогда, когда этот подход был применен на фотофайле (более двух лет назад), реализации тэгов еще небыло.
Эээ… А смысл тогда в плоском кэшировании, если всё равно руки тянутся задеревить это?
Смысл все-таки в удобстве… хоть чуть-чуть по сравнении с совсем уж плоским кешированием.

К тому же кешарование в памяти — для быстроты доступа к данным, что ведь совсем не исключает желания группировать элементы.
memcached устроен так, что он совершенно не тратит ресурсы на поиск данных, другими словами, скорость поиска нужного значения не зависит от количества данных в memcached.
Этто я подразумеваю.

Но допоперация поиска здесь настораживает.

Время оно не резиново.
Меня больше настораживает другое, что я описал в комменте ниже.
Как бы допоперация поиска стоит не так много. Тот же механизм блокировок через memcached чего стоит ))) Это не жалко, да и времени не так много займет. А вот передача пожирневшего «кешхеадер» будет стоить достаточно дорого :) Не столько процессорного времени, сколько iowait. А это может оказаться очень неприятно )
скажите, приминительно к вашему проекту сколько будет весить кешхеадер? Это же не сложно посчитать, достаточно построить хеш из используемых в проекте ключей, и серилизовать его.
Ну судя по графикам во всех мемкешах лежит что-то около 7М ключей. Это примерно половина всех сущностей, вторая половина, видимо, не востребована )
Строить хеш совершенно не интересно )
7м только ключей, без данных? И кто-то тут еще говорит об эффективности? Что за проект, если не секрет?
Онлайн игра Дозоры. У нас порядка 20М сущностей. От них никуда не денешься, все держим в мемкешах.
ну вероятно для онлайн игр то что я тут описал негодится. я не очень знаком со спецификой онлайн игр. Но вот на том же фотофайле было около 40М сущностей (сейчас гораздо больше), но проблем никаких небыло. Я думаю что ресурсы подобные фотофайлу на порядок распростаненее ресурсом типа онлайн-игры.

P.S. И все таки меня терзают смытные сомнения по поводу эффективности хранения такого количества сущностей в мемкеше. Ну да ладно.
Что такое сущность на фотофайле?

У нас же не один демон мемкеша :) Для каждого типа сущности свой кеш, или даже несколько кешей. Сейчас у нас 20 мемкешей. Так что там все нормально. А держать все в мемкешах просто приходится. От этого никуда не денешься.
Т.е. вы предлагаете хранить структуру, которая помнит о всех объектах, хранящихся в кеше?
А если структура вырастет? По личному опыту знаю, что если в memcached класть данные размером порядка 1Мб, то это чревато частыми ошибками записи (причем почему-то больше записи) или чтения этих данных из кеша. К тому же передавать мегабайт данных по сети это далеко не мгновенно (если кеш находится на другой машине).
Иными словами если ваш «кешхеадер» разростется, это приведет к тормозам, которые будет трудно найти :)

Все сказанное мной относится к очень нагруженному проекту. На не очень больших нагрузках этого может и не случаться.

P.S.: если memcached начинает вытеснять данные, это сигнал, что в архитектуре допущен косячок :) Это не критично, но лучше такого не далать. Хотя бы из чувства прекрасного )))
PPS: Если у вас достаточно серьезный проект и вам нужен специфический функционал, то лучше будет взять исходники memcached и дописать то, что необходимо. Оно будет того стоить )
+1

Вот что-то такое у меня тоже имеется в мыслях.

С архитектурой где-то косяк явно.
повторяю, подобная архитектура работала без проблем на photofile.ru, одном из самых высоконагруженных фотохостингов рунета. Конечно же можно представить себе и более нагруженные проекты, но все таки кешхеадер размером в мегабайт мне очень сложно себе представить.
Ну у нас в среднем 12М хитов в сутки и подобное решение вымерло бы очень быстро :) Тем более при конкурентном доступе. Даже при размере кешхеадера в 100Кб это решение оказалось бы узким местом.

Я считаю, что вы где-то в архитектуре приняли неверное решение. При обновлении того же списка комментариев, куда менее затратно обновить все необходимые значения в кеше, чем почистить кеш и подкинуть работы базе данных. Кеш обычно вводится, когда база или какой-то ресурсоемкий код оказывается узким местом. И решение задачи типа «выльем воду из чайника, чем сведем задачу к предыдущей» в данном случае выглядит странным.
Вы видимо немного спутали мою статью с самоучителем по работе с мемкеш. Тема моей статьи узкая, она рассказывает только о том, как реализовать групповое удаление данных из кеша. И только то. А то о чем вы горите, это даже не очевидно. Удалять ли данные из кеша, или менять их там, решается конкретно даже не применительно к конкретному проекту, а применительно к конкретной части конкретного проекта. И это уже абслоютно другая тема, цели освятить которую в данной статье я перед собой не ставил. Как впрочем и хак мемкешеда на тему добавления нового функционала.
между прочим размер кешхеадера от количества хитов в сутки не зависит.
dklab.ru/lib/Dklab_Cache/
те же яйца, только аналитическая сторона вопроса более глубоко рассмотрена
получился велосипед
читайте комментарии выше.

1. Моя реализация была придумана раньше
2. Моя реализация оптимальнее по памяти и количеству обращений к мемкешу
Уважаемый Роман, приветсвую от имени людей, которым Фотофайл знаком не-по наслышке.
Идея описана не совсем верно, ибо во-первых, на Фотофайле никогда не складировались все сущности в так Вами называемый «кешхеадер», а для каждого набора сущностей он строился отдельно, при необходимости. А во-вторых, в реализаии в мета-данных указывалось не только наличие данных, но и expire, что существенно ускоряло работы системы в целом.
В одном вы действительно правы — вариант из ДКЛаб с тегами появился позднее.
Ну и ради справедливости указали бы, что идея изначально не Ваша.
С уважением.
1. Я специально в примере указал что это всего лишь пример. И даже дальше, по ходу в комментариях я указал что целесообразнее разделить кешхеадер по первому ключу.

2. Я в курсе что там хранилось еще и время жизни, и даже написал что хранить там можно все что угодно. Повторяюсь, пример упрощенный.

3. Можно подробнее узнать, а чья же это, позвольте, идея? Ну как минимум моя и Антона, ибо эту реализацию мы обсуждали с ним вдвоем. Сама же реализация в коде была выполнена мной от и до.
Все же Роман, слова о том, что нужно делить мета-данные по ключам — критичны, иначе затраты на сериализацию выйдут бешенные.

Ну и время жизни- тоже не помешает, хотя от него можно конечно отойти. Для примера. Недалеко.

з.ы. А времена были интересные, да…
да, наверное не надо было ленится и все таки реализовать этот немаловажный нюанс))
Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.