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:
Servidor | Número de clientes | Servidor RPS | RPS por cliente | carga útil (bytes) |
---|
LAppS 0.7.0 | 240 | 84997 | 354.154 | 128 |
uWebSockets (mais recente) | 240 | 74172.7 | 309.053 | 128 |
LAppS 0.7.0 | 240 | 83627.4 | 348.447 | 512 |
uWebSockets (mais recente) | 240 | 71024.4 | 295.935 | 512 |
LAppS 0.7.0 | 240 | 79270,1 | 330.292 | 1024 |
uWebSockets (mais recente) | 240 | 66499,8 | 277.083 | 1024 |
LAppS 0.7.0 | 240 | 51621 | 215.087 | 8192 |
uWebSockets (mais recente) | 240 | 45341,6 | 188.924 | 8192 |
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 ocultobitmex={} bitmex.__index=bitmex bitmex.init=function() end - bitmex.run=function()
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
Servidor | Número de clientes | Servidor RPS | RPS por cliente | carga útil (bytes) |
---|
LAppS 0.7.0-Upstream | 400 | 257828 | 644,57 | 1024 |
nginx & lua-resty-websocket 4 trabalhadores | 400 | 33788 | 84,47 | 1024 |
websocketpp | 400 | 9789,52 | 24,47 | 1024 |
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
Servidor | Número de clientes | Servidor RPS | RPS por cliente | carga útil (bytes) |
---|
LAppS 0.7.0-upstream | 400 | 439700 | 1099.25 | 1024 |
uWebSockets-upstream | 400 | 247549 | 618,87 | 1024 |
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