【问题标题】:Docker swarm network latency with mesh and DNSRR使用网格和 DNSRR 的 Docker 群网络延迟
【发布时间】:2020-05-17 02:57:10
【问题描述】:

我有一个 3 节点的 docker swarm。

部署的一个堆栈是具有 3 个副本的数据库集群。 (MariaDB Galera)

另一个部署的堆栈是具有 2 个副本的 Web 应用程序。

Web 应用程序如下所示:

version: '3'

networks:
  web:
    external: true
  galera_network:
    external: true

services:
  application:
    image: webapp:latest
    networks:
      - galera_network
      - web
    environment:
      DB_HOST: galera_node
    deploy:
      replicas: 2

FWIW,web 网络是 traefik 所连接的。

这里的问题是galera_node(用于 webapp 的数据库主机)解析为最终利用 swarm 的网状路由(据我所知)的 VIP,并且当网状路由结束时会增加额外的延迟WAN 而不是解析到部署在同一物理主机上的galera_node 容器。

我发现的另一个选项是使用tasks.galera_node,但这似乎将 DNSRR 用于 3 个 galera 集群容器。所以在 33% 的时间里,一切都很好而且很快……但在其余时间里,我增加了不必要的延迟。

这两种行为看起来被记录为我们对不同endpoint_mode 选项的期望。参考:Docker endpoint_mode

为了说明延迟,请注意从 webapp 容器执行 ping 操作时: 注意每次 ping 解析的 IP 地址以及响应时间。

### hitting VIP that "masks" the fact that there is extra latency 
### behind it depending on where the mesh routing sends the traffic.

root@294114cb14e6:/var/www/html# ping galera_node
PING galera_node (10.0.4.16): 56 data bytes
64 bytes from 10.0.4.16: icmp_seq=0 ttl=64 time=0.520 ms
64 bytes from 10.0.4.16: icmp_seq=1 ttl=64 time=0.201 ms
64 bytes from 10.0.4.16: icmp_seq=2 ttl=64 time=0.153 ms
--- galera_node ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max/stddev = 0.153/0.291/0.520/0.163 ms

### hitting DNSRR that resolves to worst latency server

root@294114cb14e6:/var/www/html# ping tasks.galera_node
PING tasks.galera_node (10.0.4.241): 56 data bytes
64 bytes from 10.0.4.241: icmp_seq=0 ttl=64 time=60.736 ms
64 bytes from 10.0.4.241: icmp_seq=1 ttl=64 time=60.573 ms
--- tasks.galera_node ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max/stddev = 60.573/60.654/60.736/0.082 ms

### hitting DNSRR that resolves to local galera_node container

root@294114cb14e6:/var/www/html# ping tasks.galera_node
PING tasks.galera_node (10.0.4.242): 56 data bytes
64 bytes from 10.0.4.242: icmp_seq=0 ttl=64 time=0.133 ms
64 bytes from 10.0.4.242: icmp_seq=1 ttl=64 time=0.117 ms
--- tasks.galera_node ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max/stddev = 0.117/0.125/0.133/0.000 ms

### hitting DNSRR that resolves to other "still too much" latency server

root@294114cb14e6:/var/www/html# ping tasks.galera_node
PING tasks.galera_node (10.0.4.152): 56 data bytes
64 bytes from 10.0.4.152: icmp_seq=0 ttl=64 time=28.218 ms
64 bytes from 10.0.4.152: icmp_seq=1 ttl=64 time=40.912 ms
64 bytes from 10.0.4.152: icmp_seq=2 ttl=64 time=26.293 ms
--- tasks.galera_node ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max/stddev = 26.293/31.808/40.912/6.486 ms

我能够获得绕过延迟的良好性能的唯一方法是硬编码本地容器的 IP 地址,但这显然不是一个长期的解决方案,因为容器应该被视为短暂的东西。

我完全明白,由于这种延迟,我可能需要重新考虑我的地理节点位置,并且可能还有其他一些我可以做的性能调整事情。不过,似乎应该有一种方法来强制执行我想要的行为。

当本地容器可用于处理给定请求时,我基本上想绕过 DNSRR 和 VIP/mesh 路由行为。

所以问题是:

如何让我的 web 应用程序的每个副本只访问本地 swarm 主机的 galera 容器而不用硬编码该容器的 IP 地址?

【问题讨论】:

    标签: docker-compose docker-swarm docker-networking


    【解决方案1】:

    如果其他人正在与此类问题作斗争,我想发布一个解决方案(尽管我不一定将其称为实际问题的“答案”),这更像是一种解决方法,而不是我实际上的解决方案满意。

    在我的 webapp 内部,我可以使用 galera_node 作为我的数据库主机,它解析为我上面提到的网状路由 VIP。无论如何,这都为我提供了功能,所以如果我的解决方法出现问题,我知道我的连接仍然完好。

    我编写了一个小 bash 脚本,我可以将其称为 cron 作业,并为我提供我想要的结果。它可以用于源于同一问题的其他用例。

    它接受三个参数:

    • $1 = 数据库容器名称
    • $2 = 数据库网络名称
    • $3 = webapp 容器名称

    该脚本查找容器名称,查找其指定网络的 IP 地址,然后将该容器名称和 IP 地址添加到 webapp 容器的 /etc/hosts 文件中。

    这是可行的,因为容器名称也是 galera_node(在我的情况下),因此将其添加到主机文件只会覆盖 docker 解析为 VIP 的主机名。

    如前所述,我不喜欢这个,但它似乎确实适合我的目的,它避免了我必须对 IP 地址进行硬编码和手动维护它们。我确信有些场景需要对脚本进行调整,但这是一个功能性起点。

    我的脚本:update_container_hosts.sh

    #!/bin/bash
    HOST_NAME=$1
    HOST_NETWORK=$2
    CONTAINER_NAME=$3
    
    FMT="{{(index (index .NetworkSettings.Networks \"$HOST_NETWORK\") ).IPAddress}}"
    CONTAINERS=`docker ps  | grep $CONTAINER_NAME | cut -d" " -f1`
    HOST_ID=`docker ps | grep $HOST_NAME | cut -d" " -f1`
    HOST_IP=$(docker inspect $HOST_ID --format="$FMT")
    
    echo --- containers ---
    echo $CONTAINERS
    echo ------------------
    echo host: $HOST_NAME
    echo network: $HOST_NETWORK
    echo ip: $HOST_IP
    echo ------------------
    
    for c in $CONTAINERS;
    do
        if [ "$HOST_IP" != "" ]
        then
            docker cp $c:/etc/hosts /tmp/hosts.tmp
            IP_COUNT=`cat /tmp/hosts.tmp | grep $HOST_IP | wc -l`
            rm /tmp/hosts.tmp
            if [ "$IP_COUNT" = "0" ]
            then
                    docker exec  $c /bin/sh -c "echo $HOST_IP $HOST_NAME >> /etc/hosts"
                    echo "$c: Added entry to container hosts file."
            else
                    echo "$c: Entry already exists in container hosts file.  Skipping."
            fi
        fi
    done
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-03
      • 1970-01-01
      • 2019-06-18
      • 2016-10-31
      相关资源
      最近更新 更多