Hi,

> On 22. Jan 2024, at 20.00, Achim Stahlberger <achim.stahlber...@tallence.com> 
> wrote:
> 
> Hello,
> 
> we see this problem when doveadm-server is under load.
> 
> We enabled doveadm http api with this config:
> 
> service doveadm {
>  inet_listener {
>    port = 50000
>  }
>  inet_listener http {
>    port = 50001
>    ssl = no
>  }
> }
> 
> When doveadm server receives at lot of connects on port 50000 the http 
> service on
> port 50001 is not responding until load on port 50000 drops to zero.
> It seems like doveadm-server is prefering port 50000 over 50001.
> 
> Looking into Recv-Q when http hangs
> 
> Netid State      Recv-Q  Send-Q                                   Local 
> Address:Port                                       Peer Address:Port
> tcp   LISTEN     129     128                                            
> 0.0.0.0:50000                                           0.0.0.0:*
> tcp   LISTEN     1       128                                            
> 0.0.0.0:50001                                           0.0.0.0:*

By "drops to zero" do you mean the connection queue has to drain until Recv-Q 
is below 129? Or that even then it needs to go down further?

Also, doveadm process isn't supposed to be handling more than one client at a 
time. So if it has a lot of pressure, why does it matter which port it's 
answering to since it can't handle all connections anyway?

> I used this script to produce load on port 50000
> 
> #!/bin/bash
> for i in {1..1000}
> do
>  echo "124" | netcat localhost 50000 &
> done
> wait
> 
> When this script is started it takes several seconds until a connect on port 
> 50001 succeeds.
..
> I think the problem is in src/lib/ioloop-epoll.c function 
> io_loop_handler_run_internal.
> This might fix the problem (look for new variable rr):

With the fix wouldn't it still take several seconds to connect to either 50000 
or 50001, since now both the queues are full? Or why is it different?

Below is a bit simpler patch, which I think does the same as yours:

diff --git a/src/lib/ioloop-epoll.c b/src/lib/ioloop-epoll.c
index ad4100865f..4379680a6e 100644
--- a/src/lib/ioloop-epoll.c
+++ b/src/lib/ioloop-epoll.c
@@ -170,7 +170,7 @@ void io_loop_handler_run_internal(struct ioloop *ioloop)
        struct io_file *io;
        struct timeval tv;
        unsigned int events_count;
-       int msecs, ret, i, j;
+       int msecs, ret, i, j, i_start;
        bool call;

        i_assert(ctx != NULL);
@@ -197,10 +197,11 @@ void io_loop_handler_run_internal(struct ioloop *ioloop)
        if (!ioloop->running)
                return;

+       i_start = ret <= 1 ? 0 : i_rand_limit(ret);
        for (i = 0; i < ret; i++) {
                /* io_loop_handle_add() may cause events array reallocation,
                   so we have use array_idx() */
-               event = array_idx(&ctx->events, i);
+               event = array_idx(&ctx->events, (i_start + i) % ret);
                list = event->data.ptr;

                for (j = 0; j < IOLOOP_IOLIST_IOS_PER_FD; j++) {

Although it's using quite a lot of randomness (= /dev/urandom reads), which 
isn't so good. I think it would be just as good to do round-robin:

diff --git a/src/lib/ioloop-epoll.c b/src/lib/ioloop-epoll.c
index ad4100865f..80a5e67cee 100644
--- a/src/lib/ioloop-epoll.c
+++ b/src/lib/ioloop-epoll.c
@@ -197,10 +197,12 @@ void io_loop_handler_run_internal(struct ioloop *ioloop)
        if (!ioloop->running)
                return;

+       static int i_start = 0;
+       i_start++;
        for (i = 0; i < ret; i++) {
                /* io_loop_handle_add() may cause events array reallocation,
                   so we have use array_idx() */
-               event = array_idx(&ctx->events, i);
+               event = array_idx(&ctx->events, (i_start + i) % ret);
                list = event->data.ptr;

                for (j = 0; j < IOLOOP_IOLIST_IOS_PER_FD; j++) {

But even so, I'd like to understand better what exactly this is helping with 
before merging. Looking at libevent and nginx, I don't see them doing anything 
like this either.
_______________________________________________
dovecot mailing list -- dovecot@dovecot.org
To unsubscribe send an email to dovecot-le...@dovecot.org

Reply via email to