Комментарии 63
Есть еще Varnish, не пробывали его?
Я не пробовал, но было бы интересно услышать отзывы или сравнение SSI+кеш от Сысоева и Varnish как прослойка между nginx и becken-ом.
Nginx + Memcached + SSI — кеширование страниц и блоков (partials)
Кеширование страниц — ускоряем сайт в 100 раз (Varnish + ESI)
2 статейки из избранного на эту тему
Кеширование страниц — ускоряем сайт в 100 раз (Varnish + ESI)
2 статейки из избранного на эту тему
Имею мнение, что рациональнее заходить с другой стороны — встраивать через ssi отдельные блоки, и кэшировать каждый блок по отдельности. Это позволяет более гибко работать с временем кэширования, и избавиться от костыля с пуржингом кэша.
IMHO, это самый прозрачный способ.
Я с Вами согласен. В данном случае каждый блок кешируется именно по отдельности, сборка блоков в готовую страницу происходит при каждом запросе к серверу. Просто алгоритм сборки настолько заоптимизирован, что этот процес отъедает очень малую долю процессорного времени.
Если fastcgi_cache написал на весь location / {} — где ж тут по-отдельности?
Возможно вы не привыкли к стилю конфтгов nginx, в данном конкретном случае в кеш не попадает «по умолчанию» ничего, т.к. время кеширования равно 0.
По какому принципу ложить в кеш указано в директиве fastcgi_cache_key $uri$is_args$args; Т.е., например, сранички /menu.php и /menu.php?key=value будут размещены в разных кеш-файлах.
Кроме того в кеше не происходит подмены ssi-инструкций. Если в index.php есть "", то в кеше эта инструкция так и остается. Подмена происходит в менент запроса и если menu.php нету сейчас в кеше то происходит обращение к бекенду и размещение в кеш только menu.php, где время размещения в кеше определяется по заголовку «Cache-control».
Объяснил как умел, если неумело, то настройте локальную копию и убедитесь в этом сами.
А очистка кеша нужна для того что указана инструкция fastcgi_cache_use_stale, если ваш бекенд сгенерит ошибку то она не будет показана, абудет взята устаревшая копия с кеша. Ну если устаревшей копии в кеше нет, только тогда можно увидеть сбой.
Но если запрашивается сраничка index.php, menu.php,… то в кеше создается отдельная страничка
По какому принципу ложить в кеш указано в директиве fastcgi_cache_key $uri$is_args$args; Т.е., например, сранички /menu.php и /menu.php?key=value будут размещены в разных кеш-файлах.
Кроме того в кеше не происходит подмены ssi-инструкций. Если в index.php есть "", то в кеше эта инструкция так и остается. Подмена происходит в менент запроса и если menu.php нету сейчас в кеше то происходит обращение к бекенду и размещение в кеш только menu.php, где время размещения в кеше определяется по заголовку «Cache-control».
Объяснил как умел, если неумело, то настройте локальную копию и убедитесь в этом сами.
А очистка кеша нужна для того что указана инструкция fastcgi_cache_use_stale, если ваш бекенд сгенерит ошибку то она не будет показана, абудет взята устаревшая копия с кеша. Ну если устаревшей копии в кеше нет, только тогда можно увидеть сбой.
Но если запрашивается сраничка index.php, menu.php,… то в кеше создается отдельная страничка
Там хабракат кое-что вырезал, в скобочках было <!--# include virtual=«menu.php» -->
Мама, роди меня обратно…
Я как бы так помягче сказать, использую nginx в продакшне уже года четыре. Примерно на 800-та серверах. Зачастую, с собственными патчами. С трафиком в пределе около 30к rps на nginx.
Но это так, к слову.
Собственно, я хотел обратить внимание на то, что существенно дешевле не делать кэш для всего с нулевым таймаутом, а кэшировать только те куски, которые вставляются через ssi. Чтобы не строить кэш-кэй по целой простыне параметров. Чтобы не городить огород с use_stale.
Это позволит также избавиться от «если ваш бекенд сгенерит ошибку». Можно перехватить ошибку бэкэнда для каждого отдельного блока.
Я как бы так помягче сказать, использую nginx в продакшне уже года четыре. Примерно на 800-та серверах. Зачастую, с собственными патчами. С трафиком в пределе около 30к rps на nginx.
Но это так, к слову.
Собственно, я хотел обратить внимание на то, что существенно дешевле не делать кэш для всего с нулевым таймаутом, а кэшировать только те куски, которые вставляются через ssi. Чтобы не строить кэш-кэй по целой простыне параметров. Чтобы не городить огород с use_stale.
Это позволит также избавиться от «если ваш бекенд сгенерит ошибку». Можно перехватить ошибку бэкэнда для каждого отдельного блока.
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
Структура старницы
Збойный блок
Поправьте, глаза режет.
Збойный блок
Поправьте, глаза режет.
Че за херня? Тема: Кеширование блоков с помощью nginx, а в статье уже рассказывается как его заинсталить и как заинсталить РНР, че за бред?
Поправьте, бога ради, окончания «тся» и «ться».
Не рассматривали ли вы такой случай, когда сайт реализован на каком-то относительно тяжелом фреймворке (для которого время «разогрева» сравнимо или даже превышает время создания содержимого блока), и при этом страница содержит более одного блока с нулевым или близким к нулю временем жизни? Получается, что может возникнуть ситуация, когда время двух запросов к бэкенду за содержимым некэшируемых блоков превысит время создания всей страницы без использования кэша.
В любом деле нужно действовать без фанатизма. Я с Вами согласен, что в таком случае все переводить на блоки нельзя.
Вобще-то можно, частично, неужели все блоки должны быть актуальны? Посто каркас страницы кешировать уже не получится, а вот ленту новостей, курсы валют, блок с счетчиками/информерами,… можно поробовать.
Вобще-то можно, частично, неужели все блоки должны быть актуальны? Посто каркас страницы кешировать уже не получится, а вот ленту новостей, курсы валют, блок с счетчиками/информерами,… можно поробовать.
Способ слишком не гибкий — применяли уже кое-что подобное.
Почему? Потому что могут быть принципиально не кэшируемые блочки: те что зависят от текущего пользователя, например, «Спасибо, что заглянули, %username%! У вас %msg_count% новых сообщений». Каждый такой блочок будет выражаться в запросе к backend-у. Допустим таких блочков у нас 5 (вполне возможная ситуация: приветствия, формы, контролы над своими сообщениями и т.п.), это означает, что на каждую страницу на нужно делать 5 запросов к backend-у, пусть все они будут простыми, но с каждого мы получим оверхед сети, fastcgi запроса/разбора, проверки текущего пользователя. В общем, ужасно.
Куда эффективнее да ещё и гибче разруливать такие вещи на самом backend-е
Почему? Потому что могут быть принципиально не кэшируемые блочки: те что зависят от текущего пользователя, например, «Спасибо, что заглянули, %username%! У вас %msg_count% новых сообщений». Каждый такой блочок будет выражаться в запросе к backend-у. Допустим таких блочков у нас 5 (вполне возможная ситуация: приветствия, формы, контролы над своими сообщениями и т.п.), это означает, что на каждую страницу на нужно делать 5 запросов к backend-у, пусть все они будут простыми, но с каждого мы получим оверхед сети, fastcgi запроса/разбора, проверки текущего пользователя. В общем, ужасно.
Куда эффективнее да ещё и гибче разруливать такие вещи на самом backend-е
почитайте доки по nginx ssi. там есть поддержка переменных и выражения. так что при должном старании, можно и это сделать. я так понял, автор хотел только поверхностно ознакомить с темой поэтому и не рассмотрел этот аспект.
Причём тут поддержка переменных и выражения?
Мне нужно прочитать сессию пользователя из, скажем, редиса, запросить сколько у него сообщений ещё откуда-нибудь (PostgreSQL) и вывести соответствующую фразу. ngnix же это за меня не сделает?
Или, например, мы показываем список постов, для текущего пользователя нужно показать кнопки редактирования рядом с его постами, что же мне кэшировать этот список постов отдельно для каждого юзера?
Мне нужно прочитать сессию пользователя из, скажем, редиса, запросить сколько у него сообщений ещё откуда-нибудь (PostgreSQL) и вывести соответствующую фразу. ngnix же это за меня не сделает?
Или, например, мы показываем список постов, для текущего пользователя нужно показать кнопки редактирования рядом с его постами, что же мне кэшировать этот список постов отдельно для каждого юзера?
Вверху страницы делается одна ssi-вставка типа /usersettings/, которая кешируется по сессионной куке uid.
Эта вставка выдет список из set var с id постов (последних N постов) юзера (и любых других его данных).
Ниже, при выводе списка для каждого поста с помошью ssi if проверяем существование переменной с id поста среди списка постов юзера. Внутри каждого if — кнопка.
И не забываем про internal для локейшена /usersettings/ и параметр wait для его вставки.
Еще можно для него указать таймаут в несколько секунд, чтобы все хоть как-то работало, когда база сдохнет.
Эта вставка выдет список из set var с id постов (последних N постов) юзера (и любых других его данных).
Ниже, при выводе списка для каждого поста с помошью ssi if проверяем существование переменной с id поста среди списка постов юзера. Внутри каждого if — кнопка.
И не забываем про internal для локейшена /usersettings/ и параметр wait для его вставки.
Еще можно для него указать таймаут в несколько секунд, чтобы все хоть как-то работало, когда база сдохнет.
получаем сессию отдельным блоком, на результат накладываем xslt, который раскидает данные сессии по документу.
Во-первых, это гемор, во-вторых xslt — это не так уж быстро, в третьих остаются блочки некэшируемые по другим причинам: число сообщений у юзера, статус онлайн кого-нибудь, просто часто обновляющаяся инфа, в-четвёртых, libxml/libxslt текут, в-пятых, чтобы делать xsl-трансформацию нужно чтобы ssi-скрипты выдавали валидный xml.
Ну и в конце концов, что у нас получится? Бекэнд со своим движком и какими-то шаблонами (предположительно), ssi-шаблончики, xsl-трансформации. жуткий зоопарк.
Ну и в конце концов, что у нас получится? Бекэнд со своим движком и какими-то шаблонами (предположительно), ssi-шаблончики, xsl-трансформации. жуткий зоопарк.
1. это ни разу не гемор. гемор — это писать тучи сси-ифов
2. и не так уж и медленно.
3. какая разница по каким причинам они не кэшируются?
4. откуда такие данные? это ведь не какие-то левые пропиетарные библиотеки.
5. это так сложно выдавать валидный xml?
а зачем нам «какие-то шаблоны», если мы всё-равно накладываем xslt? ;-) пусть движок отдаёт чистый xml, ssi объединяет несколько xml-ек в одну и xslt приводит это дело к удобочитаемому виду. кстати, nginx случайно не поддерживает xi:include?
2. и не так уж и медленно.
3. какая разница по каким причинам они не кэшируются?
4. откуда такие данные? это ведь не какие-то левые пропиетарные библиотеки.
5. это так сложно выдавать валидный xml?
а зачем нам «какие-то шаблоны», если мы всё-равно накладываем xslt? ;-) пусть движок отдаёт чистый xml, ssi объединяет несколько xml-ек в одну и xslt приводит это дело к удобочитаемому виду. кстати, nginx случайно не поддерживает xi:include?
1. SSI + XSLT + шаблоны в бэкенде (без последних если используем только xslt) шаблоны двух видов — гемор. xslt сам по себе не самый удобный шаблонизатор.
3. Такая разница, что если блок не кэшируется принципиально, то придётся запрашивать его с бекэнда каждый раз, и если таких блоков больше одного, то вся эта солянка теряет смысл. И даже если один, она становится очень сомнительной.
4. Тестировали, некоторые трансформации текут. Возможно, если просто подсовывать значения, то с этим не столкнёшься.
5. Намного сложнее, чем html, любой неэкранированный символ, любая неопредённая entity, неправильный utf символ и всё, весь документ сломался.
3. Такая разница, что если блок не кэшируется принципиально, то придётся запрашивать его с бекэнда каждый раз, и если таких блоков больше одного, то вся эта солянка теряет смысл. И даже если один, она становится очень сомнительной.
4. Тестировали, некоторые трансформации текут. Возможно, если просто подсовывать значения, то с этим не столкнёшься.
5. Намного сложнее, чем html, любой неэкранированный символ, любая неопредённая entity, неправильный utf символ и всё, весь документ сломался.
1. уж по удобней, чем большинство
3. одним запросом можно получить все некэшируемые блоки
4. багрепорт конечно же не написали?
5. любой баг вылезает сразу, а не когда его найдёт кулхацкер. это плохо?
3. одним запросом можно получить все некэшируемые блоки
4. багрепорт конечно же не написали?
5. любой баг вылезает сразу, а не когда его найдёт кулхацкер. это плохо?
1. Не используйте большинство, используйте удобный.
3. Почему тогда просто не посчитать эти блоки на бекэнде всунуть их в страницу точно также как нгинкс, подтянуть что-то из кеша, тоже всунуть и выдать страницу?
4. Я писал другой багрепорт для libxslt раньше, понял, что всем похуй.
5. Не сразу, а когда возникнет такая ситуация, и в такой ситуации у тебя тупо перестанет отображаться вся страница.
3. Почему тогда просто не посчитать эти блоки на бекэнде всунуть их в страницу точно также как нгинкс, подтянуть что-то из кеша, тоже всунуть и выдать страницу?
4. Я писал другой багрепорт для libxslt раньше, понял, что всем похуй.
5. Не сразу, а когда возникнет такая ситуация, и в такой ситуации у тебя тупо перестанет отображаться вся страница.
1. это о чём речь?
3. идея сабжа как раз и заключается в том, чтобы не изобретать велосипед, а воспользоваться кэшированием энжиникса.
4. м… печальненько.
5. лучше ничего не показать, чем показать xss
3. идея сабжа как раз и заключается в том, чтобы не изобретать велосипед, а воспользоваться кэшированием энжиникса.
4. м… печальненько.
5. лучше ничего не показать, чем показать xss
1. Выбирайте на свой вкус, мне, например, нравится jinja2.
3. Если уж говорить о велосипедах, то скорее идея сабжа «а вот есть ещё такой быстрый велосипед». Но есть, то и дургие, ничего изобретать не надо.
5. Да там нет никакой xss, данные могут и не от пользователей браться, в конце концов. Просто если заворачивать данные в xml простой конкатенацией строк, то неизбежно будешь ловить такие баги время от времени, а как-то хитрее уже медленнее. Вообще, необходимость все данные заворачивать в xml не особо удобна.
Я не говорю же, что такой подход нельзя использовать, я говорю, что он негибкий, а значит для каких-то типов сайтов будет неэффективен, неудобен и/или порождать кучу извращений, чтобы втиснутся в рамки.
3. Если уж говорить о велосипедах, то скорее идея сабжа «а вот есть ещё такой быстрый велосипед». Но есть, то и дургие, ничего изобретать не надо.
5. Да там нет никакой xss, данные могут и не от пользователей браться, в конце концов. Просто если заворачивать данные в xml простой конкатенацией строк, то неизбежно будешь ловить такие баги время от времени, а как-то хитрее уже медленнее. Вообще, необходимость все данные заворачивать в xml не особо удобна.
Я не говорю же, что такой подход нельзя использовать, я говорю, что он негибкий, а значит для каких-то типов сайтов будет неэффективен, неудобен и/или порождать кучу извращений, чтобы втиснутся в рамки.
1. бугога х))) спасибо, такого мне не надо
3. но тогда у нас не получится map-reduce архитектуры
5. не надо заворачивать данные в xml конкатенацией строк. это вредная привычка. и именно благодаря ей xss и просачивается.
3. но тогда у нас не получится map-reduce архитектуры
5. не надо заворачивать данные в xml конкатенацией строк. это вредная привычка. и именно благодаря ей xss и просачивается.
3. Захочешь — получиться, не захочешь — сделаешь такую какую захочешь.
5. Чем-то приходиться жертвовать ради скорости, чтобы не было xss достаточно проверять данные на входе.
5. Чем-то приходиться жертвовать ради скорости, чтобы не было xss достаточно проверять данные на входе.
Кстати, вопрос на засыпку. Вы сами-то использовали такое кэширование с ssi?
простите за глупый вопрос. а как нгикс понимает что див кешировать, а не Спан? можно для примеру кусок пхп кода, чтоб понять как страница на пхп выглядит.
nginx парсит SSI-инструкции, ему неважно какой кусок html вы упаковали в блок. В статье есть ссылка на исходный код linux.ria.ua/SsiBlocks/. Если в коде не разберетесь пишите.
я однажды от скуки померял сайт на ssi, лежащий на локалхасте, утилитой ab и обнаружил, что медленнее Server Side Includes что-то еще поискать надо! как я понял, он при каждом инклюде форкает новый процесс апача/nginx, а эта операция в юниксе чрезвычайно затратная и по времени, и по памяти
Только что проверил сабж (ваш пример, который, как я понял, особо ничего и не делает) и свой собственный сайт, на тяжелом движке с большим количеством запросов к базе, к тому же на хостинге в другой стране, — так и есть:
ваш сайт
HTML transferred: 3109309 bytes
Requests per second: 143.95 [#/sec] (mean)
Time per request: 69.468 [ms] (mean)
Time per request: 6.947 [ms] (mean, across all concurrent requests)
Transfer rate: 462.66 [Kbytes/sec] received
мой
HTML transferred: 24322000 bytes
Requests per second: 226.20 [#/sec] (mean)
Time per request: 44.209 [ms] (mean)
Time per request: 4.421 [ms] (mean, across all concurrent requests)
Transfer rate: 5452.79 [Kbytes/sec] received
ваш сайт
HTML transferred: 3109309 bytes
Requests per second: 143.95 [#/sec] (mean)
Time per request: 69.468 [ms] (mean)
Time per request: 6.947 [ms] (mean, across all concurrent requests)
Transfer rate: 462.66 [Kbytes/sec] received
мой
HTML transferred: 24322000 bytes
Requests per second: 226.20 [#/sec] (mean)
Time per request: 44.209 [ms] (mean)
Time per request: 4.421 [ms] (mean, across all concurrent requests)
Transfer rate: 5452.79 [Kbytes/sec] received
nginx новый процесс не форкает.
при каждом инклюде форкает новый процесс апача/nginx
nginx устроен по другому
не всегда в случае сбоя нужно показывает кэшированную версию. зачастую требуется заглушка или хотябы ремарка о том, что эти данные могут быть не актуальны…
а ещё лучше делать так: habrahabr.ru/blogs/client_side_optimization/90481/
а ещё лучше делать так: habrahabr.ru/blogs/client_side_optimization/90481/
«There are only two hard problems in Computer Science: cache invalidation and naming things.» Phil Karlton
наткнулся случайно,
про такую возможность писал пять лет назад
habrahabr.ru/post/109050
а вообще было интересно почитать, спасибо
про такую возможность писал пять лет назад
habrahabr.ru/post/109050
а вообще было интересно почитать, спасибо
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Кеширование блоков с помощью nginx