Ускоряем Drupal: Pressflow + Nginx + Varnish

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

    Это мой первый опыт подобной настройки, но как будет далее видно из статистики достаточно удачно справляющийся со своей основной задачей — ускорением работы сайта. Интересно будет услышать и увидеть настройки, дополнительные материалы от всех кто сталкивался с подобными задачами, так как в рунете пока еще мало свободной и качественной информации по этой теме относительно системы Друпал.

    Довольно долго для разработки я использовал связку Drupal + Nginx с настройками сервера по умолчанию:

    server {
    listen 62.xxx.xx.xx:80;
    server_name mysite.com www.mysite.com;
    rewrite>^(/manager/.*)$>https://$host$1>permanent;
    location ~* ^/(webstat/|awstats|webmail/|myadmin/|manimg/) {
    proxy_pass 62.xxx.xx.xx:8080;
    proxy_redirect mysite.com:8080/ /;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Real-IP $remote_addr;
    }
    location / {
    proxy_pass mysite.com:8080;
    proxy_redirect mysite.com:8080/ /;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Real-IP $remote_addr;
    }
    location ~* ^.+\.(jpg|jpeg|gif|png|svg|js|css|mp3|ogg|mpe?g|avi|zip|gz|bz2?|rar)$ {
    root /home/pathto/drupal613;
    access_log /home/httpd-logs/mysite.com.access.log;
    error_page 404 = @fallback;
    }
    location @fallback {
    proxy_pass 62.xxx.xx.xx:8080;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Real-IP $remote_addr;
    }
    }




    Суть этих настроек проста — разгрузить апач и оставить на нем только php процессы, а всю статику(картинки, файлы) перекидывать на Nginx. Апач у меня настроен на 8080 порт, а Nginx на 80. Nginx на фронтенде анализируют, что запрашивает и выкидывает статические данные сам или же перекидывает все на апач. Данный подход разгружает сервер и немного повышает производительность.

    Для анализа сайта на Друпал, я использовал отличный сервис LoadImpact.com, который выкинул мне вот такой отчет:

    image

    Недолго нужно анализировать, чтобы понять, чем больше трафик на сайте, тем больше приходится ждать ответа от сервера. Это плохо. Решение я нашел в следующей связке:

    Pressflow + Nginx + Varnish



    Pressflow это дистрибутив Drupal с интегрированными усовершенствованиями производительности, расширяемости, эффективности, и тестирования.

    Кажая версия Pressflow является API эквивалентом тойже версии Drupal. Например, Pressflow 6 совместим со всеми Drupal 6 модулями. Pressflow 6 также имеет интегрированную SimpleTest систему из Drupal 7 и патч для поддержки CDN.


    Вот ссылки для скачки Pressflow:
    fourkitchens.com/pressflow-makes-drupal-scale/downloads
    launchpad.net/pressflow/+download

    Varnish это ключевое ПО для ускорения Вашего сайта.

    Varnish — это Open Source ПО, стандартизированное и требующее незначительных ресурсов.


    Ссылка для скачивания Varnish:
    www.varnish-cache.org/releases

    Идея этой связки не многим сложнее: на запрос к серверу выкидываем статику через Nginx, иначе идем за кешироваными данными к Varnish+Pressflow, и к апачу если нам нужно что-то от PHP.

    Шаг 1: Устанавливаем Pressflow

    Установка Pressflow вообщем-то ничем не отличается от установки Drupal :)
    fourkitchens.com/pressflow-makes-drupal-scale/installation

    Шаг 2: Настраиваем Pressflow

    Перейдите на mysite.com/admin/settings/performance и включите кеширование. Вот собственно и все.

    Шаг 3: Установка Varnish

    Если Вы далеки от понятий SSH и Linux, попробуйте создать запрос к своим хостерам на инсталяцию Varnish. Я использовал этот мануал под FreeBSD www.varnish-cache.org/installation/freebsd. Все достаточно просто.

    Шаг 4: Настраиваем Varnish

    Это один из самых сложных пунктов по настройке всей системы:

    1. Добавляем запуск varnish deamon и varnish log в конфигурационный файл /etc/rc.conf:
    varnishd_enable=«YES»
    varnishlog_enable=«YES»
    2. Меняем дефолтные настройки под себя varnish deamon:
    ${varnishd_enable:="NO"}
    ${varnishd_pidfile:="/var/run/${name}.pid"}
    ${varnishd_listen:=":8081"}
    ${varnishd_admin:="localhost:8090"}
    ${varnishd_backend:="localhost:8080"}
    ${varnishd_config:="/usr/local/etc/varnish/default.vcl"}
    ${varnishd_storage:="file,/usr/local/varnish.cache,1G"}
    ${varnishd_hash:="classic,16383"}
    ${varnishd_user:="www"}
    ${varnishd_group:="www"}

    Как уже упоминалось ранее, на моем сервере Nginx слушает 80 порт, а Apache 8080. Varnish же поставим на прослушку порта 8081, а перекидывать с него опять же будем на апач, тоесть 8080 порт.

    Тут:
    -varnishd_config — путь к дефолтному файлу настроек поведения Varnish
    -varnishd_storage — размер и путь к файлу кеша

    3. Настраиваем Varnish на работу с Pressflow:
    backend default {
    .host = "127.0.0.1";
    .port = "8080";
    .connect_timeout = 600s;
    .first_byte_timeout = 600s;
    .between_bytes_timeout = 600s;
    }

    sub vcl_recv {
    if (req.request != "GET" &&
    req.request != "HEAD" &&
    req.request != "PUT" &&
    req.request != "POST" &&
    req.request != "TRACE" &&
    req.request != "OPTIONS" &&
    req.request != "DELETE") {
    /* Non-RFC2616 or CONNECT which is weird. */
    return (pipe);
    }

    if (req.request != "GET" && req.request != "HEAD") {
    /* We only deal with GET and HEAD by default */
    return (pass);
    }

    // Remove has_js and Google Analytics cookies.
    set req.http.Cookie = regsuball(req.http.Cookie, "(^|;\s*)(__[a-z]+)=[^;]*", "");

    // To users: if you have additional cookies being set by your system (e.g.
    // from a javascript analytics file or similar) you will need to add VCL
    // at this point to strip these cookies from the req object, otherwise
    // Varnish will not cache the response. This is safe for cookies that your
    // backed (Drupal) doesn't process.
    //
    // Again, the common example is an analytics or other Javascript add-on.
    // You should do this here, before the other cookie stuff, or by adding
    // to the regular-expression above.

    // Remove a ";" prefix, if present.
    set req.http.Cookie = regsub(req.http.Cookie, "^;\s*", "");
    // Remove empty cookies.
    if (req.http.Cookie ~ "^\s*$") {
    unset req.http.Cookie;
    }

    if (req.http.Authorization || req.http.Cookie) {
    /* Not cacheable by default */
    return (pass);
    }

    // Skip the Varnish cache for install, update, and cron
    if (req.url ~ "install\.php|update\.php|cron\.php") {
    return (pass);
    }

    // Normalize the Accept-Encoding header
    // as per: varnish-cache.org/wiki/FAQ/Compression
    if (req.http.Accept-Encoding) {
    if (req.url ~ "\.(jpg|png|gif|gz|tgz|bz2|tbz|mp3|ogg)$") {
    # No point in compressing these
    remove req.http.Accept-Encoding;
    }
    elsif (req.http.Accept-Encoding ~ "gzip") {
    set req.http.Accept-Encoding = "gzip";
    }
    else {
    # Unknown or deflate algorithm
    remove req.http.Accept-Encoding;
    }
    }

    // Let's have a little grace
    set req.grace = 30s;

    return (lookup);
    }

    sub vcl_hash {
    if (req.http.Cookie) {
    set req.hash += req.http.Cookie;
    }
    }

    // Strip any cookies before an image/js/css is inserted into cache.
    sub vcl_fetch {
    if (req.url ~ "\.(png|gif|jpg|swf|css|js)$") {
    // This is for Varnish 2.0; replace obj with beresp if you're running
    // Varnish 2.1 or later.
    unset beresp.http.set-cookie;
    }
    }

    sub vcl_error {
    // Let's deliver a friendlier error page.
    // You can customize this as you wish.
    set obj.http.Content-Type = "text/html; charset=utf-8";
    synthetic {"
    <?xml version="1.0" encoding="utf-8"?>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    "} obj.status " " obj.response {"
    <стиль type="text/css">
    #page {width: 400px; padding: 10px; margin: 20px auto; border: 1px solid black; background-color: #FFF;}
    p {margin-left:20px;}
    body {background-color: #DDD; margin: auto;}
    </стиль>

    <х1>Page Could Not Be Loaded</х1>
    We're very sorry, but the page could not be loaded properly. This should be fixed very soon, and we apologize for any inconvenience.
    <хр /> <х4>Debug Info:</х4>
    <пре>
    Status: "} obj.status {"
    Response: "} obj.response {"
    XID: "} req.xid {"
    </пре>
    <адресс><ссылка href="http://www.varnish-cache.org/">Varnish</ссылка></адресс>



    "};
    return (deliver);
    }

    3. Настраиваем Ngnix на работу с Varnish:
    server {
    listen 62.xxx.xx.xx:80;
    server_name mysite.com www.mysite.com;
    rewrite ^(/manager/.*)$>https://$host$1>permanent;
    rewrite>^(/manager/.*)$>https://$host$1>permanent;
    location ~* ^/(webstat/|awstats|webmail/|myadmin/|manimg/) {
    proxy_pass 62.xxx.xx.xx:8080;
    proxy_redirect mysite.com:8080/ /;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Real-IP $remote_addr;
    }
    location / {
    proxy_pass 62.xxx.xx.xx:8081;
    proxy_redirect mysite.com:8081/ /;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Real-IP $remote_addr;
    }
    location ~* ^.+\.(jpg|jpeg|gif|png|svg|js|css|mp3|ogg|mpe?g|avi|zip|gz|bz2?|rar)$ {
    root /home/cross/data/www/mysite.com;
    access_log /home/httpd-logs/mysite.com.access.log;
    error_page 404 = @fallback;
    }
    location @fallback {
    proxy_pass 62.xxx.xx.xx:8080;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Real-IP $remote_addr;
    }
    }

    Step 5: Перегружаем сервер

    Теперь нужно убедиться, что Varnish запущен — попробуйте запустить комманду 'top' на терминале и проверьте, что процесс varnish запущен.
    Убедитесь, что Varnish + Pressflow работают — запустите varnishlog комманду под SSH и попробуйте открыть свой сайт mysite.com, varnishlog после этого должен будет показать HTTP заголовки, это будет означать, что все работает отлично.

    После всех этих настроек, я еще раз loadimpact`ом прогнал тест и получил:

    image

    Теперь ситуация значительно лучше, задержка от сервера стабильна и при повышении трафика не валит сервер.

    Вот такие нехитрые настройки запустят Pressflow + Nginx + Varnish на Вашем сервер для ускорения Drupal.

    Также походу дела обнаружилось, что у Nginx есть специальные настройки под Друпал — wiki.nginx.org/Drupal.

    Дополнительные ссылки:

    Поделиться публикацией
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама
    Комментарии 38
    • 0
      Познавательно, спасибо.
      • 0
        Спасибо.

        Интересно узнать еще чей-либо опыт по данной теме.
      • +2
        Спасибо за статью, но описания Varnish и Pressflow лучше перевести.
        • 0
          Это их официальное описание, не нашел почему-то кнопки quote в редакторе хабровском.
          • –1
            Хабраюзер, наверное имеет ввиду, что было бы хорошо, если бы вы не официальное описание вставили, а перевод. Английский до сих пор не все знают хорошо…
            • 0
              Извиняюсь за недопонимание, в английском языке «провожу» времени больше, чем в русском. Переведу контент.
            • 0
              [blockquote]
              текст цитаты
              [/blockquote]

              Только скобки угловые поставьте.
          • –1
            Комментарии в конфигах наверное лучше убрать.
            Спасибо за статью!
            • +2
              Не-не-не, лучше все это оставить, если бы не комменты, и любая доп-инфа, незнающим (как и мне до момента, когда все это заработало), было бы очень тяжело разобраться.
              • –2
                а они не стандартные?
                • +2
                  Какие-бы они не были, это комменты — суть их помочь и объяснить. Аминь :)
                  • –2
                    Просто коммент в 9 строк немного мозолит глаза :)
                    Ну да ладно. Вы автор — Вам виднее. В любом случае плюс за статью.
            • +8
              Советую varnish заменить на squid (последний рвёт предпоследнего как тузик грелку), а apache/mod_php на php-fpm, кстати в случае последнего можно на nginx включать fastcgi-кэширование.

              А вот сюда:
              location ~* ^.+\.(jpg|jpeg|gif|png|svg|js|css|mp3|ogg|mpe?g|avi|zip|gz|bz2?|rar)$ {
              root /home/pathto/drupal613;
              access_log /home/httpd-logs/mysite.com.access.log;
              error_page 404 = @fallback;
              }

              надо добавить что-нибудь вроде expires max; чтобы не раздавать закешированные у клиента картинки, а отдавать HTTP 301, да и access_log не особо нужен статике + полезно html/xml/js/css etc гзиппить nginx'ом, а не php (как происходит при выставлении соотв. галочек в друпале).

              gzip on;
              gzip_min_length 1000;
              gzip_comp_level 5;
              gzip_types text/plain text/html text/xml application/xml application/x-javascript text/javascript text/css text/json;
              gzip_disable «msie6»;
              gzip_proxied any;

              • 0
                Во, за этот коммент отдельное спасибо!

                Есть ресурсы с подробной сравнительной характеристикой varnish и squid?
                • +1
                  Дык, вроде тут где то и проскакивало стрессовое сравнение, если не ошибаюсь. + в википедии в качестве фронт-енда squid, что символизирует ;)

                  и ещё добавлю — в плане раздачи статики надо ещё смотреть в сторону дискового AIO на nginx, да и squid его тоже поддерживает, а к пхп надо прикручивать что-нибудь в духе APC/XCache/eAccelerator, а со сторону Drupal модуль cache_router.
                • 0
                  Но зато Друпал собирает все css и все js в два файла, вместо, скажем 15. Если компрессированный файл обновился, то надо пропускать запрос к нему через Apache. Поэтому надо как-то изящно решать проблему, описанную тут.
                  • 0
                    Ошибался. Всё уже работает как надо, ситуацию для незакомпрессированных ранее файлов в представленном конфиге спасает error_page 404 = @fallback;
                • 0
                  А данный конфиг Варниша подойдет для стандартного Друпала?
                  Кстати, в чем конкретно отличия Pressflov с вашей точки зрения? Насколько он быстрее стандартного Друпала?
                  • +1
                    Varnish без Pressflow не пробовал, не могу точно сказать, но по-идее реально, ведь это просто система кеширования контента отдаваемого пользователю.

                    По поводу отличий Pressflow от стандартного Друпал можно почитать у них на сайте, но суть его в том, что работа с базой данных, некоторыми структурами данных полностью переработана для ускорения работы системы в целом.
                  • +2
                    Если есть nginx, почему бы не использовать его кеширование вместо Varnish'а? Чем Varnish вообще лучше в этом случае?
                    Давно думаю насчет Varnish, но пока не могу себя убедить, нужно стороннее мнение :)
                    • 0
                      Варниш более гибок в плане настроек кеширования(VCL) + возможность использования ESI
                    • 0
                      Убери IP из последнего примера конфига nginx в пункте 3
                      ; )
                      • +2
                        Не могли бы вы объяснить чем решение Varnish+Nginx+Apache + mod_php лучше чем Nginx+fast_cgi php

                        LoadImpact.com ломится «незарегистрированными» пользователями. Сайт на друпале благодаря всей описанной выше кухне с помощью кеширования выраждается в раздачу статики. Зачем тогда городить огород — nginx прекрасно сам закеширует ответ fastcgi и будет на раздаче этого кеша показывать отличное время.

                        Складывается ощущение, что вы просто услышали где-то, что «Varnish это оч круто», поставили его и он показал какие-то результаты, которыми вы и поспешили поделиться со всеми. Но есть ли прирост по сравнению с правильной (не тонкой, просто «правильной») настройкой nginx. Я, если честно, сильно сомневаюсь.
                        • +1
                          Буду благодарен за пост с описанием правильной настройки Nginx+fast_cgi php под Drupal с соотношением 80 к 20 анонимных к залогиненым пользователям и трафиком от 10000 и более хостов в сутки.
                          • 0
                            Присоединяюсь. Получается что:

                            Varnish (proxy) + nginx (proxy web server) + apache (web server) + mod_php

                            Из этой цепочки можно легко исключить два звена и оставить:

                            nginx (proxy web server) + fcgi php

                            и сэкономить памяти как минимум, которую можно использовать под memcache например.
                            • 0
                              А нет вероятности, что на таком трафике не хватит памяти для корректной работы fcgi php?

                              Было бы очень приятно увидеть подобный мануал для корректной настройки.
                              • 0
                                Давно хочу написать но все никак не соберусь.

                                Кстати используете APC для PHP?
                                • 0
                                  Я сейчас пробую eAcc использовать, вроди как вполне отлично ускоряет работу PHP.
                        • –1
                          А для Joomla есть что-то аналогичное?
                          • +3
                            Varnish это ключевое ПО для ускорения Вашего сайта.

                            Varnish — это Open Source ПО, стандартизированное и требующее незначительных ресурсов.

                            Как то не очень понятно зачем же этот варниш всё же нужен
                            • 0
                              <пре>
                              Status: "} obj.status {"
                              Response: "} obj.response {"
                              XID: "} req.xid {"
                              </пре>
                              <адресс><ссылка href="http://www.varnish-cache.org/">Varnish</ссылка></адресс>
                              
                              ой
                              
                              • 0
                                Не ругайтесь :) HTML'ину всю эту хабр пытался показать, вот и пришлось поправить :)
                              • 0
                                Перед вашим правилом для отдачи картинок, надо добавить что-то подобное:

                                location ^~ /sites/default/files/imagecache/ { 
                                  index index.php index.html; 
                                  if (!-e $request_filename) { 
                                    rewrite ^/(.*)$ /index.php?q=$1 last; 
                                    break; 
                                  } 
                                }
                                

                                Иначе популярный модуль Imagecache работать не будет. В плане, не будут генериться новые превьюшки при первом обращении по соответствующему url`у. Возможно вы или кто-то ещё из экспертов по nginx`у подскажут, как решить такую проблему: если файл уже имеется, то отдавать его nginx`ом, а если файла нет, то не возвращать 404-й еррор, а передавать запрос на обработку Apache. Правило, которое я выше описал, тупо всё сливает на Apache, даже если превьюшка уже в наличии.
                                • 0
                                  Не такой уж я серьезный специалист, но судя по той конфигурации вижу что картинки в случае 404 вполне нормально кидаются fallback`ом на на 8080 порт и генерятся, что собственно и подтверждается практикой.
                              • 0
                                То, что нужно! как раз занимаюсь подобной проблемой.
                                • 0
                                  У меня возник вопрос, на который пока не могу найти ответ. В логах apache после varnish указывается локальный адрес, т.е. не передаются внешние адреса. Не совсем понятно, как можно передавать адреса по цепочке nginx -> varnish -> apache. При существующей связке nginx+apache этим занимается X-Real-IP + mod_rpaf.

                                  Буду признателен за подсказку.

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