Для тех кто не в курсе: LAppS — Lua Application Server, это почти как nginx или apache, но только для WebSocket протокола, вместо HTTP.
HTTP в нём поддерживается только на уровне Upgrade запроса.
LAppS изначально затачивался на высокую нагрузку и вертикальную масштабируемость, и сегодня достиг пика своих возможностей на моём железе (ну почти, можно и дальше оптимизировать, но это будет долгий и упорный труд).
Самое главное, LAppS по производительности WebSocket стека, превзошёл библиотеку uWebSockets, которая позиционируется как самая быстрая WebSocket имплементация.
Заинтересованных прошу под кат.
С последней моей статьи про LAppS прошло уже пару месяцев, заинтересованности та статья не вызвала. Надеюсь эта статья покажется хабровчанам интересней. LAppS за это время проделал довольно сложный путь к версии 0.7.0, оброс функционалом и вырос в плане производительности (что и было обещано ранее).
Одна из появившихся фич: подгружаемый модуль с реализацией клиентской части протокола WebSocket, — cws.
Благодаря этому модулю, я наконец-то смог выжать все возмозжное из моего домашнего компа, и нагрузить LAppS по настоящему.
Ранее тестирование производилось с помощью echo клиента библиотеки websocketpp (подробнее можно посмотреть на github странице проекта), которая мало того, что медленная, так ещё и трудно параллелизуемая. Тесты выполнялись просто: стартовалась пачка клиентов, результаты от каждого клиента собирались с помощью awk и несложная арифметика выдавала результаты производительности. Результаты были такими:
| Сервер | Кол-во клиентов | RPS сервера | RPS на клиента | payload (bytes) |
|---|---|---|---|---|
| LAppS 0.7.0 | 240 | 84997 | 354.154 | 128 |
| uWebSockets (latest) | 240 | 74172.7 | 309.053 | 128 |
| LAppS 0.7.0 | 240 | 83627.4 | 348.447 | 512 |
| uWebSockets (latest) | 240 | 71024.4 | 295.935 | 512 |
| LAppS 0.7.0 | 240 | 79270.1 | 330.292 | 1024 |
| uWebSockets (latest) | 240 | 66499.8 | 277.083 | 1024 |
| LAppS 0.7.0 | 240 | 51621 | 215.087 | 8192 |
| uWebSockets (latest) | 240 | 45341.6 | 188.924 | 8192 |
В данном тесте как и в последующих кол-во пакетов на смом деле вдвое выше, т.к. замер производится на on_message и в методе on_message клиента производится отправка нового пакета того-же размера. Т.е. запрос клиента и ответ сервера имеют одинаковый размер, и если считать объём трафика обработанного сервером, то нужно удваивать результат RPS умножать на payload и пренебрегая заголовками можно получить примерный объём трафика в байтах.
Очевидно, что при одновременной работе 240 процессов клиентов, самому LAppS-у (как и uWebSockets) остаётся не так уж и много ресурсов ЦПУ.
Я просмотрел несколько клиентских реализаций для WebSocket под Lua, и к сожалению не нашёл простого и достаточно производительного модуля, с помощью которого, я-бы мог как следует нагрузить LAppS. Поэтому, как обычно сделал свой велосипед.
Модуль имеет довольно простой интерфейс и иммитирует поведение браузерного WebSocket API
Простой пример того как работать с этим модулем (сервис для получения сделок с BitMEX):
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;
Сразу предупреждаю, модуль появился только сегодня и он слабо оттестирован.
Для тестирования я написал простой сервис для LAppS и назвал его так-же незатейливо benchmark.
Этот сервис на старте создаёт 100 соединений к эхо серверу WebSocket (не важно какому), и при удачном соединении отправляет 1кб сообщение. При приёме сообщения от сервера, он отправляет его назад.
Мой домашний комп: Intel® Core(TM) i7-7700 CPU @ 3.60GHz, microcode 0x5e
Память: DIMM DDR4 Synchronous Unbuffered (Unregistered) 2400 MHz (0,4 ns), Kingston KHX2400C15/16G
Всё тестирование проводилось на этом локалхосте.
Конфигурация эхо сервиса в LAppS:
"echo": { "auto_start": true, "instances": 2, "internal": false, "max_inbound_message_size": 16777216, "preload": null, "protocol": "raw", "request_target": "/echo" }
Параметр instances требует от LAppS старта двух параллельных эхо сервисов.
Конигурация бенчмарк-сервиса (клиента):
"benchmark" : { "auto_start" : true, "instances": 4, "internal": true, "preload" : [ "cws", "time" ] }
T.e. при старте создаётся 4 экземпляра сервиса-бенчмарка
Результат с включенным TLS
| Сервер | Кол-во клиентов | RPS сервера | RPS на клиента | payload (bytes) |
|---|---|---|---|---|
| LAppS 0.7.0-Upstream | 400 | 257828 | 644.57 | 1024 |
| nginx &lua-resty-websocket 4 workers | 400 | 33788 | 84.47 | 1024 |
| websocketpp | 400 | 9789.52 | 24.47 | 1024 |
uWebSockets оттестировать пока не удалось, — TLS handshake ругается на SSLv3 (мой клиент использует TLSv1.2 и в используемом мной libreSSL SSLv3 вырезан).
Результат без TLS
| Сервер | Кол-во клиентов | RPS сервера | RPS на клиента | payload (bytes) |
|---|---|---|---|---|
| LAppS 0.7.0-upstream | 400 | 439700 | 1099.25 | 1024 |
| uWebSockets-upstream | 400 | 247549 | 618.87 | 1024 |
Почему в заголовке «полмилиона» сообщений, а в тесте 257828? Потому-что сообщений вдвое больше (как и было разъяснено выше).
uWebsockets, показывает незавидные результаты в этом тесте, только потому, что он работает на 1-м ядре, многопоточная версия uWebSockets из репозитория проекта, на самом деле не работает и при включении TLS имеет data-race в OpenSSL стэке.
Если представить, что uWebSockets прекрасно работает на 2-х ядрах (как 2 эхо-сервиса LAppS), то ему условно можно будет зачесть 495098 RPS (просто удвоив результат из таблицы).
Но нужно учитывать, что эхо сервер (uWebSockets)(https://github.com/ITpC/LAppS/blob/master/benchmark/uWS/uWS.cpp) ничего с полученными данными не делает, а сразу отправляет назад. LAppS-же передаёт данные в Lua стек, соответствующему сервису.
Что ещё нового появилось в LAppS
- Модуль аутентификации ч-з PAM: pam_auth
- Модуль очередей сообщений: mqr — для обмена сообщениями между сервисами в рамках одного сервера LAppS (для мултисерверного обмена нужно использовать, что-то уже существующее, например: RabbitMQ, mosquitto, etc)
- ACL сетевых соединений
Со всем этим можно ознакомиться на wiki странице проекта.
Ну и на закуску, для ценителей, чем же собственно LAppS занимается во время этого тестирования.
Без TLS
Очевидный лидер 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
С найдём 10 отличий при работе с TLS
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
ссылка на оригинал статьи https://habr.com/post/421421/
Добавить комментарий