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

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

Всегда преклоняюсь перед теми, кто сумел прикрутить что-то одно к чему-то другому, да так, что это никому раньше в голову не приходило, плюс это бы работало и притом элегантно и эффективно!
---
Сорри, если сумбурно изложил мысль => ночь+усталость
Всё это давно документировано и ключевое "что-то" здесь все-таки nginx, а то что у него есть такие лепешки стыдно не знать.
Хайлоад, доклад майлрушников - там это все описано
На хайлоаде не был, к сожалению. Идея у меня родилась "изолированно", но на оригинальность я не претендовал. Просто на хабре ничего на эту тему не нашел, вот и решил статью набросать.
А где можно этот доклад прочитать?
а где можно скачать материалы с HL2007 ? неужели только видео искать на рутубе, которого уже вроде и нет ? а презентации, доклады не остались ни в каком виде ?
я вот прямо сейчас пишу статью с разбором собственных конфигов nginx+Apache. Выложу в течение дня, наверное
Будет интересно почитать!
Успешно используем данную практику на download(dot)ru.
Есть еще одна небольшая хитрость в протаскивании в этом отдельном запросе ява-сриптик, который вешаем на onload. Это позволяет изменять любое содержание закешированной страницы. Хотя наверное есть и более элегантные решения нежели onload.
Боюсь, что на по-настоящему динамических сайтах (например, напичканных ajax'ом) нельзя кэшировать не только блок авторизации, но и почти все элементы страницы - кнопочки с числом комментариев, "добавить в избранное", "присоединиться к блогу" и т.д. Если же сайт состоит почти только из статических элементов, то писать контент в мемкэш или на жёсткий диск - разница невелика (да-да, я знаю, что ОП работает быстрее, но я думаю, что в данном случае разница будет ничтожной).

А потом: а Вы уверены, что последовательность SSI-запросов к нескольким блокам на странице будет работать быстрее, чем один цикл отработки кода, генерящего все эти блоки разом? Несколько SSI-запросов - это, как минимум, несколько одинаковых циклов инициализации кода, т.е., например, выгрузка сессии из базы, авторизация пользователя и тому подобные вещи, которые для 10 SSI-блоков будут вызваны 10 раз. Ох не факт, что это будет эффективнее...

К тому же шаблонизаторы в нормальных ЯП работают по производительности не хуже, чем nginx в обработке SSI-шаблонов, а то и лучше, потому что шаблоны можно кэшировать на уровне кода.

Так что, ИМХО, Вы переизобретаете колесо с одним лишь изменением: оно немного квадратное :).
Боюсь, что на по-настоящему динамических сайтах (например, напичканных ajax'ом) нельзя кэшировать не только блок авторизации, но и почти все элементы страницы - кнопочки с числом комментариев, "добавить в избранное", "присоединиться к блогу" и т.д. Если же сайт состоит почти только из статических элементов, то писать контент в мемкэш или на жёсткий диск - разница невелика (да-да, я знаю, что ОП работает быстрее, но я думаю, что в данном случае разница будет ничтожной).

Вы правы, данный подход применим для "не очень динамических" сайтов.
Но идея здесь не в том, чтобы всеми силами записать данные в мемкеш непонятно зачем.
Идея в том, чтобы nginx максимально справлялся с обработкой запросов сам, дергая Apache только тогда, когда другого выхода не будет.
А потом: а Вы уверены, что последовательность SSI-запросов к нескольким блокам на странице будет работать быстрее, чем один цикл отработки кода, генерящего все эти блоки разом? Несколько SSI-запросов - это, как минимум, несколько одинаковых циклов инициализации кода, т.е., например, выгрузка сессии из базы, авторизация пользователя и тому подобные вещи, которые для 10 SSI-блоков будут вызваны 10 раз. Ох не факт, что это будет эффективнее...

Не уверен. Более того, я уверен, что 10 SSI-инклюдов будут работать медленнее одного самого обыкновенного запроса к Apache при прочих равных условиях. Что же делать? Не использовать данный подход бездумно. Если на странице такое кол-во динамических блоков, то её не имеет смысла кэшировать вообще, либо стоит использовать более сложные алгоритмы кэширования, но всегда отдавать контент через Apache/PHP.
К тому же шаблонизаторы в нормальных ЯП работают по производительности не хуже, чем nginx в обработке SSI-шаблонов, а то и лучше, потому что шаблоны можно кэшировать на уровне кода.

А вот тут мне тяжело согласиться. Реальных цифр у меня на руках нет, но что-то подсказывает мне, что реализация SSI в nginx утрет нос любому шаблонизатору в плане производительности. Особенно это касается шаблонизаторов на PHP, которые будут работать по определению значительно медленнее, даже при включенном кэшировании байткода.
Так что, ИМХО, Вы переизобретаете колесо с одним лишь изменением: оно немного квадратное :).

Вполне возможно... Утешает только, что, оказывается, не один я такой наивный - ребята из мейл.ру были раньше ;)
Окей, а в каких же тогда случаях этот подход будет выгодным? Статическая страница с одним динамическим блоком? Ну для этого есть SSI без всякого мемкэша...

Что касается скорости шаблонизаторов, советую почитать вот эту статью. Отлично потоптались по тем, кто до сих пор думает, что шаблонизатор как таковой может быть причиной затыков по скорости - то же общение с БД занимает в стотыщьмильонов раз больше времени.

На ребят из мэйл.ру же я не стану ориентироваться и Вам не советую :) - конечно, пока не узнаю этих людей лично. Т.к. некоторых я, к сожалению, знаю - и они меня, мягко говоря, не впечатляют.
Каюсь, как я ниже уже писал, недостаточно хорошо подготовился к данной теме.
Есть один важный момент, который упустил я, но озвучили мейлрушники - эти SSI-инклюды не обязательно должен обрабатывать один сервер. Нагрузку можно разделить на кластер, в котором один сервер отдает первый блок, второй сервер - второй блок и т.д.

Кроме того, данный подход дает большую гибкость при управлении устареванием кэшированных блоков. Например, У нас есть страница хабрастатьи. Саму статью можно закэшировать "навсегда", но слева от неё есть блок "Прямой эфир", которую можно кэшировать только на одну минуту, например. Вынеся "Прямой эфир" в отдельный инклюд, мы можем установить у него собственный лайфтайм, по истечению которого он будет абсолютно прозрачно перегенерирован. При этом сама страница статьи в мемкэше вообще не изменится.
...но слева от неё...

Пардон, справа.
Насчёт распределения нагрузки - пожалуй, соглашусь. Хотя я всё же слабо себе представляю нагрузку, которая заставила бы разносить разные части страницы (!) на несколько серверов.

Что же касается устаревания кэша, то я бы лично не стал париться по поводу удаления устаревших данных в срок, а действовал бы от обратного: заменял бы содержимое блока в кэше только тогда, когда данные в нём меняются, а не автоматически раз в минуту. Например, добавился новый пост - сразу обновили запись в кэше. К слову, статьи про такую практику я читал ещё в самой моей молодости как веб-программиста - где советовали кэшировать страницы в виде статических HTML-файлов и "перегенерять" их при изменении содержимого.
Да-да, мне это тоже знакомо :)
Просто вот взять ту же ленту "Прямого эфира" с Хабра... на скольких страницах она есть?
Имеет ли смысл перегенерять все эти страницы (фактически, все страницы Хабра) каждый раз, когда эта лента меняется? По-моему, тут как раз больше подойдет моё решение.
Можно сделать более бронебойную конструкцию из динамического и статического кешей. Жаль нулевая кармане позволяето написать про это в блог :)
Есть, кстати очень интересная проблема при любой перегенерации страниц на сильнонагруженных динамичных сайтах
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
Что касается скорости шаблонизаторов, советую почитать вот эту статью.

Простите, а что за статья?
Чорт, отрицательная карма почикала теги... Вот ссылка: http://www.codeirony.com/?p=9
НЛО прилетело и опубликовало эту надпись здесь
А SSI тут причём? С таким же успехом можно т.н. «основной контент страницы» кэшировать на уровне кода, который и будет обслуживать запросы…
Основная выгода от использования nginx — это экономия ресурсов.
Если у нас есть такая возможность, стоит отдавать контент средствами только nginx, не поднимая ресурсоёмкий Apache и PHP.
Ну так в предложенном варианте всё равно часть контента, которая забирается при помощи SSI, будет генериться Апачом, причём не одним Апачовым запросом, а несколькими — по числу SSI-блоков. О чём я и говорил, собственно.
НЛО прилетело и опубликовало эту надпись здесь
Ну Вы говорите о кешировании как таковом — оно определённо полезно, с этим никто не спорит!
А как решить проблему с устареванием кэша? Как nginx будет определять обновилась лента новостей или нет, когда стоит обновить кэш?
Программно. Мне кажется, что программист сам должен заложить логику очистки объектов кеша при изменении данных в программном комплексе. Плюсом можно указывать lifetime, но это не основной метод.
Обычно программно это делается следующим образом, при получении запроса идет проверка не устарели ли данные, поле типа last-modified, updatedAt и т.п. сравнивается со временем генерации кэша на основании чего принимается решение либо генерировать новый кэш, либо отобразить старый... Я делаю так! А как быть здесь?
Я имел в виду влияние на кеш на этапе добавления изменения данных. Грубо говоря, при добавлении новости, сбрасывать кеш блока последних новостей. А last-modified, updatedAt я подразумевал под lifetime.
Данный метод имеет место быть, если нет иных методов изменения источника данных кроме как через сайт. А вдруг кто-то изменит данные напрямую в базе или.. еще что-нибудь... или может быть у меня развивается параноя!?
Это уже организационные вопросы. Но если будет подспорьем lifetime то если уж кто полезет ручками в базу - то рано или поздно по истечении lifetime проблемы сами разрешатся.
Угу, паранойя. Но паранойя - наш друг :)
Вообще согласен с посмотреть профиль djem, при обновлении данных программа сама сбрасывает кэш. Тут тоже не всё так просто, кто-то должен знать, по каким урлам кэшируется какой контент. Но это тема для отдельной статьи.
НЛО прилетело и опубликовало эту надпись здесь
Давно интересуюсь nginx, освоить намереваюсь, а статья убедила, что он не так страшен, как его малюют. Спасибо!
А кто это его страшным малюет? Ни разу такого не видел :)
ну у людей предвзятое мнение - раз он на хайлоадах юзается, значит в усмерть страшное что-то :).
Как было верно подмечено чуть выше - проше отдать всю страницу апачем за раз, чем часть "быстро" отдать нгиксом, а часть - апачем. При этом грузить и напрягать апачу - более чем один раз.
"Новомодные" фрейворки инициализируются дольше чем генерят сам полезный код - факт.

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

Беда нгинкса - он умеет работать только с одним мемкешедом(если я не прав - поправьте), если нужно больше - нужно извращаться.
Лично я раньше хранил такую вот "статику" на файловой системе.
Апача до загрузки фрейворка проверяет кто на нее зашел и отдает через X-Accel-Redirect этот файлик.
Сейчас я просто пропачил сам нгинкс чтобы он выполнял теже самые действия самостоятельно.
Без загрузки апача.

Не забывайте - великий нгинкс поставляется в исходных кодах. Его можно пачить!
Если есть желание и нет лени :)
НЛО прилетело и опубликовало эту надпись здесь
Да вообще-то и PHP можно как fastCGI юзать. Так что и он не будет инициализироваться при каждом запросе.
НЛО прилетело и опубликовало эту надпись здесь
ничего, вот допишет свой сервер anight и будет на ПХП улице праздник. :).
НЛО прилетело и опубликовало эту надпись здесь
Да знаем мы всё это... Просто хотелось новых адептов заманить, а вы им сразу спалили все минусы... Как теперь быть? :)
НЛО прилетело и опубликовало эту надпись здесь
да без проблем
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
незачто
Интерпретатор PHP инициализируется один раз, да. Но код всё-равно парсится каждый раз на запрос. Тут уже вступают в игру всякие кэши, которых в случае с mod_perl/mod_python не нужно.
ну хотя бы на инициализации PHP выигрываем, да и не один, а как правильно заметил Максим выше - половину раза, и каждый раз еще дополовинивает :).
Зачем "грузить и напрягать апачу - более чем один раз"?

В memcached данные заносятся внешним по отношению к nginx способом. Т.е. в принципе два варианта - кроном или генерящим скриптом. В дальнейшем при отдаче блоков nginx вообще не будет дергать апач.

PS: это мои теоретические измышления основанные на беглом просмотре доки. memcached в nginx использовать не доводилось.
Проверку наличия куки можно делать и без SSI, и даже без внутреннего perl-обработчика. Как бонус, все POST-запросы также отправляются to backend. Если куки нет, то все отдается с диска, где подпапки соответствуют путям в URL-e

set $backend 0;
location / {
  if ($http_cookie ~* "session=([^;]+)(?:;|$)" ) {
    set $backend 1;
  }
  if ($request_method = POST) {
    set $backend 1;
  }
  if ($backend = 0) {
    rewrite (.*) $1/index.html break;
  }
  if ($backend) {
    fastcgi_pass unix:/www/project/server.sock;
    break;
  }
  index  index.html;
  include  conf/fastcgi.conf;
  access_log  /logs/project.log main;
}
Мне кажется, что данный способ действенен только если у нас есть несколько серверов. Допустим, для наглядности, на страничке используется два include virtual: один для /auth, другой для /last-activity. Загрузка такой странички будет порождать минимум 3 запроса на сервер и, как мне кажется, отдать её контент классически - через один запрос будет выгоднее. В общем случае, конечно. Картина меняется, если запрос на выдачу страницы обрабатывает один сервер-маршрутизатор, а запросы /auth и /last-activity - два других. Тогда, скорее всего, будет получаться выигрыш от использования данного метода.
ну на докладе mail.ru как раз про это и говорилось, что каждый сервер был отвественный за свой кусок.
Заметка себе на будущее: надо всё же глубже копнуть самому, прежде чем такие статьи писать :)
Тоже иногда расстраиваюсь, что всё изобретено до меня было :). А вот статьи всё равно стоит писать - упорядочивает свои мысли + всё же кто-то не знал - ознакомится.
Из этих соображений и исходил, спасибо.
В сети нет записи доклада?
Их удалили с рутуба и готовят куда-то выложить - ключевые слова highload 2007 mail.ru
Спасибо! Буду ждать появления.
Почему три запроса то? Насколько я понимаю nginx отпарсит страницу и вставит куда нужно ответы от мемкеша. Один запрос к серверу?
от одного до двух :).
где второй?
первый запрос - нгинксу, он из мемкэша достал страницу с двумя инклудами, и оба их отправил на сервер - auth - надо каждый раз прогонять на бэкенде (1 запрос на него), и второй - last-activity - если нету в кэше.
Честно говоря от меня ускользает смысл инклуда блока auth. Обычно есть более подходящие блоки для этого. Вот к примеру на морде зхабра в правой колонке есть пяток блоков, которые, возможно, имеет смысл инклудить.
потому что так надо из условий задачи написанной выше, а не именно на хабре.
Почитал условия. Мне они представляются несколько нежизненными...

Теоретически есть два варианта

1. страницу брать с бакенда, а некоторые блоки внутри страницы кешировать
2. страницу кешировать, а некоторые блоки отправлять бакенду

Второй вариант мне до сего дня не приходил в голову. И он действительно генерит несколько запросов к бакенду вместо одного.

В первом же варианте будет всегда один запрос к бакенду, если бакенд озаботится тем, чтобы подсовывать содержимое блоков в мемкеш.
второй вариант намного легче расплющить в ширину, в смысле он намного легче масштабируется в ширину.
Понял. Согласен. имеет право на жизнь.
Я привел пример с auth, потому что он мне показался самым "контрастным" в плане того, что видит авторизированный и неавторизированный пользователь.

А вообще, Хабр таким способом кэшировать сложно - у него всякие "галочки" и "рейтинги" напротив каждого комментария есть, их особо не закэшируешь...
А вообще, Хабр таким способом кэшировать сложно - у него всякие "галочки" и "рейтинги" напротив каждого комментария есть, их особо не закэшируешь...

Практика показывает, что сейчас 90% проектов, которые имеет смысл кешировать именно такие. И этот способ полезен как раз для таких проектов.
Первый запрос - на страницу с инклюдсами и его нельзя не учитывать только потому, что он не к apache. Запросы /auth и /last-activity то же не обязательно должен обрабатывать апач. Их может отдавать тот же nginx + memcached.
я учитывал вопросы только к бэкенду.
НЛО прилетело и опубликовало эту надпись здесь
Да, это похоже на очень простой и эффективный прием, спасибо.
Буду ждать: практическую часть , с описанием конфигурации сервера и примерами на PHP & Zend Framework.
Спасибо.
Автор не достаточно полно раскрыл тему. Реально, Обработка 2 инклудов может выйти дороже одной обработки всей страницы.

Ускоряем авторизацию: делаем по url /cache/auth/1234/ (где 1234 — id юзера) персональный блок авторизации, который успешно пихаем в кэш, и инклудится, соответственно, страница из кэша.

И так со всем содержимым.

Интересно было бы услышать как управлять кэшем (т.е. время жизни итп), я с этим механизмом в nginx не знаком. На сколько понимаю, это вопрос memcached.
Вариант с идентификатором пользователя в урле в эту модель не вписывается, потому что сам урл (точнее SSI-инструкция) будет закэширован вместе с идентификатором на "родительской" странице.

PS: Автор старался, честно :)
Хм... Подъёб. Тогда этот способ не особо оправдан. Куда удачней закэшировать блок в шаблонизаторе.
касательно именно блока авторизации - можно заюзать javascript:
ввести cookie "username" и в зависимости от неё рисовать форму логина, либо все ссылки, присущие юзеру :)
Вижу такую проблему (может выше в комментариях она уже описывалась)

Скажем рекламные блоки (или любые зависимые от конкретного пользователя данные) - на странице их может быть несколько. Зарегеным пользователям показываем один набор рекламы, незарегеным другой. В случае с SSI получим для каждого рекламного блока свой запрос к серверу, которому придется загрузить профиль пользователя (возможно и из кэша) и загрузить рекламный блок из БД. Если делать вставку на стороне сервера - без SSI мы возможно сможем выборку рекламы для всех рекламных мест сделать одним запросом.
Проблема есть, но есть и способ обойти её, который уже озвучивали выше - один SSI-инклюд вернет кусок javascript'а, который разбросает рекламный контент по блокам.
Не везде применимо, но сама идея такого кэширования тоже применима далеко не везде.
Если на странице много динамических блоков - не стоит применять этот метод.
Допустим у нас 2 динамических блока, и для создания каждого нужна БД, т.е. будет 2 коннекта к БД? разве это эффективно???

Второй пример, мы добавили новую рюшечку, или сменили дизайн, кэш похерился...

ИМХО кэшировать надо не блоки/страницы, а данные.

P.S. хотя для новостных сайтов или портального типа, самое оно....
Допустим у нас 2 динамических блока, и для создания каждого нужна БД, т.е. будет 2 коннекта к БД? разве это эффективно???

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

Второй пример, мы добавили новую рюшечку, или сменили дизайн, кэш похерился...

Тут вы глупость какую-то сказали. В таком случае можно просто почистить кэш полностью. Он же серверный - всё в наших руках.
Тут вы глупость какую-то сказали. В таком случае можно просто почистить кэш полностью. Он же серверный - всё в наших руках.

ИМХО нет! Есди бы вы кэшировали данные то весь ваш кэш так бы и остался...
Если эти два коннекта будут делать разные бекэнд-сервера, то вполне эффективно. Суммарно нагрузка будет выше, но такая архитектура открывает двери для горизонтального масштабирования: вместо того, чтобы апгрейдить единственный сервер, можно будет взять несколько подешевле, что по соотношению цена/производительность будет эффективнее.

Предроложим у нас один сервер: nginx+php-fpm, тогда данный способ неэфективный?
ИМХО нет! Есди бы вы кэшировали данные то весь ваш кэш так бы и остался...

Наполнение (и очистка) кэша происходят программно, можно сказать "вручную". Только извлечение данных из кэша nginx выполняет автоматически. Так что очищаем без проблем.
Предроложим у нас один сервер: nginx+php-fpm, тогда данный способ неэфективный?

В таком случае этот подход можно будет использовать лишь ограниченно, для реализации "постепенного" устаревания кэшированных блоков. В таком случае, все блоки на странице должны быть статическими, но период обновления их может быть разным. Например, текст статьи не обновляется вообще никогда (до очистки кэша), а облако тэгов - раз в 10 минут, "Прямой эфир" - раз в минуту и т.д.
Опять же, применимо это будет далеко не везде.
Я делаю приблизительно так: cloud.habrahabr.ru/blog/36632/
P.S. Спасибо, что сподобили написать, давно уже собирался, но неожиданно грянул отпуск.
Много воды. Хоть кто-нибудь может привести бенчмарки «до» и «после»? Ни один из тех кто такое внедрил не описал как это повлияло на число запросов в секунду, время построения страницы и т.д.
У нас эта связка и используется
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории