Quantas solicitações simultâneas um único processo do Flask recebe?

138

Estou criando um aplicativo com o Flask, mas não sei muito sobre o WSGI e sua base HTTP, Werkzeug. Quando começo a atender a um aplicativo Flask com gunicorn e 4 processos de trabalho, isso significa que posso lidar com 4 solicitações simultâneas?

Quero dizer solicitações simultâneas, e não solicitações por segundo ou qualquer outra coisa.

Carson
fonte

Respostas:

183

Ao executar o servidor de desenvolvimento - que é o que você obtém executando app.run(), você obtém um único processo síncrono, o que significa que no máximo 1 solicitação está sendo processada por vez.

Ao colocar o Gunicorn na frente dele em sua configuração padrão e simplesmente aumentar o número de --workers, o que você obtém é essencialmente um número de processos (gerenciados pelo Gunicorn) que cada um se comporta como o app.run()servidor de desenvolvimento. 4 trabalhadores == 4 solicitações simultâneas. Isso ocorre porque o Gunicorn usa seu synctipo de trabalhador incluído por padrão.

É importante observar que o Gunicorn também inclui trabalhadores assíncronos, a saber eventlete gevent(e também tornado, mas isso é melhor usado com a estrutura do Tornado, ao que parece). Ao especificar um desses trabalhadores assíncronos com a --worker-classbandeira, o Gunicorn gerencia vários processos assíncronos, cada um gerenciando sua própria simultaneidade. Esses processos não usam threads, mas coroutines. Basicamente, dentro de cada processo, ainda apenas uma coisa pode estar acontecendo por vez (1 thread), mas os objetos podem ser 'pausados' enquanto aguardam a conclusão de processos externos (pense em consultas ao banco de dados ou em E / S de rede).

Isso significa que, se você estiver usando um dos trabalhadores assíncronos do Gunicorn, cada trabalhador poderá lidar com muito mais do que uma única solicitação de cada vez. O número de funcionários que é melhor depende da natureza do seu aplicativo, de seu ambiente, do hardware em que ele é executado etc. Mais detalhes podem ser encontrados na página de design do Gunicorn e notas sobre como o gevent funciona em sua página de introdução.

Ryan Artecona
fonte
4
O Gunicorn agora suporta threads "reais" desde a versão 19. Veja isto e isto .
Filipe Correia
2
Como é possível acompanhar quais recursos são compartilhados (e como) e quais são completamente separados entre threads / processos? Por exemplo, como eu lidaria com uma situação em que desejo compartilhar uma enorme estrutura de dados entre vários processos manipulados pelo Gunicorn e usados ​​nos manipuladores do Flask?
precisa
O que você está perguntando @Johsm é como perguntar como compartilhar dados entre diferentes processos dentro do sistema operacional. A resposta para isso pode responder à sua pergunta: você precisa usar armazenamento externo, pois os processos não compartilham sua memória com outros processos. O Gunicorn está aqui apenas para utilizar arquiteturas de CPU de multiprocessamento, mas não lida com esses problemas.
adkl
E Eva? Isso vale para Eva também?
Eswar 15/10/19
2
o servidor de desenvolvimento frasco utiliza threads por padrão desde v1.0 ( github.com/pallets/flask/pull/2529 )
hychou
40

Atualmente, existe uma solução muito mais simples do que as já fornecidas. Ao executar o aplicativo você só tem que passar ao longo do threaded=Trueparâmetro para a app.run()chamada, como:

app.run(host="your.host", port=4321, threaded=True)

Outra opção, de acordo com o que podemos ver nos documentos do werkzeug , é usar o processesparâmetro, que recebe um número> 1, indicando o número máximo de processos simultâneos a serem manipulados:

  • threaded - o processo deve lidar com cada solicitação em um thread separado?
  • processos - se maior que 1, lide com cada solicitação em um novo processo até esse número máximo de processos simultâneos.

Algo como:

app.run(host="your.host", port=4321, processes=3) #up to 3 processes

Mais informações sobre o run()método aqui e a postagem do blog que me levou a encontrar a solução e as referências da API.


Nota: nos documentos do Flask sobre os run()métodos, é indicado que o uso em um ambiente de produção é desencorajado porque ( aspas ): "Embora leve e fácil de usar, o servidor interno do Flask não é adequado para produção, pois não é bem dimensionado. . "

No entanto, eles apontam para a página Opções de implantação , para obter as maneiras recomendadas de fazer isso ao ir para produção.

DarkCygnus
fonte
5
Obrigado pela informação. É importante observar que o documento para execução afirma que não deve ser usado em um ambiente de produção, afirmando que não atende aos requisitos de segurança ou desempenho.
Coffee_fan
1
@Coffee_fan você está certo. Mesmo no 1.1.x mais recente, eles desencorajam isso e, em vez disso, sugerem que verifique a página em Opções de implantação ao ir para a produção. Incluindo sua observação valiosa na resposta :)
DarkCygnus
33

O Flask processará uma solicitação por thread ao mesmo tempo. Se você possui 2 processos com 4 threads cada, são 8 solicitações simultâneas.

O Flask não gera nem gerencia threads ou processos. Essa é a responsabilidade do gateway WSGI (por exemplo, gunicorn).

jd.
fonte
9

Não, você definitivamente pode lidar com mais do que isso.

É importante lembrar que, no fundo, supondo que você esteja executando uma máquina com um único núcleo, a CPU realmente executa apenas uma instrução * por vez.

Nomeadamente, a CPU pode executar apenas um conjunto muito limitado de instruções e não pode executar mais de uma instrução por tick de clock (muitas instruções levam até mais de 1 tick).

Portanto, a maior parte da concorrência de que falamos em ciência da computação é a concorrência de software. Em outras palavras, existem camadas de implementação de software que abstraem a CPU de nível inferior e nos fazem pensar que estamos executando o código simultaneamente.

Essas "coisas" podem ser processos, que são unidades de código que são executadas simultaneamente, no sentido de que cada processo pensa que está sendo executado em seu próprio mundo com sua própria memória não compartilhada.

Outro exemplo são os threads, que são unidades de código dentro de processos que também permitem simultaneidade.

A razão pela qual seus 4 processos de trabalho serão capazes de lidar com mais de 4 solicitações é que eles disparam threads para lidar com mais e mais solicitações.

O limite de solicitação real depende do servidor HTTP escolhido, E / S, SO, hardware, conexão de rede etc.

Boa sorte!

* instruções são os comandos básicos que a CPU pode executar. exemplos - adicione dois números, pule de uma instrução para outra

user1094786
fonte
1
É gunicorn gerando os fios ou frasco? Não encontrei nenhuma evidência apoiando qualquer possibilidade.
jd.
1
Claro, eu entendo isso sobre os processos, mas a resposta diz que mais threads são gerados conforme necessário. É disso que eu gostaria de ter confirmação.
jd.
4
"no fundo, supondo que você esteja executando uma máquina com um único núcleo, a CPU realmente executa apenas uma instrução * por vez" Isso não está correto nas máquinas modernas. A maioria das CPUs modernas possui pipelines e superescalares , onde até um único núcleo possui várias unidades de execução e um decodificador de instruções que converte o "código da máquina" visto do lado do software nas micro-ops reais de hardware que são despachadas para as unidades de execução individuais.
Michael Geary
1
Para esclarecer, na época, as CPUs realmente executavam diretamente as instruções numéricas em um executável - o código da máquina. Cada referência de CPU tinha um gráfico de tempo das instruções mostrando quantos ciclos de relógio cada instrução levou, incluindo todas as referências de memória. Assim, você pode adicionar os horários para saber quanto tempo um pedaço de código levaria. As CPUs modernas não são assim. Uma exceção interessante é o BeagleBone, que possui um processador ARM superescalar moderno e dois processadores "PRU" antiquados com tempo de instrução fixo.
Michael Geary
1
E para esclarecer que , quando eu disse "moderno", eu o estava usando como uma abreviação para processadores como os chips ARM / Intel / AMD - em pipeline, superescalar etc. É claro que também existem processadores modernos que funcionam da maneira antiga com tempo fixo por instrução, como as PRUs BeagleBone que mencionei e vários novos microcontroladores. (E agora de volta para Gunicorn!)
Michael Geary