Pull to refresh

Comments 63

Есть еще Varnish, не пробывали его?
Я не пробовал, но было бы интересно услышать отзывы или сравнение SSI+кеш от Сысоева и Varnish как прослойка между nginx и becken-ом.
Спасибо за ссылки.

В первой статье производительность будет падать за счет того что для работы с Memcached потребуется сетевые операции.

во второй статье мы получим скорее всего сравнимую производительность nginx-кешом.
Имею мнение, что рациональнее заходить с другой стороны — встраивать через 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,… то в кеше создается отдельная страничка
Там хабракат кое-что вырезал, в скобочках было <!--# include virtual=«menu.php» -->
Мама, роди меня обратно…

Я как бы так помягче сказать, использую nginx в продакшне уже года четыре. Примерно на 800-та серверах. Зачастую, с собственными патчами. С трафиком в пределе около 30к rps на nginx.
Но это так, к слову.

Собственно, я хотел обратить внимание на то, что существенно дешевле не делать кэш для всего с нулевым таймаутом, а кэшировать только те куски, которые вставляются через ssi. Чтобы не строить кэш-кэй по целой простыне параметров. Чтобы не городить огород с use_stale.

Это позволит также избавиться от «если ваш бекенд сгенерит ошибку». Можно перехватить ошибку бэкэнда для каждого отдельного блока.

Я с Вами согласен что схему можно селать более оптимальной, но согласитесь что при этом конфиг будет выглядеть сложнее для понимания схемы.
UFO just landed and posted this here
UFO just landed and posted this here
Можно поидее ж примонтировать часть ОП как папку Ж…
UFO just landed and posted this here
Структура старницы
Збойный блок
Поправьте, глаза режет.
«движек» туда же
Че за херня? Тема: Кеширование блоков с помощью nginx, а в статье уже рассказывается как его заинсталить и как заинсталить РНР, че за бред?

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

А если видите что-то лишнее для себя, переходите с следующему подзаголовку.

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

Вобще-то можно, частично, неужели все блоки должны быть актуальны? Посто каркас страницы кешировать уже не получится, а вот ленту новостей, курсы валют, блок с счетчиками/информерами,… можно поробовать.
Способ слишком не гибкий — применяли уже кое-что подобное.
Почему? Потому что могут быть принципиально не кэшируемые блочки: те что зависят от текущего пользователя, например, «Спасибо, что заглянули, %username%! У вас %msg_count% новых сообщений». Каждый такой блочок будет выражаться в запросе к backend-у. Допустим таких блочков у нас 5 (вполне возможная ситуация: приветствия, формы, контролы над своими сообщениями и т.п.), это означает, что на каждую страницу на нужно делать 5 запросов к backend-у, пусть все они будут простыми, но с каждого мы получим оверхед сети, fastcgi запроса/разбора, проверки текущего пользователя. В общем, ужасно.

Куда эффективнее да ещё и гибче разруливать такие вещи на самом backend-е
почитайте доки по nginx ssi. там есть поддержка переменных и выражения. так что при должном старании, можно и это сделать. я так понял, автор хотел только поверхностно ознакомить с темой поэтому и не рассмотрел этот аспект.
Причём тут поддержка переменных и выражения?
Мне нужно прочитать сессию пользователя из, скажем, редиса, запросить сколько у него сообщений ещё откуда-нибудь (PostgreSQL) и вывести соответствующую фразу. ngnix же это за меня не сделает?
Или, например, мы показываем список постов, для текущего пользователя нужно показать кнопки редактирования рядом с его постами, что же мне кэшировать этот список постов отдельно для каждого юзера?
Вверху страницы делается одна ssi-вставка типа /usersettings/, которая кешируется по сессионной куке uid.
Эта вставка выдет список из set var с id постов (последних N постов) юзера (и любых других его данных).
Ниже, при выводе списка для каждого поста с помошью ssi if проверяем существование переменной с id поста среди списка постов юзера. Внутри каждого if — кнопка.

И не забываем про internal для локейшена /usersettings/ и параметр wait для его вставки.
Еще можно для него указать таймаут в несколько секунд, чтобы все хоть как-то работало, когда база сдохнет.
получаем сессию отдельным блоком, на результат накладываем xslt, который раскидает данные сессии по документу.
Во-первых, это гемор, во-вторых xslt — это не так уж быстро, в третьих остаются блочки некэшируемые по другим причинам: число сообщений у юзера, статус онлайн кого-нибудь, просто часто обновляющаяся инфа, в-четвёртых, libxml/libxslt текут, в-пятых, чтобы делать xsl-трансформацию нужно чтобы ssi-скрипты выдавали валидный xml.

Ну и в конце концов, что у нас получится? Бекэнд со своим движком и какими-то шаблонами (предположительно), ssi-шаблончики, xsl-трансформации. жуткий зоопарк.
1. это ни разу не гемор. гемор — это писать тучи сси-ифов
2. и не так уж и медленно.
3. какая разница по каким причинам они не кэшируются?
4. откуда такие данные? это ведь не какие-то левые пропиетарные библиотеки.
5. это так сложно выдавать валидный xml?

а зачем нам «какие-то шаблоны», если мы всё-равно накладываем xslt? ;-) пусть движок отдаёт чистый xml, ssi объединяет несколько xml-ек в одну и xslt приводит это дело к удобочитаемому виду. кстати, nginx случайно не поддерживает xi:include?
1. SSI + XSLT + шаблоны в бэкенде (без последних если используем только xslt) шаблоны двух видов — гемор. xslt сам по себе не самый удобный шаблонизатор.
3. Такая разница, что если блок не кэшируется принципиально, то придётся запрашивать его с бекэнда каждый раз, и если таких блоков больше одного, то вся эта солянка теряет смысл. И даже если один, она становится очень сомнительной.
4. Тестировали, некоторые трансформации текут. Возможно, если просто подсовывать значения, то с этим не столкнёшься.
5. Намного сложнее, чем html, любой неэкранированный символ, любая неопредённая entity, неправильный utf символ и всё, весь документ сломался.
1. уж по удобней, чем большинство
3. одним запросом можно получить все некэшируемые блоки
4. багрепорт конечно же не написали?
5. любой баг вылезает сразу, а не когда его найдёт кулхацкер. это плохо?
1. Не используйте большинство, используйте удобный.
3. Почему тогда просто не посчитать эти блоки на бекэнде всунуть их в страницу точно также как нгинкс, подтянуть что-то из кеша, тоже всунуть и выдать страницу?
4. Я писал другой багрепорт для libxslt раньше, понял, что всем похуй.
5. Не сразу, а когда возникнет такая ситуация, и в такой ситуации у тебя тупо перестанет отображаться вся страница.
1. это о чём речь?
3. идея сабжа как раз и заключается в том, чтобы не изобретать велосипед, а воспользоваться кэшированием энжиникса.
4. м… печальненько.
5. лучше ничего не показать, чем показать xss
1. Выбирайте на свой вкус, мне, например, нравится jinja2.
3. Если уж говорить о велосипедах, то скорее идея сабжа «а вот есть ещё такой быстрый велосипед». Но есть, то и дургие, ничего изобретать не надо.
5. Да там нет никакой xss, данные могут и не от пользователей браться, в конце концов. Просто если заворачивать данные в xml простой конкатенацией строк, то неизбежно будешь ловить такие баги время от времени, а как-то хитрее уже медленнее. Вообще, необходимость все данные заворачивать в xml не особо удобна.

Я не говорю же, что такой подход нельзя использовать, я говорю, что он негибкий, а значит для каких-то типов сайтов будет неэффективен, неудобен и/или порождать кучу извращений, чтобы втиснутся в рамки.
1. бугога х))) спасибо, такого мне не надо
3. но тогда у нас не получится map-reduce архитектуры
5. не надо заворачивать данные в xml конкатенацией строк. это вредная привычка. и именно благодаря ей xss и просачивается.
3. Захочешь — получиться, не захочешь — сделаешь такую какую захочешь.
5. Чем-то приходиться жертвовать ради скорости, чтобы не было xss достаточно проверять данные на входе.
5. ага, типа как на хабре — каверкать любое упоминание слова javascript? x)
Кстати, вопрос на засыпку. Вы сами-то использовали такое кэширование с ssi?
Ну вот, а я гавна такого сорта уже поел, и xslt тоже.
Ты даже не понял смысла моей фразы, и при этом ещё бросаешь безосновательные ощущения.
я прекрасно всё понял.
простите за глупый вопрос. а как нгикс понимает что див кешировать, а не Спан? можно для примеру кусок пхп кода, чтоб понять как страница на пхп выглядит.
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
Я думаю твой тест может претендовать на звание «самый объективный тест в рунете», тут даже нету смысла говорить о чистоте эксперимента — результат очевиден. Ура!
nginx новый процесс не форкает.
Тем не менее, результаты удручающие.
сравнение не корректное, приложения работают в разных окружениях.
Я бы согласился с вами, если б не огромная разница в Transfer rate.
Я тут протестил, оказывается хабр работает намного медленее, чем мой собственный сайт-визитка в локалке :)
Я кажется написал, что сайт находится в другой стране, а не в локалке, ок?
Да, и это полностью сводит на нет всю объективность вашего измерения…
при каждом инклюде форкает новый процесс апача/nginx

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

а ещё лучше делать так: 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
а вообще было интересно почитать, спасибо
Sign up to leave a comment.

Articles