Падение производительности на порте с Beast.1.0.0-b66 до Boost.1.67.0.Beast

Я наблюдал резкое падение производительности (и резкое увеличение потребления процессора) при переходе с Beast.1.0.0-b66 (с использованием Boost.1.64.0) на Boost.1.67.0.Beast (то есть с Beast, интегрированным в Boost), Без сомнения, я сделал что-то не так, но я не могу себе представить, что.

Что было:

typedef beast::http::request<beast::http::string_body> BeastHttpRequest;

сейчас:

namespace http = boost::beast::http;    
typedef http::request<http::string_body> BeastHttpRequest;

и что было:

beast::http::prepare(req);
beast::http::write(stream, req);

сейчас:

req.prepare_payload();
http::write(stream, req);

Конечно, мне также пришлось внести многочисленные изменения в API. Например:

req.fields.replace(hdrName, hdrValue);

сейчас:

req.set(hdrName, hdrValue);

Приложение работает корректно - включая согласование SSL и согласование прокси-сервера - но я должен исправить скачок в использовании процессора и соразмерное падение производительности. Интересно, кто-нибудь знает что-то очевидное, что я упустил из виду?

РЕДАКТИРОВАТЬ: я должен был упомянуть, что я использую flat_buffer для потока SSL.

У меня была возможность профилировать данные производительности "до порта" и "после порта". Вот цепочка вызовов "до порта" (т.е. с хорошей производительностью):

- 34.61% HttpRequest::send
   - 32.02% beast::http::write<boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >&>, true, beast::http::string_body,
      - 31.90% beast::http::write<boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >&>, true, beast::http::string_bo
         - 20.77% beast::http::detail::write_preparation<true, beast::http::string_body, beast::http::basic_fields<std::allocator<char> > >::init
            - 18.25% beast::http::detail::write_fields<beast::basic_streambuf<std::allocator<char> >, beast::http::basic_fields<std::allocator<char> > >
               - 10.38% beast::write<beast::basic_streambuf<std::allocator<char> >, boost::basic_string_ref<char, std::char_traits<char> > >
                  - 10.20% beast::detail::write_dynabuf<beast::basic_streambuf<std::allocator<char> >, boost::basic_string_ref<char, std::char_traits<char> > >
                     + 3.66% beast::basic_streambuf<std::allocator<char> >::prepare
                     + 2.90% beast::basic_streambuf<std::allocator<char> >::commit
                     + 1.81% boost::lexical_cast<std::string, boost::basic_string_ref<char, std::char_traits<char> > >
                     + 1.47% boost::asio::buffer_copy<beast::basic_streambuf<std::allocator<char> >::mutable_buffers_type>
               - 7.51% beast::write<beast::basic_streambuf<std::allocator<char> >, char [3]>
                  - 7.47% beast::detail::write_dynabuf<beast::basic_streambuf<std::allocator<char> >, 3ul>
                     + 3.14% beast::basic_streambuf<std::allocator<char> >::prepare
                     + 2.84% beast::basic_streambuf<std::allocator<char> >::commit
                     + 1.32% boost::asio::buffer_copy<beast::basic_streambuf<std::allocator<char> >::mutable_buffers_type>
            + 2.04% beast::http::detail::write_start_line<beast::basic_streambuf<std::allocator<char> >, beast::http::basic_fields<std::allocator<char> > >
         - 9.60% beast::http::string_body::writer::write<beast::http::detail::writef0_lambda<boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_serv
            - 9.57% beast::http::detail::writef0_lambda<boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >&>, beast:
               - 9.54% boost::asio::write<boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >&>, beast::detail::buffe
                  - 9.48% boost::asio::write<boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >&>, beast::detail::bu
                     - 8.55% boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >&>::write_some<boost::asio::detail::c
                        - 7.56% boost::asio::ssl::detail::io<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >, boost::asio::ssl::detail::wr
                           - 6.98% boost::asio::write<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >, boost::asio::mutable_buffers_1>
                              - 6.93% boost::asio::write<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >, boost::asio::mutable_buffers_1,
                                 - 6.69% boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >::write_some<boost::asio::detail::consuming_buffer
                                    - 6.69% boost::asio::stream_socket_service<boost::asio::ip::tcp>::send<boost::asio::detail::consuming_buffers<boost::asio::const_buffer, boost::asio::mutable_buffers_1>
                                       - 6.67% boost::asio::detail::reactive_socket_service_base::send<boost::asio::detail::consuming_buffers<boost::asio::const_buffer, boost::asio::mutable_buffers_1> >
                                          - 6.51% boost::asio::detail::socket_ops::sync_send
                                             - 6.32% 0xec6d
                                                - 6.08% system_call_fastpath
                                                   - 6.07% sys_sendmsg
                                                      - 6.06% __sys_sendmsg
                                                         - 5.94% ___sys_sendmsg
                                                            + 5.84% sock_send

а вот цепочка вызовов "после порта" (т.е. с низкой производительностью):

- 53.77% HttpRequest::send
   - 53.32% boost::beast::http::write<boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp>&>, true, boost::beast::http::basic_string_body<char, std::char_traits<char>, std::allo
      - 53.30% boost::beast::http::write<boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp>&>, true, boost::beast::http::basic_string_body<char, std::char_traits<char>, std::a
         - 53.14% boost::beast::http::write<boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp>&>, true, boost::beast::http::basic_string_body<char, std::char_traits<char>, std
            - 53.03% boost::beast::http::write_some<boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp>&>, true, boost::beast::http::basic_string_body<char, std::char_traits<ch
               - 52.95% boost::beast::http::detail::write_some_impl<boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp>&>, true, boost::beast::http::basic_string_body<char, std
                  - 36.58% boost::beast::http::serializer<true, boost::beast::http::basic_string_body<char, std::char_traits<char>, std::allocator<char> >, boost::beast::http::basic_fields<std::allocator<
                     - 35.28% boost::beast::http::serializer<true, boost::beast::http::basic_string_body<char, std::char_traits<char>, std::allocator<char> >, boost::beast::http::basic_fields<std::allocat
                        - 25.93% boost::beast::http::detail::write_some_lambda<boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp>&> >::operator()<boost::beast::detail::buffers
                           - 25.82% boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp>&>::write_some<boost::beast::detail::buffers_ref<boost::beast::buffers_prefix_view<boost:
                              - 25.69% boost::asio::ssl::detail::io<boost::asio::basic_stream_socket<boost::asio::ip::tcp>, boost::asio::ssl::detail::write_op<boost::beast::detail::buffers_ref<boost::beas
                                 - 22.20% boost::asio::write<boost::asio::basic_stream_socket<boost::asio::ip::tcp>, boost::asio::mutable_buffer>
                                    - 22.13% boost::asio::write<boost::asio::basic_stream_socket<boost::asio::ip::tcp>, boost::asio::mutable_buffer, boost::asio::detail::transfer_all_t>
                                       - 21.96% boost::asio::detail::write_buffer_sequence<boost::asio::basic_stream_socket<boost::asio::ip::tcp>, boost::asio::mutable_buffer, boost::asio::mutable_buffer
                                          - 21.47% boost::asio::basic_stream_socket<boost::asio::ip::tcp>::write_some<boost::asio::const_buffers_1>
                                             - 21.34% boost::asio::detail::reactive_socket_service_base::send<boost::asio::const_buffers_1>
                                                - 21.17% boost::asio::detail::socket_ops::sync_send
                                                   - 20.45% 0xec6d
                                                      - 19.63% system_call_fastpath
                                                         - 19.57% sys_sendmsg
                                                            - 19.52% __sys_sendmsg
                                                               - 19.16% ___sys_sendmsg
                                                                  + 18.90% sock_sendmsg

1 ответ

Решение

Это должно быть быстрее, а не медленнее, так как алгоритмы HTTP были оптимизированы. Я думаю, что я знаю, что происходит, хотя. Было бы полезно сравнить производительность двух версий при использовании обычных сокетов, а не SSL. boost::asio::ssl::stream имеет недостаток, заключающийся в том, что при записи последовательностей буферов длиной более единицы он записывает данные в сокет для каждого буфера в последовательности вместо объединения этих зашифрованных буферов в одну запись. Это может оказать значительное влияние на производительность.

Это действительно необходимо исправить в Boost.Asio, но обходной путь заключается в том, что вы можете написать свой собственный потоковый упаковщик, алгоритм записи которого, когда он представлен с последовательностями буферов, длина которых больше единицы, создает новую последовательность длиной один, используя memcpy и динамическое распределение. Я также открыл бы проблему здесь: https://github.com/boostorg/asio/issues

Почему разница в двух версиях Beast? Старая версия Beast выделяла память во время сериализации для хранения линейной версии сообщения. Текущая версия использует алгоритм, который вообще не требует выделения памяти. В обычном случае это быстрее, но, как вы обнаружили при работе с ssl::stream Типы это может быть медленнее.

См. https://github.com/boostorg/beast/issues/1108

Другие вопросы по тегам