Pergunta

Eu desenvolvi um servidor HTTP mini-em C ++, usando boost :: asio, e agora estou carga testando-a com vários clientes e eu fui incapaz de chegar perto de saturar a CPU. Estou testando em uma instância Amazon EC2, e recebendo sobre o uso de 50% de uma CPU, 20% de outro, e os dois restantes estão ociosos (de acordo com htop).

Detalhes:

  • Os incêndios servidor até um thread por núcleo
  • Os pedidos são recebidos, analisados, processados, e as respostas são escritas
  • Os pedidos são de dados, que é lido fora de memória (somente leitura para este teste)
  • Eu sou 'carregar' o servidor usando duas máquinas, cada um executando um aplicativo java, correndo 25 tópicos, o envio de pedidos
  • eu estou vendo cerca de 230 solicitações / rendimento sec (isto é aplicativo solicitações, que são compostas de muitas solicitações HTTP)

Então, o que devo olhar para melhorar este resultado? Dada a CPU é mais ocioso, eu gostaria de alavancagem que a capacidade adicional para obter um rendimento mais elevado, dizer 800 solicitações / s ou o que quer.

Idéias que eu tive:

  • Os pedidos são muito pequenas, e muitas vezes preenchidas em poucos ms, eu poderia modificar o cliente para enviar / compor pedidos maiores (talvez usando lotes)
  • Eu poderia modificar o servidor HTTP para usar o padrão Select design, é este apropriado aqui?
  • Eu poderia fazer alguma profiling para tentar entender o que o gargalo é / são
Foi útil?

Solução

boost :: asio não é tão thread-friendly como você poderia esperar - há um grande bloqueio em torno do código epoll em boost / ASIO / detail / epoll_reactor.hpp o que significa que apenas um thread pode pôr em syscall epoll do kernel de uma vez. E para muito pequenas solicitações isso faz toda a diferença (ou seja, você só vai ver o desempenho cerca de single-threaded).

Note que esta é uma limitação de como boost :: use ASIO as instalações do kernel do Linux, não necessariamente o kernel Linux em si. O syscall epoll suporta vários segmentos ao usar eventos disparados por borda, mas fazê-lo direito (sem bloqueio excessiva) pode ser bastante complicado.

BTW, tenho vindo a fazer algum trabalho nesta área (combinando um epoll ciclo de eventos disparado por borda totalmente multithreaded com fios programado pelo usuário / fibras) e fez algum código disponível sob a um href = "http <: // nginetd.cmeerw.org" rel = "noreferrer"> nginetd projeto.

Outras dicas

Como você está usando EC2, todas as apostas estão fora.

Tente usando hardware real, e então você pode ser capaz de ver o que está acontecendo. Tentando fazer testes de desempenho em VMs é basicamente impossível.

Eu ainda não funcionou o EC2 é útil para, se alguém descobrir, por favor me avise.

De seus comentários sobre a utilização da rede,
Você não parece ter muito movimento rede.

3 + 2.5 MiB/sec é em torno do 50Mbps bola-parque (em comparação com a sua porta de 1Gbps).

Eu diria que você está tendo um dos dois problemas a seguir,

  1. insuficiente carga de trabalho (baixa solicitação de taxa de seus clientes)
    • Bloqueio no servidor (geração de resposta interferida)

Olhando para as notas de cmeerw e seus números de utilização da CPU
(Marcha lenta na 50% + 20% + 0% + 0%)
parece mais provável uma limitação na sua implementação do servidor.
Eu respondo segundo cmeerw (+1).

230 pedidos / seg parece muito baixo para tais solicitações simples assíncronos. Como tal, usando vários segmentos é provavelmente otimização prematura - fazê-lo funcionar corretamente e sintonizado em um único segmento, e veja se você ainda precisa deles. Apenas se livrar de bloqueio necessária-un pode fazer as coisas até a velocidade.

Este artigo tem algum detalhe e discussão sobre I estratégias de E / S para o servidor web desempenho de estilo circa 2003. Qualquer um algo mais recente obtida?

ASIO é bom para pequenas e médias tarefas, mas não é muito bom em alavancar o poder do sistema subjacente. Nem são chamadas de soquete matérias, ou mesmo IOCP no Windows, mas se você é experiente, você sempre será melhor do que ASIO. De qualquer forma, há uma grande quantidade de sobrecarga com todos esses métodos, apenas mais com ASIO.

Por que vale a pena. usando chamadas de soquete matérias sobre meu costume HTTP pode servir 800K solicitações dinâmicas por segundo com um I7 4 núcleos. Ele está servindo de RAM, que é onde você precisa ser para esse nível de desempenho. Neste nível de desempenho do driver de rede e sistema operacional estão consumindo cerca de 40% da CPU. Usando ASIO posso obter em torno de 50 a 100 mil pedidos por segundo, o seu desempenho é bastante variável e principalmente ligado no meu aplicativo. A mensagem por @cmeerw principalmente explica o porquê.

Uma maneira de melhorar o desempenho é através da implementação de um proxy UDP. Interceptando solicitações HTTP e, em seguida, roteamento-los sobre UDP para o servidor UDP-HTTP backend você pode ignorar um monte de TCP sobrecarga nas pilhas do sistema operacional. Você também pode ter extremidades dianteiras qual o tubo através de UDP-se, o que não deve ser muito difícil de fazer sozinho. Uma vantagem de um proxy HTTP-UDP é que ele permite que você use qualquer bom frontend sem modificação, e você pode trocá-los à vontade, sem qualquer impacto. Você só precisa de um par de mais servidores para implementá-lo. Esta modificação no meu exemplo baixou o uso da CPU OS a 10%, o que aumentou os meus pedidos por segundo para pouco mais de um milhão naquele único backend. E FWIW Você deve sempre ter uma configuração frontend-backend para qualquer site performance porque as interfaces pode armazenar em cache de dados sem abrandar o mais importante backend solicitações dinâmicas.

O futuro parece estar escrevendo o seu próprio driver que implementa sua própria pilha de rede para que você possa chegar o mais próximo às solicitações quanto possível e implementar seu próprio protocolo de lá. O que provavelmente não é o que a maioria dos programadores querem ouvir como é mais complicado. No meu caso eu seria capaz de usar 40% mais CPU e passar para mais de 1 milhão de solicitações dinâmicas por segundo. O método de proxy UDP pode chegar perto de um ótimo desempenho sem a necessidade de fazer isso, mas você vai precisar de mais servidores - embora se você estiver fazendo isso muitas solicitações por segundo normalmente você vai precisar de várias placas de rede e múltiplas interfaces para lidar com a largura de banda para ter um par leve proxies UDP em que não há esse negócio um grande.

Hope alguns isso pode ser útil.

Como muitos casos de io_service você tem? Asio impulso tem uma exemplo que cria um io_service por CPU e usá-los na forma de RoundRobin.

Você ainda pode criar quatro linhas e um atribuir por CPU, mas cada thread pode pesquisar por conta própria io_service.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top