Добрый день, On Thu, Jan 04, 2024 at 07:04:31PM +0300, izor...@gmail.com wrote: > Добрый вечер, Илья. > > Замерил тесты на физическом сервере, пока без без поддержки kTLS. > Оказывается в тестах на виртуальной машине я неправильно интерпретировал > интерпретировал скорости, > которые выводила утилита curl. Вместо МБит/сек там идёт МБайт/сек. > > Результаты тестов при скачивании файла с самого сервера: > - HTTP/1.1 - ~3 504,14 МБит/сек (CPU load 100%) > - HTTP/2 - ~3 568,57 МБит/сек (CPU load 100%) > - HTTP/3 - ~2 872,09 МБит/сек (CPU load 58-62%) > > Результаты тестов при скачивании файла по локальной сети: > - HTTP/1.1 - ~2 325,03 МБит/сек (CPU load 45-50%) > - HTTP/2 - ~2 333,56 МБит/сек (CPU load 45-50%) > - HTTP/3 - ~1 350,26 МБит/сек (CPU load 50-55%) > > Анализ профиля для протокола HTTP/3 при скачивании файла с самого сервера: > 482 27.1% 27.1% 482 27.1% __sendmsg
У вас quic_gso включен? Если нет, попробуйте включить: quic_gso on; Также попробуйте приаттаченный патч, добавляющий поддержку sendmmsg() (quic_gso при этом оставьте включенным). nginx будет надо переконфигурить перед сборкой. Интересно посмотреть, как изменятся цифры. > 473 26.6% 53.7% 473 26.6% __libc_pread64 > 367 20.6% 74.4% 367 20.6% _aesni_ctr32_ghash_6x > 151 8.5% 82.8% 151 8.5% __memmove_avx_unaligned_erms > 58 3.3% 86.1% 58 3.3% epoll_wait > 31 1.7% 87.9% 31 1.7% __recvmsg > 10 0.6% 88.4% 93 5.2% ngx_quic_write_buffer > 8 0.4% 88.9% 100 5.6% ngx_quic_recvmsg > 7 0.4% 89.3% 7 0.4% __strcmp_avx2 > 7 0.4% 89.7% 7 0.4% ngx_quic_read_buffer > 6 0.3% 90.0% 115 6.5% ngx_http_charset_body_filter > 6 0.3% 90.3% 108 6.1% ngx_http_write_filter > 6 0.3% 90.7% 82 4.6% ngx_quic_create_frame > 6 0.3% 91.0% 8 0.4% ossl_gcm_set_ctx_params > 5 0.3% 91.3% 19 1.1% EVP_CIPHER_CTX_ctrl > 5 0.3% 91.6% 5 0.3% aesni_ctr32_encrypt_blocks > 5 0.3% 91.8% 5 0.3% ngx_quic_alloc_buf > 5 0.3% 92.1% 15 0.8% ngx_quic_handle_ack_frame_range > 5 0.3% 92.4% 59 3.3% ngx_quic_handle_datagram > 4 0.2% 92.6% 10 0.6% CRYPTO_gcm128_encrypt_ctr32 [..] -- Roman Arutyunyan
# HG changeset patch # User Roman Arutyunyan <a...@nginx.com> # Date 1692075843 -14400 # Tue Aug 15 09:04:03 2023 +0400 # Node ID 0f7b91d0fea6d132f877ff25992a457a2fe437e6 # Parent 6c8595b77e667bd58fd28186939ed820f2e55e0e QUIC: use sendmmsg() with UDP segmentation instead of sendmsg(). The syscall allows to send more datagrams with a single call. Using sendmmsg() will not introduce compatibility issues since this syscall was added in Linux kernel 3.0, while UDP segmentation was added in 4.18. diff --git a/auto/os/linux b/auto/os/linux --- a/auto/os/linux +++ b/auto/os/linux @@ -291,4 +291,16 @@ ngx_feature_test="socklen_t optlen = siz . auto/feature +ngx_feature="sendmmsg()" +ngx_feature_name="NGX_HAVE_SENDMMSG" +ngx_feature_run=no +ngx_feature_incs="#include <sys/socket.h> + #include <sys/uio.h>" +ngx_feature_path= +ngx_feature_libs= +ngx_feature_test="struct mmsghdr msg[UIO_MAXIOV]; + sendmmsg(0, msg, UIO_MAXIOV, 0);" +. auto/feature + + CC_AUX_FLAGS="$cc_aux_flags -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64" diff --git a/src/event/quic/ngx_event_quic_output.c b/src/event/quic/ngx_event_quic_output.c --- a/src/event/quic/ngx_event_quic_output.c +++ b/src/event/quic/ngx_event_quic_output.c @@ -48,11 +48,9 @@ static ngx_int_t ngx_quic_create_datagra static void ngx_quic_commit_send(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx); static void ngx_quic_revert_send(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx, uint64_t pnum); -#if ((NGX_HAVE_UDP_SEGMENT) && (NGX_HAVE_MSGHDR_MSG_CONTROL)) +#if (NGX_HAVE_UDP_SEGMENT && NGX_HAVE_MSGHDR_MSG_CONTROL && NGX_HAVE_SENDMMSG) static ngx_uint_t ngx_quic_allow_segmentation(ngx_connection_t *c); static ngx_int_t ngx_quic_create_segments(ngx_connection_t *c); -static ssize_t ngx_quic_send_segments(ngx_connection_t *c, u_char *buf, - size_t len, struct sockaddr *sockaddr, socklen_t socklen, size_t segment); #endif static ssize_t ngx_quic_output_packet(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx, u_char *data, size_t max, size_t min); @@ -80,7 +78,7 @@ ngx_quic_output(ngx_connection_t *c) in_flight = cg->in_flight; -#if ((NGX_HAVE_UDP_SEGMENT) && (NGX_HAVE_MSGHDR_MSG_CONTROL)) +#if (NGX_HAVE_UDP_SEGMENT && NGX_HAVE_MSGHDR_MSG_CONTROL && NGX_HAVE_SENDMMSG) if (ngx_quic_allow_segmentation(c)) { rc = ngx_quic_create_segments(c); } else @@ -250,7 +248,7 @@ ngx_quic_revert_send(ngx_connection_t *c } -#if ((NGX_HAVE_UDP_SEGMENT) && (NGX_HAVE_MSGHDR_MSG_CONTROL)) +#if (NGX_HAVE_UDP_SEGMENT && NGX_HAVE_MSGHDR_MSG_CONTROL && NGX_HAVE_SENDMMSG) static ngx_uint_t ngx_quic_allow_segmentation(ngx_connection_t *c) @@ -308,16 +306,28 @@ ngx_quic_allow_segmentation(ngx_connecti static ngx_int_t ngx_quic_create_segments(ngx_connection_t *c) { - size_t len, segsize; + size_t len, segsize, clen; ssize_t n; - u_char *p, *end; + u_char *p, *start, *end; + uint16_t *valp; uint64_t preserved_pnum; - ngx_uint_t nseg; + ngx_err_t err; + ngx_uint_t nseg, nmsg; + struct msghdr msg; + struct cmsghdr *cmsg; ngx_quic_path_t *path; ngx_quic_send_ctx_t *ctx; ngx_quic_congestion_t *cg; ngx_quic_connection_t *qc; - static u_char dst[NGX_QUIC_MAX_UDP_SEGMENT_BUF]; +#if (NGX_HAVE_ADDRINFO_CMSG) + char msg_control[CMSG_SPACE(sizeof(uint16_t)) + + CMSG_SPACE(sizeof(ngx_addrinfo_t))]; +#else + char msg_control[CMSG_SPACE(sizeof(uint16_t))]; +#endif + struct iovec iovs[UIO_MAXIOV]; + static u_char dst[UIO_MAXIOV * NGX_QUIC_MAX_UDP_SEGMENT_BUF]; + struct mmsghdr msgs[UIO_MAXIOV]; qc = ngx_quic_get_connection(c); cg = &qc->congestion; @@ -330,94 +340,12 @@ ngx_quic_create_segments(ngx_connection_ } segsize = ngx_min(path->mtu, NGX_QUIC_MAX_UDP_SEGMENT_BUF); - p = dst; - end = dst + sizeof(dst); - - nseg = 0; - - preserved_pnum = ctx->pnum; - - for ( ;; ) { - - len = ngx_min(segsize, (size_t) (end - p)); - - if (len && cg->in_flight + (p - dst) < cg->window) { - - n = ngx_quic_output_packet(c, ctx, p, len, len); - if (n == NGX_ERROR) { - return NGX_ERROR; - } - - if (n) { - p += n; - nseg++; - } - - } else { - n = 0; - } - - if (p == dst) { - break; - } - - if (n == 0 || nseg == NGX_QUIC_MAX_SEGMENTS) { - n = ngx_quic_send_segments(c, dst, p - dst, path->sockaddr, - path->socklen, segsize); - if (n == NGX_ERROR) { - return NGX_ERROR; - } - - if (n == NGX_AGAIN) { - ngx_quic_revert_send(c, ctx, preserved_pnum); - - ngx_add_timer(&qc->push, NGX_QUIC_SOCKET_RETRY_DELAY); - break; - } - - ngx_quic_commit_send(c, ctx); - - path->sent += n; - - p = dst; - nseg = 0; - preserved_pnum = ctx->pnum; - } - } - - return NGX_OK; -} - - -static ssize_t -ngx_quic_send_segments(ngx_connection_t *c, u_char *buf, size_t len, - struct sockaddr *sockaddr, socklen_t socklen, size_t segment) -{ - size_t clen; - ssize_t n; - uint16_t *valp; - struct iovec iov; - struct msghdr msg; - struct cmsghdr *cmsg; - -#if (NGX_HAVE_ADDRINFO_CMSG) - char msg_control[CMSG_SPACE(sizeof(uint16_t)) - + CMSG_SPACE(sizeof(ngx_addrinfo_t))]; -#else - char msg_control[CMSG_SPACE(sizeof(uint16_t))]; -#endif ngx_memzero(&msg, sizeof(struct msghdr)); ngx_memzero(msg_control, sizeof(msg_control)); - iov.iov_len = len; - iov.iov_base = buf; - - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - - msg.msg_name = sockaddr; - msg.msg_namelen = socklen; + msg.msg_name = path->sockaddr; + msg.msg_namelen = path->socklen; msg.msg_control = msg_control; msg.msg_controllen = sizeof(msg_control); @@ -431,7 +359,7 @@ ngx_quic_send_segments(ngx_connection_t clen = CMSG_SPACE(sizeof(uint16_t)); valp = (void *) CMSG_DATA(cmsg); - *valp = segment; + *valp = segsize; #if (NGX_HAVE_ADDRINFO_CMSG) if (c->listening && c->listening->wildcard && c->local_sockaddr) { @@ -442,14 +370,100 @@ ngx_quic_send_segments(ngx_connection_t msg.msg_controllen = clen; - n = ngx_sendmsg(c, &msg, 0); - if (n < 0) { - return n; + for ( ;; ) { + + preserved_pnum = ctx->pnum; + + p = dst; + + for (nmsg = 0; nmsg < UIO_MAXIOV; nmsg++) { + + start = p; + end = p + NGX_QUIC_MAX_UDP_SEGMENT_BUF; + + for (nseg = 0; nseg < NGX_QUIC_MAX_SEGMENTS; nseg++) { + + if (cg->in_flight + (p - dst) >= cg->window) { + break; + } + + len = ngx_min(segsize, (size_t) (end - p)); + if (len == 0) { + break; + } + + n = ngx_quic_output_packet(c, ctx, p, len, len); + + if (n == NGX_ERROR) { + return NGX_ERROR; + } + + if (n == 0) { + break; + } + + p += n; + } + + if (nseg == 0) { + break; + } + + iovs[nmsg].iov_base = start; + iovs[nmsg].iov_len = p - start; + + msgs[nmsg].msg_hdr = msg; + msgs[nmsg].msg_hdr.msg_iov = &iovs[nmsg]; + msgs[nmsg].msg_hdr.msg_iovlen = 1; + msgs[nmsg].msg_len = 0; + } + + if (nmsg == 0) { + break; + } + + eintr: + + n = sendmmsg(c->fd, msgs, nmsg, 0); + + if (n == -1) { + err = ngx_errno; + + switch (err) { + case NGX_EAGAIN: + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, + "sendmmsg() not ready"); + + ngx_quic_revert_send(c, ctx, preserved_pnum); + + ngx_add_timer(&qc->push, NGX_QUIC_SOCKET_RETRY_DELAY); + return NGX_OK; + + case NGX_EINTR: + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, + "sendmmsg() was interrupted"); + goto eintr; + + default: + c->write->error = 1; + ngx_connection_error(c, err, "sendmsg() failed"); + return NGX_ERROR; + } + } + + len = p - dst; + + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, + "sendmmsg: %z of %ui msg of size %uz", n, nmsg, len); + + c->sent += len; + + ngx_quic_commit_send(c, ctx); + + path->sent += len; } - c->sent += n; - - return n; + return NGX_OK; } #endif
_______________________________________________ nginx-ru mailing list nginx-ru@nginx.org https://mailman.nginx.org/mailman/listinfo/nginx-ru