LINUX.ORG.RU

Глупый вопрос про веб-фреймворк и загрузку фоток

 , , ,


0

3

Здравствуйте

Вот читаю я доку про gunicorn. В ней написано, что количество воркеров желательно делать 2 * число_ядер + 1.

Допустим, у меня 1-ядерный VPS. Запускаю я свой бекенд с тремя воркерами. Бекенд умеет принимать фотки от пользователей. 3 юзера одновременно начинают заливать фото -> сервис парализован: даже гет-запросы перестают обрабатываться

Как решается эта проблема в среде синхронных фреймворков?

★★★★★

Последнее исправление: makoven (всего исправлений: 2)

Первоночально поставить nginx. Потом насторить мониторинг. Увеличивать мощности основываясь на полученных данных от мониторинга.

alfss
()
Ответ на: комментарий от alfss

Чем поможет nginx в этой ситуации и что делать, если других мощностей нет, а надо обслужить хотя бы 50 одновременных аплоадов фоток?

makoven ★★★★★
() автор топика

php синхронный и как-то справляется тоже) и до популярности nodejs люди грузили тоннами фотки) можно выделить отдельный микросервис на загрузку и написать его на golang как это сделал dropbox и google.можно по хитрому интегрироваться с амазоновским S3 например. ну и посмотрите на опыт instagram ) это сейчас одна из самых больших инсталляций django. да они все еще на django.

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

abc
()
Ответ на: комментарий от abc

php синхронный и как-то справляется тоже

Ака mod-apache там попач сам несколько интерпретаторов держит в памяти и время от времени убивая их, запускает новые копии, чтобы не текли сильно.

Ака fast-cgi/fpm там один пыхо-процесс зигота, остальное как у попача.

Что там что там — менее восьми интерпретаторов готовых принять запрос клиента я не видел.

deep-purple ★★★★★
()
Ответ на: комментарий от zolden

Тересна! Но сомнительно — устанавливать в нжинксе значения для суперглобалов пыха.. Т.е. они так от пыха и не отвязались, хотя и сразу на диск файл кладут.

deep-purple ★★★★★
()

Очевидно, надо увеличить количество ядер хотя бы до 16, тогда можно будет запустить 33 воркера.

deadNightTiger ★★★★★
()
Ответ на: комментарий от deadNightTiger

Как-то не очень впечатляет: 16-ядерный сервер для 33 соединений

makoven ★★★★★
() автор топика
Ответ на: комментарий от makoven

а надо обслужить хотя бы 50 одновременных аплоадов фоток?

Вы проводили тесты ?

У вас есть статистика за 2-3е суток(хотя бы) чтобы подтвердить 50 запросов на загрузку файлов в секунду?

Если ваша цель просто академическая, то почитайте как работает nginx, сделайте нагрузочные тесты и посмотрите во, что будет упираться система. Сделайте выводы, экспериментируйте дальше.

В противном случае:

  • Пересмотрите бизнес модель (возможно не стоит и начинать)
  • Выберите другой инструментарий
  • Обоснуйте руководству необходимость в увеличении ресурсов
alfss
()
Последнее исправление: alfss (всего исправлений: 2)
Ответ на: комментарий от zolden

Я подозревал, что nginx можно обучить загрузить файл на диск и уже затем обращаться к бэкенду. Но в реальности надо сначала передать заголовки запроса бэкенду, чтобы он проверил токен, тип и размер файла, итд. И отменить загрузку если что-то не устраивает

makoven ★★★★★
() автор топика
Последнее исправление: makoven (всего исправлений: 1)

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

Tark ★★
()
Последнее исправление: Tark (всего исправлений: 1)
Ответ на: комментарий от Tark

Так и собирался делать, что еще остается)

makoven ★★★★★
() автор топика
Ответ на: комментарий от alfss

Вы проводили тесты ?

Для трех воркеров? Три слоупока с айфонами парализуют мой прекрасный REST API одновременно начав заливать фотки через 3g соединение

makoven ★★★★★
() автор топика
Ответ на: комментарий от alfss

На ноуте, через 3g с трех вкладок начал загружать фотки. На четвертой вкладке сервис помер. Правда там был не nginx, а falcon и whitenoise. Потому и спрашиваю, как ginx в данной ситуации помог бы?

makoven ★★★★★
() автор топика
Последнее исправление: makoven (всего исправлений: 4)

Попробуй найти различие между concurrent и parallel execution. После этого, надеюсь, часть вопросов сама собой исчезнет.

kardapoltsev ★★★★★
()

Я б написал отдельный асинхроннный сервис для аплоада.

provaton ★★★★★
()
Ответ на: комментарий от makoven

Вообще nginx умеет буферизовать запросы к бэкенду, это решает проблему медленных клиентов.

deadNightTiger ★★★★★
()
Ответ на: комментарий от makoven

Я подозревал, что nginx можно обучить загрузить файл на диск и уже затем обращаться к бэкенду. Но в реальности надо сначала передать заголовки запроса бэкенду, чтобы он проверил токен, тип и размер файла, итд. И отменить загрузку если что-то не устраивает

Почитайте повнимательней HTTP-протокол. Там невозможно отменить прием запроса - можно только отменить его обработку. Так что, просто используйте буферизацию HTTP-запросов на стороне NGINX (она там вроде включена по умолчанию) и NGINX будет параллельно принимать те самые 50 upload-ов. Ну а по приему тела запроса (включая файл) NGINX будет отфутболивать этот запрос бэкенду, и там уже вам решать, что с ним делать в зависимости от токена, размера и пр.

Единственно, не забудьте правильно настроить в NGINX параметр client_max_body_size, чтобы позволял принимать файлы нужного вам размера.

vinvlad ★★
()
Ответ на: комментарий от vinvlad

Почитайте повнимательней HTTP-протокол. Там невозможно отменить прием запроса - можно только отменить его обработку

Как так-то? Во всех микрофреймворках, что я пробовал, тело пост-запроса представляет собой некий стрим. Я как-то не задумывался, что случается с соединением, если вернуться из обработчика, не прочитав тело. Неужто фреймворк читает тело без моего ведома?

Так что, просто используйте буферизацию HTTP-запросов на стороне NGINX

Идея здравая, но не осилю я настроить nginx, чтоб он и авторизацию и типы и размер файлов чекал. У меня там Access-Control-Allow-Origin: *. Без проверок никак

makoven ★★★★★
() автор топика
Последнее исправление: makoven (всего исправлений: 2)
Ответ на: комментарий от makoven

Как так-то? Во всех микрофреймворках, что я пробовал, тело пост-запроса представляет собой некий стрим. Я как-то не задумывался, что случается с соединением, если вернуться из обработчика, не прочитав тело. Неужто фреймворк читает тело без моего ведома?

Вы конечно, можете тупо оборвать TCP-соединение, если фреймворк это позволяет. Но это будет воспринято веб-клиентом как некорректное завершение HTTP-запроса. PHP, например сначала читает запрос, а потом уже выдает вам разобранное тело запроса или «стрим» для обработки тела в raw-режиме.

Идея здравая, но не осилю я настроить nginx, чтоб он и авторизацию и типы и размер файлов чекал. У меня там Access-Control-Allow-Origin: *. Без проверок никак

А вам и не надо ничего проверять на стороне NGINX-а. Вы же обрабатывать запрос будете на стороне бэкенда (NGINX его только принимает) - вот там и проверяйте. Какой ответ вернете NGINX-у, такой он и дальше отфутболит веб-клиенту.

vinvlad ★★
()
Ответ на: комментарий от vinvlad

А вам и не надо ничего проверять на стороне NGINX-а

А нафиг он будет загружать тело, которое мне возможно нафиг не нужно

makoven ★★★★★
() автор топика
Последнее исправление: makoven (всего исправлений: 1)
Ответ на: комментарий от vinvlad

Но это будет воспринято веб-клиентом как некорректное завершение HTTP-запроса

Ну так-то да, не канонично получается. А что поделать

makoven ★★★★★
() автор топика
Ответ на: комментарий от makoven

А нафиг он будет загружать тело, которое мне возможно нафиг не нужно

Потому что так положено по протоколу ) И скорее всего тело на тот момент будет уже загружено на сервер, а стрим, который вы получаете, будет просто стримом чтения временного файла.

Ну так-то да, не канонично получается. А что поделать

Делать, как я сказал ))) - протокол надо соблюдать. Если вы не дочитаете свой стрим до конца, это вовсе не значит, что сервер не будет читать запрос полностью. Вы просто неправильно понимаете логику работу фреймворка.

vinvlad ★★
()
Ответ на: комментарий от makoven

... а чтобы слишком большие запросы не лезли к вам в бэкенд-часть, установить соответствующий максимальный размер тела запроса в NGINX (client_max_body_size) - NGINX будет обламывать такие запросы самостоятельно.

vinvlad ★★
()
Ответ на: комментарий от vinvlad

Ну ок. А nginx без доп модулей умеет сначала полностью скачать тело и только после этого начать тревожить бэк?

makoven ★★★★★
() автор топика
Ответ на: комментарий от makoven

А nginx без доп модулей умеет сначала полностью скачать тело и только после этого начать тревожить бэк

Он именно так и делает - прозрачно проксирует HTTP-запросы в бэкенд.

Ну а там уже, по ходу дела, настроите количество воркеров - чтобы они успевали разгребать поток запросов от NGINX.

vinvlad ★★
()
Ответ на: комментарий от makoven

А nginx без доп модулей умеет сначала полностью скачать тело и только после этого начать тревожить бэк

NGINX в принципе может работать и без предварительной буферизации - там есть соответствующий параметр - но вам такой режим как раз не нужен.

vinvlad ★★
()

В ней написано, что количество воркеров желательно делать 2 * число_ядер + 1.

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

Legioner ★★★★★
()

Эммм... Ты вообще в курсе, как работают http и ядро???!
PS. Вот что жээс с могом делает

Shadow ★★★★★
()

Блин, в топике много тонкого троллинга. Не распарсил, а то бы тоже посоветовал микросервис на Яве написать.

Shadow ★★★★★
()
Ответ на: комментарий от Legioner

... поэтому ставь воркеров побольше. Я бы начал с 100

Каждый воркер-процесс - это затраты оперативной памяти сервера. Если памяти немеренно и больше девать её некуда, то можно и так )

Я просто предложил более экономный вариант, когда прием данных из сети осуществляется оптимизированным под это дело NGINX-ом. Ему хоть 100, хоть тысячу запросов параллельно принимать - по фигу. Ну а число реальных обработчиков фоток правильнее выбирать исходя из реальной нагрузки. В принципе, если поток запросов от NGINX в бэкенд будет непрерывным, то и пара воркер-процессов загрузят процессор на полную катушку - файлы же сначала в кэш записываются, а только потом сбрасываются на диск. Так зачем столько воркеров городить?

vinvlad ★★
()
Ответ на: комментарий от Shadow

Самый тонкий тут ты со своим ведром и хттп. На втором месте парень, который выучил слова concurrent и parallel

makoven ★★★★★
() автор топика
Ответ на: комментарий от vinvlad

Каждый воркер-процесс - это затраты оперативной памяти сервера

А мне не далее как пол года назад ЛОР-аналитики рассказывали, что процесс - это далеко не 8 мегабайт стека. Что память у одинаковых процессов CoW и в реальности там выйдет сотни килобайт, не более

Ему хоть 100, хоть тысячу запросов параллельно принимать - по фигу

Можно еще про фронт побеспокоиться. window.fetch в браузере отменять проблематично (через какие-то сигналы). Возможно гуманнее будет разрывать соединение на стороне сервера. Чтоб клиента не тормозить почем зря

makoven ★★★★★
() автор топика
Последнее исправление: makoven (всего исправлений: 2)

Вот читаю я доку про gunicorn. В ней написано, что количество воркеров желательно делать 2 * число_ядер + 1.

Кстати, в документации написано не совсем так ) Там сказано, что нужно начинать выбор реально необходимого числа воркеров стартуя с указанной формулы. Большая разница...

vinvlad ★★
()
Ответ на: комментарий от makoven

А мне не далее как пол года назад ЛОР-аналитики рассказывали, что процесс - это далеко не 8 мегабайт стека. Что память у процесса CoW и в реальности там сотни килобайт, не более

Ну стэк-то как раз не CoW - он же используется каждым воркером индивидуально. И куча - тоже, за исключением памяти, где общий исполняемый код хранится, если он был предварительно подгружен главным процессом. Можешь запустить несколько воркеров и посмотреть, сколько они памяти реально жрут. Уж точно не сотню килобайт ) Это зелёные потоки - те да, жрут существенно меньше.

vinvlad ★★
()
Ответ на: комментарий от vinvlad

Может и не CoW, но точно помню, что меня уверяли, что он далеко меньше 8 заявленных системой мегабайт

makoven ★★★★★
() автор топика
Ответ на: комментарий от makoven

На самом деле, в Gunicorn поддерживается куча всяких разных типов воркеров - и затраты памяти у них могут быть разные. Тут я настаивать на каких-то цифрах не буду - проще запустить и посмотреть в реальности.

Я, в общем-то, исходил из обычных затрат PHP-шных воркеров - там это несколько мегов.

vinvlad ★★
()

Что касается разных типов воркеров в Gunicorn, советую обратить внимание на Async Workers. Там для обрабоки запросов используются «зелёные» потоки - более оптимальные в плане использования памяти и процессора. Ну и число одновременно обрабатываемых запросов там «чуток» побольше - задается параметром worker_connections (по умолчанию - 1000).

vinvlad ★★
()
Ответ на: комментарий от vinvlad

Это пляски с gevent monkey.patch_all. Надо попробовать, конечно, но выглядит подозрительно

makoven ★★★★★
() автор топика
Ответ на: комментарий от resurtm

aiohttp вызывает, мягко говоря, некоторые неудобства при работе с ORM и прочими синхронными вещами

makoven ★★★★★
() автор топика

Для решения каждой подзадачи можно выбирать отдельный, наиболее подходящий «инструмент» - всё это можно оформлять в виде отдельных backend-сервисов, стоящих за NGINX, или, чтобы обойтись без NGINX, выносить на отдельный поддомен с другим IP-шником. Причем, в одни backend-сервисы можно проксировать HTTP-запросы из NGINX с предварительной буферизацией, в другие — напрямую, без буферизации (это там, где хочется иметь более гибкий контроль над TCP-соединением и поступающими по нему данными).

При выборе конкретного решения нужно чётко осознавать, что будет узким местом при выполнении каждой подзадачи, поскольку на входе в это «узкое место» нужно организовывать какую-то очередь - иначе при всплесках нагрузки на сервер будут выскакивать отказы при выполнении запросов.

Типичным узким местом, к примеру, является работа с базой данных - в силу ограничений на общее количество параллельных соединений с БД. Собственно, при работе с БД обычных синхронных воркеров, их число и выбирается исходя из указанных соображений и еще наличия имеющихся аппаратных ресурсов. В этом случае NGINX оперативно «высасывает» и буферизует из сетевого интерфейса поступающие запросы (сетевой вход исключается из числа узких мест), а в качестве «очереди» выступает TCP-шный backlog порта листинера на стороне backend-части (следует обращать внимание на правильную настройку этого параметра — он должен быть достаточно большим).

При использовании «зелёных» потоков или асинхронного стиля обработки (типа NodeJS) в backend-части появляется возможность параллельного обслуживания гораздо большего числа входящих соединений, но возникает задача «ручного» разруливания узких мест. Какие-то длительные вычисления нужно выносить в фоновую обработку, чтобы не стопорить работу основных обрабатывающих потоков. Для работы с базой данных тоже нужен какой-то регулирующий механизм типа семафоров или специального пула внутренних потоков, непосредственно выполняющих обращение к базе данных. Ну или вообще можно задействовать какой-то внешний промежуточный посредник-балансировщик между БД и backend-частью.

Вот, собственно, базовые премудрости, которые нужно держать в голове при выборе варианта реализации. Как-то так...

vinvlad ★★
()

Много умного уже написано, поэтому для баланса спрошу глупое.
Чем именно занят бэкенд и прочие воркеры? Что показывает профилировщик/логи/top/strace и прочее?
Я не могу понять, как три фотки на любом количестве CPU могут так завесить сервис.

zolden ★★★★★
()
Ответ на: комментарий от zolden

Я не могу понять, как три фотки на любом количестве CPU могут так завесить сервис

А чего ж тут непонятного? ) Cлово «завесить» - это, конечно, перебор. Просто работает сервер всего с тремя обычными синхронными воркерами, без всякого NGINX впереди - соответственно, когда все три воркера заняты приемом фоток, другие соединения уже не принимаются, а просто стоят в backlog-очереди.

vinvlad ★★
()

3 юзера одновременно начинают заливать фото -> сервис парализован: даже гет-запросы перестают обрабатываться

PHP-шник (я) ничего не понял. Как такое возможно? Почему только 3 воркера?

anonymous
()
Ответ на: комментарий от anonymous

Ну три воркера всего. Так в настройках указано. Кончились они, свободные. А файлы большие, или соединение медленное.

Как пхпешник можешь открыть две вкладки в браузере с одним и тем же урл файла с кодом:

<?php

session_start();
sleep(15);

?>

Complete!
Тут хоть сто воркеров, а «висеть» будет.

deep-purple ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.