2

We want to know what algorithm the Docker mesh uses to route requests to containers. Here's why:

We deploy our applications to self-hosted docker swarms. We use the docker routing mesh to direct traffic to the individual nodes, like this:

  • internet ->
  • firewall ->
  • load director (nginx) ->
  • nginx "least connection" routing to three swarm managers ->
  • docker mesh ->
  • Any of the six app containers running on three different non-manager docker nodes

Our developers suspect that the docker mesh is routing traffic round robin, which could result in some app containers being overloaded with slow requests while other containers are under-utilized. If the devs are right, we should not use the docker mesh and instead should use the load director to direct traffic to the individual containers using a smarter algorithm than round robin.

On the other hand, if the docker mesh is keeping track of how many requests are in flight to each container and delivering traffic to the container with the fewest requests, then we do not need to do the work of bypassing the docker mesh.

The question

What algorithm does the docker mesh use to direct traffic to available containers? Is it simple round robin?

Our nginx config

Our nginx receives traffic from the internet and proxies it to the docker mesh on any of the three docker manager nodes:

upstream document_service {
  least_conn;
  server dockermgr1.nosuchdomain:8402;
  server dockermgr2.nosuchdomain:8402;
  server dockermgr3.nosuchdomain:8402;
}

server {
...
        proxy_pass http://document_service;

Our docker-compose config

The docker-compose file configures the service to have six replicas on the three docker runner nodes:

version: "3.4"

services:
  documentsservice:
    image: ${IMAGE_LOCATION}documents_service/documentsservice:prod-${COMPOSE_BUILD_TAG:-latest}
    container_name: documentsservice
    ports:
      - "8402:80"
    ...
    deploy:
      replicas: 6
      placement:
        constraints: [node.role != manager]
      resources:
        limits:
          memory: 1024MB
      update_config:
        parallelism: 1
        order: start-first
        failure_action: continue

Versions

  • docker-ce 5:19.03.12~3-0~debian-buster
  • nginx-full 1.14.2-2+deb10u4
  • docker-compose: 1.27.4
Wayne Conrad
  • 635
  • 1
  • 7
  • 20

1 Answers1

0

Mesh routing is most likely round robin only

I took a dive into the docker source. I found references to various routing methods, but the only one that appears to be used is round robin. I also found a question on the docker forum that seems to confirm that mesh routing is round-robin only.

Examining the source


In vendor/github.com/moby/ipvs/constants.go is this interesting list of routing strategies:

const (                                                                                                                                                                                        
        // RoundRobin distributes jobs equally amongst the available                                                                                                                           
        // real servers.                                                                                                                                                                       
        RoundRobin = "rr"                                                                                                                                                                      
                                                                                                                                                                                               
        // LeastConnection assigns more jobs to real servers with                                                                                                                              
        // fewer active jobs.                                                                                                                                                                  
        LeastConnection = "lc"                                                                                                                                                                 
                                                                                                                                                                                               
        // DestinationHashing assigns jobs to servers through looking                                                                                                                          
        // up a statically assigned hash table by their destination IP                                                                                                                         
        // addresses.                                                                                                                                                                          
        DestinationHashing = "dh"                                                                                                                                                              
                                                                                                                                                                                               
        // SourceHashing assigns jobs to servers through looking up                                                                                                                            
        // a statically assigned hash table by their source IP                                                                                                                                 
        // addresses.                                                                                                                                                                          
        SourceHashing = "sh"                                                                                                                                                                   
                                                                                                                                                                                               
        // WeightedRoundRobin assigns jobs to real servers proportionally                                                                                                                      
        // to there real servers' weight. Servers with higher weights                                                                                                                          
        // receive new jobs first and get more jobs than servers                                                                                                                               
        // with lower weights. Servers with equal weights get                                                                                                                                  
        // an equal distribution of new jobs                                                                                                                                                   
        WeightedRoundRobin = "wrr"                                                                                                                                                             
                                                                                                                                                                                               
        // WeightedLeastConnection assigns more jobs to servers                                                                                                                                
        // with fewer jobs and relative to the real servers' weight                                                                                                                            
        WeightedLeastConnection = "wlc"                                                                                                                                                        
)  

However the only one of these constants that is every used is RoundRobin:

wayne@treebeard:~/temp/docker-src/moby$ ack 'ipvs\.(RoundRobin|LeastConnection|DestinationHashing|SourceHashing|WeightedRoundRobin|WeightedLeastConnection)'
libnetwork/service_linux.go
117:            SchedName:     ipvs.RoundRobin,
225:            s.SchedName = ipvs.RoundRobin

Although this was a very cursory look at the source, I found no obvious means of configuring the routing mode to be anything other than RoundRobin.

A related question on the docker forums

A question on the docker forum seems to confirm that the only routing method available to the mesh is round robin:

https://forums.docker.com/t/configure-swarm-mode-routing-mesh-load-balancing-method/75413

I’ve read that the swarm mode routing mesh load balancer uses round-robin (https://success.docker.com/article/ucp-service-discovery#externalloadbalancing(swarmmoderoutingmesh) 15).

Is there a possibility to configure the load balancing method (e.g. (weighted) least connection, source/destination hashing…) of the swarm mode routing mesh?

The answer was:

The swarm mode routing mesh aka ingress acts on layer4 and does not know about those configuration details you ask for. The documentation can be found here: https://docs.docker.com/engine/swarm/ingress/ 45. The link you pasted is aimed towards “why using the interlock proxy as advantages”.

If you have an enterprise license: you are entitled to use the interlock proxy, which is part of UCP. It is a layer7 reverse proxy/loadbalancer. Back in the days when I tried early versions of interlock it had some limitiations. From what i read in the change log the current versions seem to be close what traefik is capable to do.

If you are running on Docker-CE, you might want to take a look at traefik.

Wayne Conrad
  • 635
  • 1
  • 7
  • 20
  • This is more of a guess than anything, so not giving it the checkmark in the hopes that someone writes a more deserving answer. – Wayne Conrad Aug 25 '21 at 16:51