Lock при обновлении кеша.

lem

Новичок
Lock при обновлении кеша.

Есть скрипт, который кеширует свой вывод вот так (упрощённая конструкция):
PHP:
if(filemtime(CACHE_FILE) > MAX_CACHE_TIME) {
     $s = render...
     echo $s;
     fwrite($s, CACHE_FILE);
}
else
     readfile(CACHE_FILE);
Проблема в том, что к этому скрипту обращаются 10-20 раз в минуту, а при обновлении кеша ему приходится работать 20-30 секунд. Для того, чтобы избежать параллельного обновления кеша нужно лочить эту операцию, я делаю это созданием .lock файла.

Правильно ли это? Как делаете вы?

-~{}~ 10.02.09 13:07:

Сразу дополнительный вопрос по этой же проблеме.

Если пользователь запрашивает скрипт, кеш которого устарел, то есть два варианта:
1. Пользователю выкидывается старый кеш.
2. Пользователь ждёт, пока кеш обновится.

Я использую второй метод, но пользовател(и) может(могут) так висеть по минуте, как-то не кошерно... Пробовал с 503-й ответ с заголовком Retry-After:150 , но браузеры не делают второго запроса после 150 секунд.

Эта вторая проблема не критичная, всё-равно nginx перед апачем висит, но всё же...
 

lem

Новичок
Огромное спасибо за название и статью. В моём случае с кешем в файловой системе, получаем при обновлении кеша:
PHP:
if(filemtime(CACHE_FILE) > MAX_CACHE_TIME) {
     touch(CACHE_FILE);
     ... renew...
}
Проблема первого варианта в том, что изображение (у меня php графики рисует) может лежать необновлённым три месяца, потом его запросит пользователь, а ему старое из кеша вылезет. То есть, мне только второй вариант подходит. Есть ли третий? ;)
 

lem

Новичок
Там больше 40000 изображений. Это форумные линеечки (такая штука для женских форумов). Из этих 40К обновляются постоянно примерно 2000, раз в несколько дней ещй тысяч 10, а остальные пылятся в кеше и изредка их кто-нибудь запрашивает, и они обновляются.

То есть, по крону не получится - это часа на 4 работы сервера.
 

Gas

может по одной?
да, тогда по крону не стоит.

может лежать необновлённым три месяца, потом его запросит пользователь, а ему старое из кеша вылезет
я когда говорил про первый вариант, то имел ввиду, что _первый_ пользователь инициирует обновление кеша, ждёт и получает актуальные данные, а другие пользователи, которые зашли через секунду и кеш ещё в процессе обновления, получают старые данные, а не ждут пересчёта или инициализируют его ещё раз. Данные то, не архиважные, обновят страницу и увидят потом обновление - ничего страшного, зато быстро получли ответ и сервер не грузится понапрасну.
 

lem

Новичок
Тогда последний вопрос, что использовать: .lock или touch()?
 

SiMM

Новичок
[m]flock[/m] уже некашерен? Разумеется, не на FAT32

-~{}~ 11.02.09 08:36:

> Там больше 40000 изображений. Это форумные линеечки (такая штука для женских форумов). Из этих 40К обновляются постоянно примерно 2000, раз в несколько дней ещй тысяч 10, а остальные пылятся в кеше и изредка их кто-нибудь запрашивает, и они обновляются.

Что-то я не пойму - 40000 изображений обновляются одновременно? Иначе проблема мне кажется высосанной из пальца, если картинка обновляется ТОЛЬКО по её запросу и необходимости обновления.
 

Wicked

Новичок
Gas
а зачем наказывать первого пользователя, заставляя его ждать? Имхо ему нужно тоже отдать из кэша, а уже после этого начать долго генерировать новый кэш

-~{}~ 11.02.09 11:43:

а при обновлении кеша ему приходится работать 20-30 секунд.
сколько и каких задач включено в эти 20-30 секунд?
 

DiMA

php.spb.ru
Команда форума
> а зачем наказывать первого пользователя, заставляя его ждать?

конечно, отдаем ему кеш годовой давности и порядок

> Тогда последний вопрос, что использовать: lock() или touch()?

маразматический вопрос. Нужно использовать обе функции (вернее, fopen + flock + fwrite).
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
>при обновлении кеша ему приходится работать 20-30 секунд
генерация одной картинки занимает 20-30 секунд?!
 

lem

Новичок
DiMA
>маразматический вопрос. Нужно использовать обе функции (вернее, fopen + flock + fwrite).

Я не понимаю, зачем лочить файл, если при проверке filemtime, обновлённого тачем, параллельный клиент не станет обновлять кеш. То есть, вероятность такого очень низкая.
 

DiMA

php.spb.ru
Команда форума
> То есть, вероятность такого очень низкая.

Нормальный программист никогда не надеется на авось. А такая ситуация обязательно случится, другой скрипт влезет между if (filemtime) и touch(), из-за чего обновление кеша будет запущено параллельно 2 раза. Не хочешь делать по-человечески - твое личное дело, однако это программирование на соплях. И не афишируй свои кривые технологии в форуме :)
 

prolis

Новичок
1. Архитектура. Задача стоит - обновлять градусник раз в день (если там дни указываются), значит обновлять раз в день. Вчерашняя картинка не нужна - значит каждый день чистить всё устаревшее, а обновлённое или созданное в этот день - обновить по крону. При запросе отсутствующего "сегодняшнего" изображения - генерировать ново. Можно продумать и про параллельную генерацию.
2.Технология. Генерация изображения за 20 секунд - охотно поверю при страничном размере изображения или ручной обработке. Даже если генерация длится много больше полсекунды, можно во время лочки отдать первому запросу заглушку "Пожалуйста подождите..."
 
Сверху