У меня есть сервер nginx, сидящий перед apache, на котором запущен django.
Большая часть моего сайта - это статический контент: http://www.grovemade.com/
Мой сервер приложений может легко обрабатывать элементы, которые должны быть динамическими (POST, корзина, статус заказа, часто задаваемые вопросы и т. Д.).
Подавляющее большинство обращений приходится на статические страницы, такие как страницы продуктов, страницы о страницах, запросы на получение ajax.
Он работает как чемпион, обслуживая страницы прямо из memcached. Я действительно попросил SF помочь определить мое узкое место здесь: Доказывает ли это узкое место пропускной способности сети? и это ограничено ограничением исходящего трафика моих хостов. таким образом, он на 100% способен на все, что мне нужно. Я был весь в восторге от цифр; но цифры не означают чушь, когда сразу 40 страниц засыпают словами: «Эй, сделай мне новую для кеша!» "Привет, я тоже!"
Единственная проблема заключается в том, что во время интенсивного трафика, когда истекает срок действия моего кеша для определенной страницы, мой сервер приложений получает тысячи запросов, что приводит к сбоям / возможному сбою сервера. То, что я представляю, больше похоже на ...
О: Сервер приложений автоматически отправляет контент в memcached в своем собственном темпе (потому что он определенно может заполнить кеш ... но не сотнями одновременно). Сервер переднего плана работает с тем, что у него есть - никогда не пытается получать запросы через прокси. Черт, это может выбросить пустую страницу, мне все равно; по крайней мере, сервер приложений будет жив, принимать заказы и сможет заполнить эту сломанную страницу в какой-то момент в будущем вместо нисходящей спирали смерти, когда я даже не могу поднять свой щит (memcached). Проблема в том, что мне пришлось бы создать систему, которая определяет каждую страницу, которую предполагается кэшировать, из нескольких мест. Django знает, какие страницы кэшировать; Полагаю, это будет легко. Но nginx -> django: я бы не хотел, чтобы он все проксировал (иначе я был бы в той же ситуации); поэтому мне пришлось бы закодировать больше логики в отдельном месте. Мех.
B: Nginx может ограничивать подключения к серверу приложений. Но как он будет различать запросы, которые должны быть поставлены в очередь на сервер приложений, и типы, в которых я хочу, чтобы он выполнял только одно соединение? В конце концов, приложение решает, кэшировать страницу или нет. Я бы не хотел, чтобы он прерывал соединения, если он ждет на моем сервере приложений простого динамического контента, такого как получение сведений о заказе. Могу ли я создать цикл ответа на запрос между кешем / приложением, который сообщает, что страница должна быть создана? и что последующие запросы следует игнорировать?
Мля.
Итак, учитывая, что 99% трафика удовлетворяется nginx, а мой сервер приложений действительно интересен только тем X%, которые конвертируют и превращают его в динамическую страницу, что мне делать, чтобы предотвратить полное затопление моего сервера приложений за несколько секунд где он отвечает:
Эй, ты! Позвольте мне вернуть вам эту страницу. О, еще 1000 человек хотят этого? Хорошо, я сделаю это, чтобы .... если бы мог.
Проблема / пример из реального мира: сегодня у нас огромный всплеск хитов. Обычно у нас не так много трафика, но мы выпустили наш продукт сегодня, и клиенты с предзаказом пришли как сумасшедшие. Сервер обрабатывает трафик @ 20% мощности сейчас, но были очень очень отрывочные моменты, когда я почти терял его, когда он пытался сгенерировать одну маленькую страницу, на которую все нажимали, когда истек почасовой таймер кеширования.
Я лихорадочно выбирал самые важные кешированные страницы и пытался сохранить их в кеше. Это было / не / весело! Я также вручную вытащил HTML из apache, работающего на: 8080, и закинул их в memcached.
Если моему процессу apache не хватит памяти и он полностью выйдет из строя, скажем, memcached, или прошло достаточно времени, чтобы истек срок действия ключей, возникла бы точка ... "трудного возврата", когда так много людей будут обходить кеш, что мой сервер будет даже более перегружен, чем обычно / поэтому обычно не может быть восстановлен без простой блокировки всех запросов и начала заполнения кеша вручную.
Что обычно делается, чтобы это работало?
Извините за поток мыслей вроде поста. Я не спал из-за этого ..
# grove urls
# ----------
location / {
set $use_memcached no;
if ($request_method = GET) {
set $use_memcached yes;
}
if ($host ~ "^cached") {
set $use_memcached no;
}
if ($request_uri ~ '.{240,}') {
set $use_memcached no;
}
if ($args ~ nginx_bypass_cache=true) {
set $use_memcached no;
}
if ($use_memcached = yes) {
set $memcached_key "nginx.$request_uri";
memcached_pass localhost:11211;
}
default_type text/html;
client_max_body_size 50m;
error_page 404 502 = @cache_miss;
}
location @cache_miss {
proxy_pass http://127.0.0.1:8080;
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;
client_max_body_size 50m;
client_body_buffer_size 128k;
proxy_connect_timeout 60; # time to connect to upstream server
proxy_send_timeout 300; # time to wait for upstream to accept data
proxy_read_timeout 300; # time to wait for upstream to return data
proxy_buffer_size 4k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
}
Если вы опубликуете свою конфигурацию nginx, возможно, я смогу вам помочь лучше!
Как правило, я буду использовать fastcgi_cache / proxy_cache Nginx с fastcgi_cache_use_stale/proxy_cache_use_stale
Я сказал оба варианта, потому что если вы можете запускать серверное приложение с помощью Nginx fastcgi или другого модуля, то лучше сделать это.
Если Apache на 8080 не может быть удален, лучше использовать proxy_cache с proxy_cache_use_stale updating
линия.
Пожалуйста, предоставьте свою конфигурацию, чтобы мы могли ее улучшить.
==
Добавлен образец конфигурации на основе вашей (очень сырой, скорее всего, потребуется настройка)
#IMPORTANT outside server{..} block
proxy_cache_path /var/run/nginx-cache levels=1:2 keys_zone=GROVE:500m inactive=60m;
proxy_cache_key "$scheme$request_method$host$request_uri";
fastcgi_cache_use_stale updating;
server {
#other stuff
set $no_cache 0;
# POST requests and urls with a query string should always go to PHP
if ($request_method = POST) {
set $no_cache 1;
}
# grove urls
# ----------
location / {
default_type text/html;
client_max_body_size 50m;
proxy_pass http://127.0.0.1:8080;
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;
client_body_buffer_size 128k;
proxy_connect_timeout 60; # time to connect to upstream server
proxy_send_timeout 300; # time to wait for upstream to accept data
proxy_read_timeout 300; # time to wait for upstream to return data
proxy_buffer_size 4k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
proxy_cache_bypass $no_cache;
proxy_no_cache $no_cache;
proxy_cache GROVE;
proxy_cache_valid 60m;
}