Веб-сервер за рубежом + статика в России = ускорение скорости загрузки страницы

  • Tutorial
Самый частый вопрос при выборе зарубежного хостера (на примере Hetzner): «Не будет ли сайт тормозить»? Несмотря на то, что ping к Hetzner из России достаточно мал, статика (особенно тяжелая или если ее много) с серверов, размещенных в России, отдается быстрее.

Есть несколько вариантов увеличения скорости оставаясь в Hetzner:

1. Использование российских CDN-сервисов.
2. Проксирование/кэширования статики через сервер/vps, размещенный в России.

Я расскажу, как технически реализовать проксирование/кэширование статики с помощью nginx через сервер, размещенный в России.


Для решения задачи потребуется вынести всю статику на отдельный поддомен, а если статики много — на несколько доменов. К примеру, assets01.example.com, assets02.example.com, ..., assets04.example.com (использование больше 4-х доменов может привести к снижению производительности, т.к. DNS-resolve тоже занимает какое-то время). Таким образом, браузер минуя ограничения одновременных коннектов, быстрее загрузит страницу. Важно, чтобы ссылки к статике на странице всегда оставались одинаковыми, т.к. в случае постоянного перемешивания доменов assets01-asstets04 браузер будет ее загружать заново.

В следующем примере статика будет прозрачно проксироваться с сервера в Hetzner и кэшироваться на российском сервере, таким образом повторная загрузка будет происходить только при изменениях на сервере в Hetzner. Отмечу, что в случае, если требуется изменить, к примеру, css, потребуется или изменить имя файла, или цифру в запросе. К примеру, можно использовать адреса assetsXX.example.com/css/styles.css?2342324, а при изменении файла styles.css менять serial на любой другой. Это полезно в том числе при использовании параметра nginx «expires max» — браузер не будет даже проверять обновления, что так же увеличивает скорость открытия страницы.

Конфиг nginx на российском сервере будет выглядеть следующим образом (на сервере в Hetzner так же потребуется прописать алиасы):

# устаревший кэш будет удаляться через 30 дней, максимальный размер кэша 100 Гб
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=static:32m inactive=30d max_size=100g;

server {
    listen 80;
    server_name assets01.example.com assets02.example.com assets03.example.com assets04.example.com;

    # access_log я без необходимости не включаю, т.к. запись в лог на нагруженных сервисах дает лишнюю нагрузку на дисковую подсистему
    access_log off;
    error_log /var/log/nginx/example.com-err.log;

    # этот локейшн полезен для случаев, когда посетитель или поисковик пытается зайти по адресу http://assetsXX.example.com/ - редиректим его на основной сайт
    location / {
        rewrite ^ http://example.com$uri permanent;
    }

    # перечисляем расширения, которые будем кэшировать
    location ~* \.(jpg|jpeg|gif|png|ico|css|midi|wav|bmp|js|swf|flv|avi|djvu|mp3)$ {
        # указываем IP сервера в Hetzner
        proxy_pass http://111.111.111.111:80;
        proxy_redirect off;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_buffer_size 16k;
        proxy_buffers 32 16k;

        # указываем заголовок expires для ссылок, в которых присутствует serial (к примеру, http://assetsXX.example.com/css/styles.css?2342324)
        if ($request_uri ~* "\?[0-9]+$") {
            expires max;
            break;
        }

        proxy_cache static;
        # делаем кэш валидным в течение 30 дней
        proxy_cache_valid 30d;
        proxy_ignore_headers "Cache-Control" "Expires";
        # строим кэш на основе запроса и его параметров, без учета названия хоста, чтобы кэш для assetsXX не загружался несколько раз (таким образом /css/styles.css?123 и /css/styles.css?321 будут разными объектами)
        proxy_cache_key "$uri$is_args$args";
        proxy_cache_lock on;
    }
}
Southbridge
273,00
Обеспечиваем стабильную работу серверов
Поделиться публикацией

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

    +2
    По идее сработает с любым провайдером (хостером), не обязательно Hetzner
      0
      Сработает конечно же с любым зарубежным хостером.
      +2
      Причем тут Hetzner вообще не понятно. Обычный проксируещий конфиг с кешем в nginx.
        0
        Так заголовок больше народу привлечет, очевидно)
          0
          Вероятно, это обосновывает всю идею с двумя хостерами. Hetzner дешёвый, а российских хост можно взять меньшей мощности.
          0
          а где посоветуете взять в россии сервера для кэширования?
            0
            а где посоветуете взять в россии сервера для кэширования?

            Это уже «на вкус и цвет» ;-) Попробуйте посмотреть разные варианты на ресурсах типа ispreview.
          • НЛО прилетело и опубликовало эту надпись здесь
              0
              hardworm, а лучше использовать оба варианта. :-)
              0
              С Варнишем не сравнивали?
                0
                И сколько времени пройдет, после замены на сервере основном сервере /favicon.ico до его обновления в кеше?
                Я не нашел в приведенном примере настройки или описания, что позволить обновить изображение, только аргументы для css.
                Исходя из того, что после обновления сайта мы меняете хеш для всех css и возможно js, для медиа контента такой вариант не имеет смысла, хотя по вашему конфигу можно, иначе браузер заново загружает все изображения, а кеш заново наполняется.
                Так, что я думаю 30 дней ждать обновления баннера или иконки это не совсем верный вариант. Как вы решаете эту задачу?
                  0
                  Для замены favicon можно пойти аналогичным путем с сериалами. Достаточно добавить tag:

                  <link href="/favicon.ico?123" rel="shortcut icon" type="image/x-icon" />
                  


                  Да и баннеры можно аналогично организовать, почему нет?
                    0
                    Я не имел ввиду, что нельзя подменить путь к favicon. Я не отрицал возможности добавление хеша и к изображением.
                    Я не нахожу ответа на самый обычный вопрос, который часто возникает вообще при кешировании.
                    У меня >80 Гб статики. Ваше предложение? Держать для каждой ссылки свой хеш?
                    Если, да, то если строить его по данным файла прибавить не мало i/o нагрузки. Не говоря о дополнительной части в изменении кода.
                    Есть второй 1 хеш для обновления сайта, как часто делают для css & js. Но если взять один хеш для всех изображений, то все что я хотел донести, при замене пару Кб простого favicon, у вас весь кеш станет не валидным и будет заново наполнятся заливая все 80 Гб.
                    Все это я описал сразу. И хочу услышать общее решение в этом случае, как управлять обновлением контента.
                      0
                      Можно удалить конкретный объект из кэша, но вряд ли это сделать автоматически намного проще, чем организовать сериалы со стороны программирования.
                      По-поводу io нагрузки — это уже зависит от алгоритма, на мой взгляд.
                        0
                        В следующем примере статика будет прозрачно проксироваться с сервера в Hetzner и кэшироваться на российском сервере, таким образом повторная загрузка будет происходить только при изменениях на сервере в Hetzner.

                        К сожалению, вы не показали решение. Так что я не могу согласится с вашим конфигом. Не смотря на имеющееся дополнение про css. Максимум это «конфиг для проксирования статитики, а для обновления нужно обновить алгоритм построенние ссылок, для внесение хеша к измененным элементам». А это не малое упущение, иначе действительно еще один пример обычного конфига, с добавлением хеша, даже не через location, а через аргументы с добавлением IfIsEvil.
                        0
                        Меняете хеш только у тех файлов, которые изменились, вот и все.
                          0
                          Этот вариантов я указывал как один из возможных. Хотел услышать как решает проблему автор, или хотя бы его мнение на нее.
                            0
                            Я эту задачу решаю на уровне программирования, ruby on rails.

                            Вряд ли есть более простое решение. Разве что указывать меньший интервал кэширования proxy_cache_valid, но тогда и от expires придется отказаться.
                      0
                      Этот способ идеально подходит для rails приложений. В остальных случаях его использовать без дополнительной подготовки скорее всего не получится.
                      0
                      Так не советуют делать конфиг.
                      Во-первых нет proxy_cache_lock. Если найти файл который все еще не сохранился на вашем кэш сервере то забить ваш сервер можно даже утилитой ab (хотя при вашем proxy_cache_key "$uri$is_args$args"; и так забить ваш диск не составит проблем).

                      Во-вторых вы сами тестировали нормально ваш пример? debug nginx включали? Файлы берутся из кэша или проксируются при каждом запросе?
                        0
                        Так не советуют делать конфиг.
                        Во-первых нет proxy_cache_lock.

                        Согласен, исправился.

                        (хотя при вашем proxy_cache_key "$uri$is_args$args"; и так забить ваш диск не составит проблем).

                        L3n1n, может быть у Вас есть идеи, как обойти этот момент при работе с сериалами?

                        Во-вторых вы сами тестировали нормально ваш пример? debug nginx включали? Файлы берутся из кэша или проксируются при каждом запросе?

                        Тестировал раньше и специально проверил с использованием debug еще раз — файлы берутся из кэша. А почему вопрос, есть какие-то опасения?

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

                      Самое читаемое