
Comparação de várias ferramentas (RabbitMQ, Crossbar.io, Nats.io, Nginx, etc.) para organizar RPC entre microsserviços.
Teste de multiprocessador Artigo atualizado 2019-12-15Resumo . A implementação de chamadas RPC síncronas por meio do sistema MQ clássico não é eficaz - fornece desempenho reduzido e efeitos colaterais que precisam ser enrolados manualmente (ou com ferramentas adicionais).
O Inverted Json é um servidor de tarefas leve que permite fazer chamadas RPC síncronas "honestas" (o cliente e o servidor se conectam via Json invertido para enviar informações), o que garante alto desempenho (7 vezes mais rápido que o RabbitMQ) e a comunicação ocorre via http , que permite o uso de qualquer ferramenta http, que pode ser enrolada no console.
1. Testes
Todas as ferramentas são divididas em 3 grupos:
- “Conexão direta” - quando o cliente se dirige diretamente ao trabalhador, em projetos com um grande número de trabalhadores / serviços é o mais difícil de configurar, requer um “cliente inteligente”, ou seja, ao ligar, o cliente deve ter informações sobre como e para onde enviar a solicitação (ou é necessário um proxy local adicional), como regra, produz menos carga na rede.
- “Conexão proxy” - uma variante com um único ponto de entrada, um cliente simples, mas ao mesmo tempo as dificuldades permanecem do lado dos trabalhadores / seriais - encaminhando e alocando portas, registrando endereços para proxies, configurações de firewall mais complicadas, ferramentas adicionais são frequentemente usadas para gerenciar todo esse farm .
- “Conexão invertida” - um único ponto de entrada para clientes e trabalhadores (pode ser considerado como um ESB), a configuração de rede mais simples.
- Uso de memória e processador extraído de `docker stats`
- No teste "2 núcleos", o servidor e os clientes com as quebras são divididos em núcleos diferentes para reduzir a influência um do outro, portanto, o servidor é limitado a 2 núcleos através do conjunto de tarefas (teste de núcleos sem restrições)
Algumas reflexões sobre o benchmark abaixo.
2. MQ ou RPC
Embora esses dois métodos de comunicação sejam diferentes, às vezes o primeiro é usado em vez do segundo e vice-versa.
Se você tentar delinear os limites, quando usar o quê, poderá obter algo assim:
- RPC (chamada de procedimento síncrono) - quando o cliente exige uma resposta imediatamente (em um curto período de tempo), quando o trabalhador precisa responder enquanto espera por uma resposta e se o cliente sai (por tempo limite), essa resposta não é mais necessária (é por isso que você não precisa salvar " request ”, como costuma ser feito nos sistemas MQ).
Por exemplo, quando você faz uma consulta no banco de dados - você faz RPC, não deseja usar o MQ para isso. - MQ (chamada de procedimento assíncrona) - quando a resposta não é necessária (imediatamente), quando você só precisa concluir algum tipo de tarefa no final ou apenas transferir dados.
Por exemplo, para enviar cartas, você pode enviar uma tarefa via MQ
3. RPC sobre RabbitMQ
O RabbitMQ é frequentemente usado para organizar RPCs, mas como sistemas MQ semelhantes, ele cria uma sobrecarga adicional, e é por isso que seu uso não é muito produtivo.
Se você usar a "fila" para RPC, precisará limpar os canais, porque se o trabalhador tiver caído por algum tempo, depois de reiniciar, ele poderá executar várias tarefas irrelevantes, porque os clientes enviaram solicitações todo esse tempo e, além disso, esperaram em vão por uma resposta. o trabalhador não estava ativo. No total, o trabalhador receberá a tarefa mesmo que o cliente tenha saído antes, o mesmo com o cliente, se o canal do cliente não for contado, ele poderá ficar entupido com as respostas não recebidas do trabalhador, embora seja possível fechar o canal do cliente no RabbitMQ, mas ao mesmo tempo o desempenho seja reduzido drasticamente.
Você também precisa fazer um porco trabalhar para saber se ele está vivo.
Além disso, os recursos são gastos no trabalho com canais, quando nos sistemas RPC os dados são simplesmente enviados ao trabalhador e vice-versa.
4. Json invertido
Existem muitos sistemas MQ diferentes, mas não há muitos RPCs (Job Servers), como o Gearman / Crossbar.io, são escolhas muito pequenas, portanto os desenvolvedores geralmente usam os sistemas MQ para RPCs.
Portanto, o
JSON invertido (iJson) foi criado - um servidor proxy com uma interface http em que clientes e trabalhadores se conectam como um cliente de rede: [client] -> [Json invertido] <- [worker], escrito em C / C ++, usa epoll, máquinas de estado para roteamento, analisador json de streaming, fatias em vez de strings *, etc. maneiras de obter melhor desempenho.
Vantagens do JSON invertido sobre o RabbitMQ:- Não há necessidade de limpar canais de cliente e trabalhador de mensagens não recebidas
- Não é necessário executar ping no trabalhador, o cliente receberá um erro imediatamente se o trabalhador desconectar (com uma conexão keepalive)
- API mais fácil - apenas uma solicitação http (como regra, ela já é suportada por todos os idiomas e estruturas)
- Funciona mais rápido e consome menos memória
- Uma maneira mais fácil de enviar comandos para um trabalhador específico (por exemplo, se houver vários trabalhadores na fila, mas você precisar trabalhar com um específico)
Outras informações do Json invertido- A capacidade de transferir dados binários (não apenas json, como o nome pode sugerir)
- Não é necessário especificar o id se o trabalhador estiver conectado como keep-alive, o Inverted Json simplesmente conecta o cliente e o trabalhador diretamente.
- A capacidade de "assinar" vários comandos (canais), assinar um padrão (por exemplo, comando / *) sem perder o desempenho.
- A imagem do Docker tem apenas 2,6 MB (versão reduzida)
- Json invertido do kernel apenas ~ 1400 linhas de código (v0.3), menos código - menos bugs;)
- JSON invertido não modifica o corpo da solicitação (corpo), mas o envia como está.
5. Experimente o Json invertido em 3 minutos
Você pode experimentar o Json invertido agora mesmo se tiver o
Docker e
enrolar :

Descrição da imagem:
1) Iniciando a imagem do Docker
Json invertido na porta 8001, --log 47 registra solicitações de entrada, etc .:
$ docker run -it -p 8001:8001 lega911/ijson --log 47
2) Registre o trabalhador para a tarefa "calc / sum" e aguarde a tarefa, solicite o tipo "get", ou seja, - obtenha a tarefa:
$ curl localhost/calc/sum -H 'type: get'
3) O cliente faz uma solicitação de calc / soma de RPC:
$ curl localhost/calc/sum -d '{"id": 15, "data": "2+3"}'
4) O trabalhador recebe a tarefa `{" id ": 15," data ":" 2 + 3 "}` - os dados permanecem inalterados, agora você precisa enviar o resultado para o mesmo id, o tipo de solicitação é "result":
$ curl localhost -H 'type: result' -d '{"id": 15, "result": 5}'
... e o cliente obtém o resultado como é
`{"id": 15, "result": 5}`
5.1 Jsonrpc
O JsonRPC 2 não é suportado, mas existem alguns rudimentos, por exemplo, o cliente pode enviar solicitações como (url / rpc / call):
{"jsonrpc": "2.0", "method": "calc/sum", "params": [42, 23], "id": 1}
aceite erros como:
{"jsonrpc": "2.0", "error": {"code": -32601, "message": "Method not found"}, "id": null}
No entanto, se houver demanda, o suporte ao JsonRPC poderá ser aprimorado.
5.2 Exemplo de cliente e trabalhador Python
E aqui você pode encontrar um exemplo no "modo de trabalho", que é mais produtivo e compacto.
6. Algumas reflexões sobre o resultado do benchmark
- Crossbar.io : é baseado em python, portanto, não é tão rápido e não pode usar vários núcleos devido ao GIL.
- RabbitMQ : RPC sobre o MQ, que impõe uma sobrecarga adicional. Uma queda rápida no desempenho com carga crescente (não refletida no teste).
- Nats : não é ruim, apesar de inferior a Json Invertido, como RPC sobre MQ também terá os mesmos problemas.
- Json invertido : atingiu o limite da rede (ou seja, iniciar várias cópias de testes em diferentes núcleos não resulta em um resultado melhor no total), mostrou o uso mais eficiente da memória e do processador em relação ao desempenho.
- Nginx : quando o proxy-pass, o desempenho cai rapidamente se o modo keep-alive não estiver ativado (desativado por padrão), devido ao fato de o linux não permitir abrir / fechar muitos soquetes em um curto período de tempo (isso não se reflete no teste).
- Traefik : muito voraz, usou 600% da CPU no pico, inferior a nginx em velocidade
- uvloop (sob assíncio) - oferece um desempenho muito bom, porque mais escritos em C / C ++, para RPC é mais preferível que ZeroMQ
- ZeroMQ - o próprio trabalhador é escrito em Python, por isso foi executado no kernel, embora o teste do multiprocessador consuma mais de 100% da CPU, devido ao fato de o próprio zeromq ser escrito em C / C ++ sem captura GIL. Ele oferece um ótimo desempenho, mas, por outro lado, se o trabalhador não apenas a + b, qualquer complicação levará a uma redução significativa na RPC, porque atingirá o núcleo ainda mais cedo.
- ZeroRPC : declarado como um invólucro leve sobre o ZeroMQ, na realidade, 95% do desempenho do ZeroMQ é perdido, parece que não é tão leve.
- GRPC : a opção para python produz muito código python clichê, ou seja, o processador acaba por ser pesado e repousa rapidamente na CPU, para idiomas compilados provavelmente não existe esse problema.
- Testes de dois e vários núcleos, em vários núcleos, alguns indicadores diminuíram, porque é preciso competir pelos recursos da CPU com o código de teste do cliente; por outro lado, alguns testes deram um ótimo desempenho, como o Traefik, que consumiu 600% da CPU
7. Conclusão
Se você possui uma empresa grande e muitos funcionários, pode dar suporte a várias ferramentas complexas para organizar conexões diretas entre microsserviços, o que pode fornecer uma comunicação eficaz.
E para pequenas empresas e startups, onde uma pequena equipe precisa resolver problemas de vários campos, o Inverted Json pode economizar tempo e recursos.
Para o desenvolvimento do Inverted Json, os planos incluem suporte para pubsub, kubernetes e outras idéias interessantes.
Se você está interessado no projeto ou apenas deseja ajudar o autor, pode colocar um asterisco no
projeto github , obrigado.
PS:
- Demorou mais tempo para criar este artigo, incluindo testes, do que para criar o próprio Json invertido
- Os protótipos Json invertidos também foram escritos em 1. python + asyncio + uvloop, 2. em GoLang
- Os testes foram revisados por diferentes especialistas.
- “Fatias em vez de cadeias” - na maioria dos casos, ao analisar http / json, os dados não são copiados para cadeias, mas o link para os dados de origem é usado, portanto, não há alocação e cópia desnecessárias de memória.
- Se você testará - não use solicitações no python, é muito lento, melhor que o pycurl, esse wrapper é usado nos testes.
- A referência é aqui
- Fontes aqui