LAppS: Medio mill贸n de mensajes de 1KB-WebSocket por segundo con TLS en una CPU

Para aquellos que no saben: LAppS - Lua Application Server , es casi como nginx o apache, pero solo para el protocolo WebSocket, en lugar de HTTP.


HTTP solo se admite en el nivel de solicitud de actualizaci贸n.


Originalmente, LAppS se agudiz贸 para una alta carga y escalabilidad vertical, y hoy ha alcanzado el m谩ximo de sus capacidades en mi hardware (bueno, casi, puede optimizar a煤n m谩s, pero ser谩 un trabajo largo y duro).


Lo m谩s importante, LAppS en t茅rminos de rendimiento de la pila de WebSocket ha superado la biblioteca uWebSockets, que se posiciona como la implementaci贸n m谩s r谩pida de WebSocket.


Interesado por favor debajo del gato.


Han pasado un par de meses desde mi 煤ltimo art铆culo de LAppS , ese art铆culo no despert贸 inter茅s. Espero que este art铆culo les parezca m谩s interesante a los Khabrovitas. LAppS durante este tiempo ha hecho un camino bastante dif铆cil hacia la versi贸n 0.7.0, repleto de funcionalidad y ha crecido en t茅rminos de rendimiento (que se prometi贸 anteriormente).


Una de las caracter铆sticas que apareci贸: un m贸dulo cargable con la implementaci贸n de la parte del cliente del protocolo WebSocket, - cws.


Gracias a este m贸dulo, finalmente pude extraer todo de la computadora de mi casa y cargar LAppS de verdad.


Las pruebas anteriores se llevaron a cabo utilizando el cliente ebs de la biblioteca websocketpp (se pueden encontrar m谩s detalles en la p谩gina de github del proyecto), que no solo es lento, sino tambi茅n dif铆cil de paralelizar. Las pruebas se llevaron a cabo simplemente: un grupo de clientes comenz贸, los resultados de cada cliente se recopilaron utilizando awk y la aritm茅tica simple arroj贸 resultados de rendimiento. Los resultados fueron los siguientes:


ServidorNumero de clientesServidor RPSRPS por clientecarga 煤til (bytes)
LAppS 0.7.024084997354,154128
uWebSockets (煤ltimo)24074172.7309.053128
LAppS 0.7.024083627.4348,447512
uWebSockets (煤ltimo)24071024.4295,935512
LAppS 0.7.024079270.1330,2921024
uWebSockets (煤ltimo)24066499.8277.0831024
LAppS 0.7.024051621215,0878192
uWebSockets (煤ltimo)24045341,6188,9248192

En esta prueba, as铆 como en el n煤mero posterior de paquetes, de hecho, es el doble. la medici贸n se realiza en on_message y en el m茅todo on_message del cliente se env铆a un nuevo paquete del mismo tama帽o. Es decir la solicitud del cliente y la respuesta del servidor son del mismo tama帽o, y si considera la cantidad de tr谩fico procesado por el servidor, debe duplicar el resultado de RPS multiplicando por la carga 煤til y descuidando los encabezados, puede obtener una cantidad aproximada de tr谩fico en bytes.


Obviamente, con la operaci贸n simult谩nea de 240 procesos de clientes, a LAppS (como uWebSockets) no le quedan muchos recursos de CPU.


Mir茅 varias implementaciones de clientes para WebSocket en Lua, y desafortunadamente no encontr茅 un m贸dulo simple y suficientemente productivo con el que pudiera cargar LAppS correctamente. Por lo tanto, como siempre lo hizo su bicicleta.


El m贸dulo tiene una interfaz bastante simple e imita el comportamiento del navegador WebSocket API


Un ejemplo simple de c贸mo trabajar con este m贸dulo (un servicio para recibir transacciones con 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; 

Te advierto de inmediato, el m贸dulo apareci贸 solo hoy y est谩 mal probado.


Para las pruebas, escrib铆 un servicio simple para LAppS y lo llam茅 el mismo punto de referencia sin pretensiones.


Este servicio al principio crea 100 conexiones al servidor de eco WebSocket (sin importar cu谩l), y si la conexi贸n es exitosa, env铆a un mensaje de 1 kb. Cuando recibe un mensaje del servidor, lo devuelve.


La computadora de mi casa: Intel庐 Core (TM) i7-7700 CPU @ 3.60GHz, microc贸digo 0x5e
Memoria: DIMM DDR4 Sincr贸nico Sin memoria intermedia (sin registrar) 2400 MHz (0.4 ns), Kingston KHX2400C15 / 16G


Todas las pruebas se llevaron a cabo en este host local.


Configuraci贸n de eco de servicio en LAppS:


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

El par谩metro de instancias requiere LAppS para iniciar dos servicios de eco paralelos.


Configuraci贸n del servicio de referencia (cliente):


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

Al inicio se crean 4 instancias del benchmark de servicio


Resultado con TLS habilitado


ServidorNumero de clientesServidor RPSRPS por clientecarga 煤til (bytes)
LAppS 0.7.0-Upstream400257828644,571024
nginx & lua-resty-websocket 4 trabajadores4003378884,471024
websocketpp4009789.5224,471024

uWebSockets no ha podido probar hasta el momento: el apret贸n de manos de TLS jura sobre SSLv3 (mi cliente usa TLSv1.2 y est谩 cortado en el SSLv3 libreSSL que uso).


Resultado sin TLS


ServidorNumero de clientesServidor RPSRPS por clientecarga 煤til (bytes)
LAppS 0.7.0-upstream4004397001099.251024
uWebSockets-upstream400247549618,871024

驴Por qu茅 en el encabezado de "medio mill贸n" de mensajes, y en la prueba 257828? Porque hay el doble de mensajes (como se explic贸 anteriormente).


uWebsockets, muestra resultados poco envidiables en esta prueba, solo porque funciona en el 1er n煤cleo, la versi贸n multiproceso de uWebSockets del repositorio del proyecto no funciona realmente, y cuando TLS est谩 activado, tiene carrera de datos en la pila OpenSSL.


Si imagina que uWebSockets funciona bien en 2 n煤cleos (como 2 servicios de eco LAppS), entonces se puede configurar condicionalmente 495098 RPS (solo el doble del resultado de la tabla).


Pero debe tener en cuenta que el servidor de eco ( uWebSockets ) no hace nada con los datos recibidos, sino que los env铆a de inmediato. LAppS pasa datos a la pila Lua correspondiente al servicio.


驴Qu茅 hay de nuevo en LAppS?


  • M贸dulo de autenticaci贸n PAM pam_auth
  • M贸dulo de cola de mensajes: mqr: para intercambiar mensajes entre servicios dentro del mismo servidor LAppS (para el intercambio multiservidor, debe usar algo ya existente, por ejemplo: RabbitMQ, mosquitto, etc.)
  • Conexiones de red ACL

Todo esto se puede encontrar en la p谩gina wiki del proyecto.


Bueno, para una merienda, para entendidos, qu茅 hace LAppS exactamente durante esta prueba.


Sin 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 diferencias al trabajar con 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/es421421/


All Articles