LAppS: Eine halbe Million 1 KB WebSocket-Nachrichten pro Sekunde mit TLS auf einer CPU

Für diejenigen, die nicht wissen: LAppS - Lua Application Server , es ist fast wie Nginx oder Apache, aber nur für das WebSocket-Protokoll anstelle von HTTP.


HTTP wird nur auf der Ebene der Upgrade-Anforderung unterstützt.


LAppS wurde ursprünglich für hohe Last und vertikale Skalierbarkeit geschärft und hat heute den Höhepunkt seiner Fähigkeiten auf meiner Hardware erreicht (fast, Sie können weiter optimieren, aber es wird eine lange und harte Arbeit sein).


Am wichtigsten ist, dass LAppS in Bezug auf die Leistung des WebSocket-Stacks die uWebSockets-Bibliothek übertroffen hat, die als schnellste WebSocket-Implementierung positioniert ist.


Interessiert bitte unter Katze.


Es ist ein paar Monate her seit meinem letzten LAppS- Artikel, dieser Artikel hat kein Interesse geweckt. Ich hoffe, dieser Artikel erscheint den Chabrowiten interessanter. LAppS hat in dieser Zeit einen ziemlich schwierigen Weg zur Version 0.7.0 eingeschlagen, ist mit Funktionen überwachsen und hat in Bezug auf die Leistung zugenommen (was früher versprochen wurde).


Eine der Funktionen, die angezeigt wurden: ein ladbares Modul mit der Implementierung des Client-Teils des WebSocket-Protokolls, - cws.


Dank dieses Moduls konnte ich endlich alles aus meinem Heimcomputer herausholen und LAppS wirklich laden.


Frühere Tests wurden mit dem ebs-Client der Websocketpp-Bibliothek durchgeführt (weitere Details finden Sie auf der Github-Projektseite), der nicht nur langsam, sondern auch schwer zu parallelisieren ist. Die Tests wurden einfach durchgeführt: Eine Reihe von Kunden wurde gestartet, die Ergebnisse von jedem Kunden wurden mit awk gesammelt, und einfache Arithmetik ergab Leistungsergebnisse. Die Ergebnisse waren wie folgt:


ServerAnzahl der KundenRPS-ServerRPS pro KundeNutzlast (Bytes)
LAppS 0.7.024084997354,154128
uWebSockets (aktuell)24074172.7309.053128
LAppS 0.7.024083627.4348,447512
uWebSockets (aktuell)24071024.4295,935512
LAppS 0.7.024079270.1330,2921024
uWebSockets (aktuell)24066499.8277.0831024
LAppS 0.7.024051621215.0878192
uWebSockets (aktuell)24045341.6188.9248192

In diesem Test sowie in der nachfolgenden Anzahl von Paketen ist er tatsächlich doppelt so hoch. Die Messung wird für on_message durchgeführt, und bei der on_message-Methode des Clients wird ein neues Paket derselben Größe gesendet. Das heißt, Die Anforderung des Clients und die Antwort des Servers sind gleich groß. Wenn Sie die vom Server verarbeitete Verkehrsmenge berücksichtigen, müssen Sie das RPS-Ergebnis verdoppeln, indem Sie mit der Nutzlast multiplizieren und die Header vernachlässigen. Sie können eine ungefähre Menge an Verkehr in Bytes erhalten.


Offensichtlich verfügt LAppS selbst (wie uWebSockets) bei gleichzeitigem Betrieb von 240 Client-Prozessen nicht mehr über viele CPU-Ressourcen.


Ich habe mir unter Lua mehrere Client-Implementierungen für WebSocket angesehen und leider kein einfaches und ausreichend produktives Modul gefunden, mit dem ich LAppS ordnungsgemäß laden konnte. Deshalb wie immer dein Fahrrad.


Das Modul hat eine ziemlich einfache Oberfläche und ahmt das Verhalten der Browser- WebSocket-API nach


Ein einfaches Beispiel für die Arbeit mit diesem Modul (ein Dienst zum Empfangen von Transaktionen mit BitMEX):


Versteckter Text
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; 

Ich warne Sie sofort, das Modul ist erst heute erschienen und es ist schlecht getestet.


Zum Testen habe ich einen einfachen Service für LAppS geschrieben und ihn als denselben unprätentiösen Benchmark bezeichnet .


Dieser Dienst erstellt zu Beginn 100 Verbindungen zum Echoserver WebSocket (egal welcher), und wenn die Verbindung erfolgreich ist, sendet er eine 1-KB-Nachricht. Wenn eine Nachricht vom Server empfangen wird, wird sie zurückgesendet.


Mein Heimcomputer: Intel® Core (TM) i7-7700-CPU bei 3,60 GHz, Mikrocode 0x5e
Speicher: DIMM DDR4 Synchron ungepuffert (nicht registriert) 2400 MHz (0,4 ns), Kingston KHX2400C15 / 16G


Alle Tests wurden an diesem lokalen Host durchgeführt.


Service-Echo- Konfiguration in LAppS:


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

Für den Parameter instance muss LAppS zwei parallele Echodienste starten.


Konfiguration des Benchmark-Dienstes (Client):


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

Zu Beginn werden 4 Instanzen des Service-Benchmarks erstellt


Ergebnis mit aktiviertem TLS


ServerAnzahl der KundenRPS-ServerRPS pro KundeNutzlast (Bytes)
LAppS 0.7.0-Upstream400257828644,571024
Nginx & Lua-Resty-Websocket 4 Arbeiter4003378884,471024
websocketpp4009789,5224.471024

uWebSockets konnte bisher nicht getestet werden - TLS-Handshake schwört auf SSLv3 (mein Client verwendet TLSv1.2 und ist in dem von mir verwendeten libreSSL-SSLv3 ausgeschnitten).


Ergebnis ohne TLS


ServerAnzahl der KundenRPS-ServerRPS pro KundeNutzlast (Bytes)
LAppS 0.7.0-upstream4004397001099,251024
uWebSockets-Upstream400247549618,871024

Warum in der Überschrift "eine halbe Million" Nachrichten und im Test 257828? Weil es doppelt so viele Nachrichten gibt (wie oben erklärt).


uWebsockets zeigt in diesem Test nicht beneidenswerte Ergebnisse, nur weil es auf dem 1. Kern funktioniert, die Multithread-Version von uWebSockets aus dem Projekt-Repository nicht funktioniert und wenn TLS aktiviert ist, hat es Datenrennen im OpenSSL-Stack.


Wenn Sie sich vorstellen, dass uWebSockets auf 2 Kernen (wie 2 LAppS-Echodiensten) einwandfrei funktioniert, kann es bedingt auf 495098 RPS eingestellt werden (verdoppeln Sie einfach das Ergebnis aus der Tabelle).


Sie müssen jedoch berücksichtigen, dass der Echoserver ( uWebSockets ) nichts mit den empfangenen Daten tut , sondern diese sofort zurücksendet . LAppS übergibt Daten an den Lua-Stack, der dem Service entspricht.


Was ist neu in LAppS?


  • PAM-Authentifizierungsmodul pam_auth
  • Nachrichtenwarteschlangenmodul: mqr - zum Austausch von Nachrichten zwischen Diensten innerhalb desselben LAppS-Servers (für den Austausch auf mehreren Servern müssen Sie etwas verwenden, das bereits vorhanden ist, z. B. RabbitMQ, Moskito usw.)
  • ACL-Netzwerkverbindungen

All dies finden Sie auf der Projekt- Wiki- Seite.


Nun, für einen Snack, für Kenner, was genau macht LAppS während dieser Tests.


Ohne TLS


Versteckter Text
   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 

Wir werden 10 Unterschiede bei der Arbeit mit TLS feststellen


Versteckter Text
  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/de421421/


All Articles