O diesel deve ser executado usando um agente de sincronização, actix_web :: web :: block ou futures-cpupool?

10

fundo

Estou trabalhando em um aplicativo actix-web usando diesel através de r2d2 e não tenho certeza de como fazer consultas assíncronas da melhor maneira. Encontrei três opções que parecem razoáveis, mas não tenho certeza de qual é a melhor.

Soluções Potenciais

Ator de sincronização

Por um lado, eu poderia usar o exemplo actix , mas é bastante complicado e requer uma boa dose de clichê para construir. Espero que exista uma solução mais razoável.

Actix_web::web::block

Como outra opção, eu poderia usar o actix_web::web::blockpara agrupar minhas funções de consulta em um futuro, mas não tenho certeza das implicações de desempenho disso.

A consulta está sendo executada no mesmo sistema Tokio? Pelo que pude encontrar na fonte, ele cria um encadeamento no pool de encadeamentos actix-web subjacente . Isso é um problema?

Se eu ler o código corretamente, o r2d2 bloqueia seu encadeamento ao adquirir uma conexão, o que bloquearia parte do pool principal do actix-web. Mesmo com consultas de banco de dados. Isso bloquearia todo o actix-web se eu fizer mais consultas do que ter threads nesse pool? Se assim for, grande problema.

Futuros-cpupool

Finalmente, a aposta segura que pode ter uma sobrecarga desnecessária é o cpupool de futuros . A questão principal é que isso significa adicionar outra caixa ao meu projeto, embora eu não goste da ideia de vários pools de CPUs flutuando no meu aplicativo desnecessariamente.

Como o r2d2 e o diesel bloquearão, há uma quantidade surpreendente de coisas complicadas aqui.

Mais importante, não compartilhe esse cpupool com nada que não esteja usando o mesmo pool r2d2 (pois todos os threads criados podem bloquear a espera de uma conexão r2d2, bloqueando todo o pool quando houver trabalho).

Em segundo lugar (um pouco mais óbvio), você não deveria ter mais conexões r2d2 do que threads no pool e vice-versa, pois a maior desperdiçaria recursos (conexões não utilizadas / threads constantemente bloqueadas) (talvez mais um thread, talvez mais rápido transferência de conexão pelo agendador do SO em vez do agendador do cpupool).

Por fim, lembre-se do banco de dados que você está usando e do desempenho que você tem lá. A execução de uma única conexão r2d2 e um único encadeamento no pool pode ser melhor em um aplicativo sqlite pesado de gravação (embora eu recomende um banco de dados adequado para isso).

Respostas antigas

Soluções antigas que podem funcionar

https://www.reddit.com/r/rust/comments/axy0hp/patterns_to_scale_actixweb_and_diesel/

Em essência, recomenda Futures-cpupool.

Qual é a melhor abordagem para encapsular E / S de bloqueio no futuro-rs?

Recomenda o Futures-cpupool para casos gerais.

Soluções antigas que não funcionam

https://www.reddit.com/r/rust/comments/9fe1ye/noob_here_can_we_talk_about_async_and_databases/

Uma correção muito boa para uma versão antiga do actix-web. Pelo que posso encontrar, os pedidos não têm mais um conjunto de CPUs.

logina
fonte
A partir dos comentários nesta edição , parece que futures-cpupoolé a solução alternativa recomendada para a falta de asyncsuporte no Diesel.
Jmb
Essa é mais uma solução geral. Espero por algo que alavanque o sistema actix. Não obstante, vou explorar o futuro-cpupool agora para procurar problemas.
Logina
Bem-vindo ao Stack Overflow! Parece que sua pergunta pode ser respondida pelas respostas de Qual é a melhor abordagem para encapsular o bloqueio de E / S no futuro-rs? . Caso contrário, edite sua pergunta para explicar as diferenças. Caso contrário, podemos marcar esta pergunta como já respondida.
Shepmaster
Como o cpupool também interage com o conjunto de conexões de bloqueio no r2d2, não tenho certeza de como resolver isso da melhor maneira. Estou pesquisando agora e atualizarei com isso em breve.
Logina

Respostas:

3

Eu estou indo com futuros-cpupool. É a melhor solução devido à natureza de bloqueio das minhas interações.

O uso do actix_web :: web :: block é decente o suficiente, mas utilizará um pool de threads compartilhado no actix (e devido às chamadas de bloqueio que eu uso, isso pode bloquear todo o pool de threads e interferir em outras tarefas atribuídas ao actix_web).

É melhor usar o futures-cpupool para criar um pool de threads separado por banco de dados apenas para interações com o banco de dados. Dessa forma, você agrupa todas as tarefas que precisam esperar uma pela outra (quando há mais tarefas que conexões) em um pool, impedindo-as de bloquear outras tarefas que não precisam de conexão e potencialmente limitando o número de threads ao número de conexões (para que a tarefa seja agendada apenas quando não for bloqueada).

No caso em que você deseja usar apenas uma conexão com o banco de dados (ou muito poucas), o agente de sincronização é uma opção muito boa. Ele agirá como um futuros-cpupool com um encadeamento, garantindo que todas as tarefas sejam executadas uma de cada vez, exceto pelo uso de um dos encadeamentos subjacentes do actix-web em vez de um separado (portanto, apenas bom para pouquíssimas conexões) . Acho que o clichê grande demais para valer a pena, no entanto.

logina
fonte
6
lendo minhas descobertas acima - coloque informações relevantes para a resposta no resposta , não a pergunta.
Shepmaster