LAppS: Meio milhão de mensagens de 1 KB-WebSocket por segundo com TLS em uma CPU

Para quem não conhece: LAppS - Lua Application Server , é quase como nginx ou apache, mas apenas para o protocolo WebSocket, em vez de HTTP.


O HTTP nele é suportado apenas no nível da solicitação de atualização.


O LAppS foi originalmente aprimorado para alta carga e escalabilidade vertical, e hoje atingiu o pico de suas capacidades no meu hardware (bem, quase, você pode otimizar ainda mais, mas será um trabalho longo e árduo).


Mais importante, o LAppS em termos de desempenho da pilha do WebSocket superou a biblioteca uWebSockets, posicionada como a implementação mais rápida do WebSocket.


Interessado por favor sob o gato.


Faz alguns meses desde o meu último artigo do LAppS , esse artigo não despertou interesse. Espero que este artigo pareça mais interessante para os Khabrovitas. O LAppS durante esse período fez um caminho bastante difícil para a versão 0.7.0, cheio de funcionalidades e cresceu em termos de desempenho (prometido anteriormente).


Um dos recursos que apareceram: um módulo carregável com a implementação da parte do cliente do protocolo WebSocket, - cws.


Graças a este módulo, finalmente consegui extrair tudo do meu computador doméstico e carregar o LAppS de verdade.


Os testes anteriores foram realizados usando o cliente ebs da biblioteca websocketpp (mais detalhes podem ser encontrados na página do github do projeto), que não é apenas lenta, mas também difícil de paralelizar. Os testes foram realizados de maneira simples: vários clientes foram iniciados, os resultados de cada cliente foram coletados usando awk e a aritmética simples produziu resultados de desempenho. Os resultados foram os seguintes:


ServidorNúmero de clientesServidor RPSRPS por clientecarga útil (bytes)
LAppS 0.7.024084997354.154128
uWebSockets (mais recente)24074172.7309.053128
LAppS 0.7.024083627.4348.447512
uWebSockets (mais recente)24071024.4295.935512
LAppS 0.7.024079270,1330.2921024
uWebSockets (mais recente)24066499,8277.0831024
LAppS 0.7.024051621215.0878192
uWebSockets (mais recente)24045341,6188.9248192

Nesse teste, assim como no número subsequente de pacotes, na verdade, é duas vezes maior. a medição é executada em on_message e, no método on_message do cliente, um novo pacote do mesmo tamanho é enviado. I.e. a solicitação do cliente e a resposta do servidor são do mesmo tamanho e, se você considerar a quantidade de tráfego processada pelo servidor, precisará duplicar o resultado do RPS, multiplicando-o por carga útil e negligenciando os cabeçalhos, poderá obter uma quantidade aproximada de tráfego em bytes.


Obviamente, com a operação simultânea de 240 processos do cliente, o próprio LAppS (como o uWebSockets) não tem muitos recursos de CPU restantes.


Eu observei várias implementações de clientes para o WebSocket em Lua e, infelizmente, não encontrei um módulo simples e suficientemente produtivo com o qual eu pudesse carregar o LAppS corretamente. Portanto, como sempre fez sua bicicleta.


O módulo possui uma interface bastante simples e imita o comportamento da API WebSocket do navegador


Um exemplo simples de como trabalhar com este módulo (um serviço para receber transações com o BitMEX):


Texto oculto
bitmex={} bitmex.__index=bitmex bitmex.init=function() end - bitmex.run=function() --   BitMEX local websocket,errmsg=cws:new( "wss://www.bitmex.com/realtime", { ["onopen"]=function(handler) --   WebSocket    local result, errstr=cws:send(handler,[[{"op": "subscribe", "args": ["orderBookL2:XBTUSD"]}]],1); --    1 (OpCode 1 - ) if(not result) --     , -  then print("Error on websocket send at handler "..handler..": "..errstr); end end, ["onmessage"]=function(handler,message,opcode) print(message) --     BitMEX   . end, ["onerror"]=function(handler, message) --    print(message..". Socket FD: "..handler); end, ["onclose"]=function(handler) --     print("WebSocket "..handler.." is closed by peer."); end }); if(websocket == nil) --     then print(errmsg) else while not must_stop() do cws:eventLoop(); -- poll  end end end return bitmex; 

Eu te aviso imediatamente, o módulo apareceu apenas hoje e está mal testado.


Para testar, escrevi um serviço simples para o LAppS e chamei de o mesmo benchmark despretensioso.


Esse serviço no início cria 100 conexões com o servidor de eco WebSocket (não importa qual) e, se a conexão for bem-sucedida, ele envia uma mensagem de 1kb. Ao receber uma mensagem do servidor, ela a envia de volta.


Meu computador doméstico: CPU Intel® Core (TM) i7-7700 a 3,60GHz, microcódigo 0x5e
Memória: DIMM DDR4 síncrono sem buffer (não registrado) 2400 MHz (0,4 ns), Kingston KHX2400C15 / 16G


Todos os testes foram realizados neste host local.


Configuração de eco de serviço no LAppS:


  "echo": { "auto_start": true, "instances": 2, "internal": false, "max_inbound_message_size": 16777216, "preload": null, "protocol": "raw", "request_target": "/echo" } 

O parâmetro instance requer que o LAppS inicie dois serviços de eco paralelo.


Configuração do serviço de benchmark (cliente):


  "benchmark" : { "auto_start" : true, "instances": 4, "internal": true, "preload" : [ "cws", "time" ] } 

No início, são criadas 4 instâncias do benchmark de serviço


Resultado com TLS ativado


ServidorNúmero de clientesServidor RPSRPS por clientecarga útil (bytes)
LAppS 0.7.0-Upstream400257828644,571024
nginx & lua-resty-websocket 4 trabalhadores4003378884,471024
websocketpp4009789,5224,471024

O uWebSockets falhou até agora no teste - o handshake TLS jura no SSLv3 (meu cliente usa TLSv1.2 e é cortado no libreSSL SSLv3 que eu uso).


Resultado sem TLS


ServidorNúmero de clientesServidor RPSRPS por clientecarga útil (bytes)
LAppS 0.7.0-upstream4004397001099.251024
uWebSockets-upstream400247549618,871024

Por que no cabeçalho de "meio milhão" de mensagens e no teste 257828? Porque há duas vezes mais mensagens (como foi explicado acima).


uWebsockets, mostra resultados inviáveis ​​neste teste, apenas porque funciona no 1º núcleo, a versão multiencadeada do uWebSockets do repositório do projeto não funciona e, quando o TLS é ativado, ele tem corrida de dados na pilha OpenSSL.


Se você imagina que o uWebSockets funciona bem em 2 núcleos (como 2 serviços de eco LAppS), ele pode ser configurado como 495098 RPS condicionalmente (apenas o dobro do resultado da tabela).


Mas você precisa considerar que o servidor de eco ( uWebSockets ) não faz nada com os dados recebidos, mas envia de volta imediatamente. LAppS passa dados para a pilha Lua correspondente ao serviço.


Novidades do LAppS


  • Módulo de autenticação PAM pam_auth
  • Módulo de fila de mensagens: mqr - para troca de mensagens entre serviços no mesmo servidor LAppS (para troca de vários servidores, você precisa usar algo já existente, por exemplo: RabbitMQ, mosquitto, etc)
  • Conexões de rede ACL

Tudo isso pode ser encontrado na página wiki do projeto.


Bem, para um lanche, para os conhecedores, o que exatamente o LAppS faz durante este teste.


Sem TLS


Texto oculto
   iptables. 4.98% lapps [ip_tables] [k] ipt_do_table     3.80% lapps [kernel.vmlinux] [.] syscall_return_via_sysret       Lua  3.52% lapps libluajit-5.1.so.2.0.5 [.] lj_str_new    WebSocket  1.96% lapps lapps [.] WSStreamProcessing::WSStreamServerParser::parse     1.88% lapps [kernel.vmlinux] [k] copy_user_enhanced_fast_string 1.81% lapps [kernel.vmlinux] [k] __fget 1.61% lapps [kernel.vmlinux] [k] tcp_ack 1.49% lapps [kernel.vmlinux] [k] _raw_spin_lock_irqsave 1.48% lapps [kernel.vmlinux] [k] sys_epoll_ctl 1.45% lapps [xt_tcpudp] [k] tcp_mt  LAppS 1.35% lapps lapps [.] LAppS::IOWorker<false, true>::execute   1.28% lapps lapps [.] cws_eventloop ... 1.27% lapps [nf_conntrack] [k] __nf_conntrack_find_get.isra.11 1.14% lapps [kernel.vmlinux] [k] __inet_lookup_established 1.14% lapps libluajit-5.1.so.2.0.5 [.] lj_BC_TGETS      C++ 1.01% lapps lapps [.] LAppS::Application<false, true, (abstract::Application::Protocol)0>::execute ... 0.98% lapps [kernel.vmlinux] [k] ep_send_events_proc 0.98% lapps [kernel.vmlinux] [k] tcp_recvmsg 0.96% lapps libc-2.26.so [.] __memmove_avx_unaligned_erms 0.93% lapps libc-2.26.so [.] malloc 0.92% lapps [kernel.vmlinux] [k] tcp_transmit_skb 0.88% lapps [kernel.vmlinux] [k] sock_poll 0.85% lapps [nf_conntrack] [k] nf_conntrack_in 0.83% lapps [nf_conntrack] [k] tcp_packet 0.79% lapps [kernel.vmlinux] [k] do_syscall_64 0.78% lapps [kernel.vmlinux] [k] ___slab_alloc 0.78% lapps [kernel.vmlinux] [k] _raw_spin_lock_bh 0.73% lapps libc-2.26.so [.] _int_free 0.69% lapps [kernel.vmlinux] [k] __slab_free 0.66% lapps libcryptopp.so.5.6.5 [.] CryptoPP::Rijndael::Base::UncheckedSetKey 0.66% lapps [kernel.vmlinux] [k] tcp_write_xmit 0.65% lapps [kernel.vmlinux] [k] sock_def_readable 0.65% lapps [kernel.vmlinux] [k] tcp_sendmsg_locked 0.64% lapps libc-2.26.so [.] vfprintf     ( - bemchmark) 0.64% lapps lapps [.] LAppS::ClientWebSocket::send ... 0.64% lapps [kernel.vmlinux] [k] tcp_v4_rcv 0.63% lapps [kernel.vmlinux] [k] __alloc_skb 0.61% lapps lapps [.] std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release 0.61% lapps [kernel.vmlinux] [k] _raw_spin_lock 0.60% lapps libc-2.26.so [.] __memset_avx2_unaligned_erms 0.60% lapps [kernel.vmlinux] [k] kmem_cache_alloc_node 0.59% lapps libluajit-5.1.so.2.0.5 [.] lj_tab_get 0.59% lapps [kernel.vmlinux] [k] __local_bh_enable_ip 0.58% lapps [kernel.vmlinux] [k] __dev_queue_xmit 0.57% lapps [kernel.vmlinux] [k] nf_hook_slow 0.55% lapps [kernel.vmlinux] [k] ep_poll_callback 0.55% lapps [kernel.vmlinux] [k] skb_release_data 0.54% lapps [kernel.vmlinux] [k] native_queued_spin_lock_slowpath 0.54% lapps libc-2.26.so [.] cfree@GLIBC_2.2.5 0.53% lapps [kernel.vmlinux] [k] ip_finish_output2 0.49% lapps libluajit-5.1.so.2.0.5 [.] lj_BC_RET 0.49% lapps libc-2.26.so [.] __strlen_avx2 0.48% lapps [kernel.vmlinux] [k] _raw_spin_unlock_irqrestore 

Encontraremos 10 diferenças ao trabalhar com TLS


Texto oculto
  3.73% lapps [kernel.vmlinux] [k] syscall_return_via_sysret 3.49% lapps libcrypto.so.43.0.1 [.] gcm_ghash_clmul 3.42% lapps libcrypto.so.43.0.1 [.] aesni_ctr32_encrypt_blocks 2.74% lapps [ip_tables] [k] ipt_do_table 2.17% lapps libluajit-5.1.so.2.0.5 [.] lj_str_new 1.41% lapps libpthread-2.26.so [.] __pthread_mutex_lock 1.34% lapps libssl.so.45.0.1 [.] tls1_enc 1.32% lapps [kernel.vmlinux] [k] __fget 1.16% lapps libcrypto.so.43.0.1 [.] getrn 1.06% lapps libc-2.26.so [.] __memmove_avx_unaligned_erms 1.06% lapps lapps [.] WSStreamProcessing::WSStreamServerParser::parse 1.05% lapps [kernel.vmlinux] [k] tcp_ack 1.02% lapps [kernel.vmlinux] [k] copy_user_enhanced_fast_string 1.02% lapps [nf_conntrack] [k] __nf_conntrack_find_get.isra.11 0.98% lapps lapps [.] cws_eventloop 0.98% lapps [kernel.vmlinux] [k] native_queued_spin_lock_slowpath 0.93% lapps libcrypto.so.43.0.1 [.] aead_aes_gcm_open 0.92% lapps lapps [.] LAppS::IOWorker<true, true>::execute 0.91% lapps [kernel.vmlinux] [k] tcp_recvmsg 0.89% lapps [kernel.vmlinux] [k] sys_epoll_ctl 0.88% lapps libcrypto.so.43.0.1 [.] aead_aes_gcm_seal 0.84% lapps [kernel.vmlinux] [k] do_syscall_64 0.82% lapps [kernel.vmlinux] [k] __inet_lookup_established 0.82% lapps [kernel.vmlinux] [k] tcp_transmit_skb 0.79% lapps libpthread-2.26.so [.] __pthread_mutex_unlock_usercnt 0.77% lapps [kernel.vmlinux] [k] _raw_spin_lock_irqsave 0.76% lapps [xt_tcpudp] [k] tcp_mt 0.71% lapps libcrypto.so.43.0.1 [.] aesni_encrypt 0.70% lapps [kernel.vmlinux] [k] _raw_spin_lock 0.67% lapps [kernel.vmlinux] [k] ep_send_events_proc 0.66% lapps libcrypto.so.43.0.1 [.] ERR_clear_error 0.63% lapps [kernel.vmlinux] [k] sock_def_readable 0.62% lapps lapps [.] LAppS::Application<true, true, (abstract::Application::Protocol)0>::execute 0.61% lapps libc-2.26.so [.] malloc 0.61% lapps [nf_conntrack] [k] nf_conntrack_in 0.58% lapps libssl.so.45.0.1 [.] ssl3_read_bytes 0.58% lapps libluajit-5.1.so.2.0.5 [.] lj_BC_TGETS 0.57% lapps [kernel.vmlinux] [k] tcp_write_xmit 0.56% lapps libssl.so.45.0.1 [.] do_ssl3_write 0.55% lapps [kernel.vmlinux] [k] __netif_receive_skb_core 0.54% lapps [kernel.vmlinux] [k] ___slab_alloc 0.54% lapps libc-2.26.so [.] __memset_avx2_unaligned_erms 0.51% lapps [kernel.vmlinux] [k] _raw_spin_lock_bh 0.51% lapps libcrypto.so.43.0.1 [.] gcm_gmult_clmul 0.51% lapps [kernel.vmlinux] [k] sock_poll 0.48% lapps [nf_conntrack] [k] tcp_packet 0.48% lapps libc-2.26.so [.] cfree@GLIBC_2.2.5 0.48% lapps libssl.so.45.0.1 [.] SSL_read 0.46% lapps [kernel.vmlinux] [k] copy_user_generic_unrolled 0.45% lapps [kernel.vmlinux] [k] tcp_sendmsg_locked 0.45% lapps lapps [.] LAppS::ClientWebSocket::send 0.44% lapps libc-2.26.so [.] _int_free 0.44% lapps libssl.so.45.0.1 [.] ssl3_read_internal 0.43% lapps [kernel.vmlinux] [k] futex_wake 0.42% lapps libluajit-5.1.so.2.0.5 [.] lj_tab_get 0.42% lapps libc-2.26.so [.] vfprintf 0.41% lapps [kernel.vmlinux] [k] tcp_v4_rcv 

Source: https://habr.com/ru/post/pt421421/


All Articles