Pull to refresh

Comments 40

Не секрет, что для защиты от HTTP-DDoS зачастую используют связку nginx в качестве фронтенда и некий другой web-сервер в качестве бакенда.

А зачем нужен другой web-сервер. Приведите пример, пожалуйста, как вы это делаете, почему недостаточно только nginx?
наверное имелось ввиду что-то типа mod_php + Apache, но тогда достаточно смешно говорить о высокой производительности и ддос-е, так как такая связка или очень древняя, или вряд ли это кому-либо актуальное приложение настолько, чтобы его досить
И чем вам Apache + mod_php не угодил? [sarcasm mode on]
Вообще из mod_php + Apache можно выжать очень много, если нормально приготовить. Если поставить поверх nginx для отдачи статики и кеша, выходит вполне себе нормально. Оно, конечно, не особо надо т.к. есть fpm, но возможно.
fpm ни разу не быстрее mod_php, возможно ресурсов жрет поменьше, но не быстрее
Я, в общем-то, про то же. Они примерно одинаково отрабатывают.
Оно «быстрее» в плане того, что может переварить большое коннектов при прочих равных. Именно потому что кушает меньше памяти => больше воркеров можно запустить. Отсюда и легенда про быстроту (ибо народ обычно тестит ab с флагом -c и видит крутые цифры).
Да, собственно, ничего не мешает использовать такое логирование только на нгинкс, но у меня, обычно, всё в связке (apache, WEBrick или тот-же nginx на бакенде) и nginx на высокопроизводительном фронтенде, который их «прикрывает».
Какая аргументация использования второго web-сервера? И какой язык программирования, чтобы понять ситуацию?
apache + mod_rewrite. Когда не хочется переписывать .htaccess у сайтов.
Странное решение, замедлить работу сайта из-за десятка правил в htaccess? И погуглите nginx htaccess converter.
Когда сайтов более 50 + есть куча вложенных .htaccess в разных папках — тогда стоит задуматься о том, чтобы переписывать для каждого правила и искать .htaccess'ы.
Прокси — это типичная реализация nginx (http://nginx.org/en/docs/http/ngx_http_proxy_module.html), что используется в качестве бакенда не принципиально. У меня в качестве бакендов есть и webrick(ruby) и apache(php) и IIS и даже небольшой самописанный. Также десяток-другой VPS'ок, которые «упадут» задолго до преславутых C10k.
Можно вопрос? WEBrick у вас же не в продакшене?
Он не совсем у меня, клиентский. Ставили временно, но нет ничего более постоянного, чем временное…
Ну это как-то не серьезно совсем.
Ну, например, есть еще томкат контейнер, или jetty. На pho свет клином не сошелся. За nginx может быть и несколько разношерстных серверов.
Тем самым вышеописанная реализация хранения с SETEX позволила добиться равных результатов с хранением в файле
Или вы в обоих случаях протестировали производительность ab.
Вы имеете ввиду, что я не «довёл» сохранялку до неработоспособного состояния, чтобы понять в каком случае раньше начнутся проблемы? Да, возможно, стоило попытаться, но задача сохранения логов стоит не только в самом хранении, а ещё и в анализе/выборке/парсинге и ротации этих логов.
Если же сравнивать голое сохранение, то здесь, пожалуй надо использовать SET, а не SETEX.
Я имею в виду, что обычно один поток ab не способен полностью нагрузить даже одного рабочего процесса nginx в hello world тестах. Поэтому на основе представленных данных я лично не могу сделать тот вывод, что был процитирован.
Да, согласен, вывод несколько преждевремен.
Изначально меня интересовало сравнение SETEX/EVALSHA, где этого теста оказалось достаточно.
Попытаюсь завтра нагрузить сильнее.
ab запустил с 9 PC непрерывно и с локального снимаю статистику
redis
# ab -n 100000 -c 16 -v 0 127.0.0.1:80/
Time taken for tests: 20.768 seconds
Complete requests: 100000
Failed requests: 0
Write errors: 0
Total transferred: 84400000 bytes
HTML transferred: 61200000 bytes
Requests per second: 4815.09 [#/sec] (mean)
Time per request: 3.323 [ms] (mean)
Time per request: 0.208 [ms] (mean, across all concurrent requests)
Transfer rate: 3968.69 [Kbytes/sec] received

Connection Times (ms)
min mean[±sd] median max
Connect: 0 2 0.3 2 5
Processing: 1 2 0.3 2 6
Waiting: 1 2 0.3 2 5
Total: 2 3 0.4 3 8

Percentage of the requests served within a certain time (ms)
50% 3
66% 3
75% 4
80% 4
90% 4
95% 4
98% 4
99% 4
100% 8 (longest request)


файл
# ab -n 100000 -c 16 -v 0 127.0.0.1:80/
Concurrency Level: 16
Time taken for tests: 19.616 seconds
Complete requests: 100000
Failed requests: 0
Write errors: 0
Total transferred: 84400000 bytes
HTML transferred: 61200000 bytes
Requests per second: 5097.93 [#/sec] (mean)
Time per request: 3.139 [ms] (mean)
Time per request: 0.196 [ms] (mean, across all concurrent requests)
Transfer rate: 4201.81 [Kbytes/sec] received

Connection Times (ms)
min mean[±sd] median max
Connect: 0 2 0.2 2 5
Processing: 1 2 0.2 2 5
Waiting: 1 2 0.2 2 5
Total: 2 3 0.4 3 7

Percentage of the requests served within a certain time (ms)
50% 3
66% 3
75% 3
80% 3
90% 4
95% 4
98% 4
99% 4
100% 7 (longest request)


оттетстил раз 10, разница в пределах статистической погрешности, большей нагрузки создать нечем
А при этом ещё сравнивали сколько было залогировано? Как я написал ниже, если я не ошибся, то модуль начинает просто дропать логи, когда не справляется с нагрузкой.
Локально сделанные запросы были залогированы все, с других машин не успевал проверить. На неделе оттестирую ещё.
Достаточно сопоставить количество залогированых запросов с суммарным количеством запросов сделанных со всех машин.
Да это понятно, они у меня просто лились непрерывно просто для нагрузки + тестировал-таки с SETEX 20.
«не справляется с нагрузкой» не совсем корректный термин. Модуль отбрасывает записи, когда переполняется временный буфер отправки (400k). Однако предполагается, что сеть, через которую выполняется логгирование, достаточно эффективна, чтобы вовремя относить поступающие записи.

Подобное снижение качества сервиса происходит с логгированием в файл, когда заканчиваются дисковые буферы.
Помимо пропускной способности сети, есть ещё на другом конце сам redis, который должен успевать читать.
Кто-то уже пробовал такую связку в бою?

У меня есть ничем не обоснованное подозрение, что всё это может сломаться в самый неподходящий момент. Раз Redis хранит всю свою базу в памяти, значит эта система будет работать до тех пор, пока на сервере с редисом она не закончилась. В случае DDoS-атаки количество запросов резко возрастает. Предположим, что количество залогированных запросов стало таким, что Redis увел сервер в swap и стал тормозить, замедляя работу и самого nginx-а. Наверное, такое возможно?

Та же ситуация произойдет, если мы забудем настроить ротацию логов в Redis. В какой-то момент без видимых причин nginx начнет отдавать запросы заметно медленее. А поскольку причина проблемы неочевидна, то разработчик, скорее всего, сначала перероет свое приложение в поисках регрессии, а потом уже вспомнит про логи в Redis.

Кроме того, интересно, что произойдет, если Redis отвалится. Насколько я вижу, модуль пытается переустановить соединение. Мне кажется, это катастрофически должно сказаться на производительности сервера (кстати, этот вариант легко проверяется с помощью бенчмарков).

Если бы я настраивал что-то подобное, то скорее всего, я бы предпочел, чтобы nginx скидывал логи в обычные предсказуемые файлы, а потом по крону парсил бы их содержимое и запихивал в любую базу (и скорее всего, это был бы не Redis).
В таком виде эта связка родилась сегодня утром )
Выложил на хабр именно для того чтобы услышать мнения о возможных доработках.
Использовать её планирую только в варианте с SETEX, т.е. ротация априори включена.
Вариант с падением redis оттестирую и отпишусь.
Насколько я вижу, модуль просто начинает дропать логи если не справляется с нагрузкой или не удается установить соединение до того, как у него заканчивается буфер.
Если сравнивается SETEX и EVALSHA, то надо было еще добавить MULTI / EXEC.
Не представляю какое преимущество может дать redis для анализа логов. Если какие-то счётчики держать, то ещё можно понять, но целиком логи очевидно удобнее и надёжнее в файл или какую-то систему аггрегации логов (syslog / logstash etc)
Частично Вы сами ответили на свой вопрос — можно держать счётчики.
Ну или, например, сделайте выборку из файла всех запросов сделанных с ip 1.2.3.4 к локейшину /test/ за последние 20 сек
А если хранить логи просто «чтобы было», то в redis, конечно, необходимости нет.
Не вижу сложностей в том, чтобы сделать такую выборку: пара грепов, либо один Perl/AWK ну или PyPy + простенький парсер.

grep -E "\[18/Sep/2013:06:50:(0|1)" access.log | grep "GET /api/" | wc -l
Выборка с 06:50:00 по 06:50:19 (20 секунд) GET запросов к "/api/*"

А со счётчиками проблема в том, что нет гибкости. Захотели вы сделать выборку не за 20 секунд, а за 120 и уже нужно лезть в конфиги nginx, делать релоад, ждать накопления данных.
grep -E "\[18/Sep/2013:06:50:(0|1)" access.log | grep «GET /api/» | wc -l
Выборка с 06:50:00 по 06:50:19 (20 секунд) GET запросов к "/api/*"

А если секунды не уложились в одну минуту/день/год? :)
И какова производительность этого комбайна?
Если секунды не уложились, просто пишем более подходящую регулярку.
Учитывая, что там все в конвеере, то фигачиться очень быстро. Не раз приходилось анализировать логи в несколько гигов и более сложными однострочниками, всегда это был вопрос менее минуты. В такой ситуации логи в redis дадут только минусы — отдать несколько гигов ОЗУ ради того, что бы получить результат не за, условно, минуту, а секунду, видится абсолютно нецелесообразно. Дисковый кэш ОСи вещь достаточно умная что бы на неё можно было полагаться.

В общем решение интересно чисто академически. Для продакшена не пригодное, при атаке тем более.
По-моему, это гениально. Правда, очень поможет для фильтрации.
Sign up to leave a comment.

Articles