Akka.net 通过 Docker 容器远程处理:客户端随机无法连接到主机 [英] Akka.net remoting over Docker containers: client randomly fails to connect to host

查看:36
本文介绍了Akka.net 通过 Docker 容器远程处理:客户端随机无法连接到主机的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有一个带有 TestActor 的简单主机,它只将接收到的字符串写入控制台:

using (var actorSystem = ActorSystem.Create("host", HoconLoader.FromFile("config.hocon"))){var testActor = actorSystem.ActorOf(Props.Create(), "TestActor");Console.WriteLine($"等待请求...");而(真){Task.Delay(1000).Wait();}}

另一方面,有一个简单的客户端,它选择远程角色并将一个 TestMessage 传递给它,然后在没有指定超时的情况下等待询问.

using (var actorSystem = ActorSystem.Create("client", HoconLoader.FromFile("config.hocon"))){var testActor = actorSystem.ActorSelection("akka.tcp://host@host:8081/user/TestActor");Console.WriteLine($"发送消息...");testActor.Ask(new TestMessage($"Message")).Wait();Console.WriteLine($"消息确认.");}

客户端和主机部署在两个Docker容器(docker-compose)上,其网络配置如下(docker network inspect ...):

<预><代码>[{"Name": "akkaremotetest_default","Id": "4995d7e340e09e4babcca7dc02ddf4f68f70761746c1246d66eaf7ee40ccec89","创建": "2018-07-21T07:55:39.3534215Z","范围": "本地","司机": "桥",启用IPv6":假,IPAM":{"驱动程序": "默认",选项":空,配置":[{"子网": "172.19.0.0/16",网关":172.19.0.1"}]},内部":假,可附加":假,入口":假,配置自":{网络": ""},ConfigOnly":假,容器":{6040c260c5195d2fe350bf3c89b5f9ede8a65d44da6adb48817fbef266a99e07":{"Name": "akkaremotetest_host_1","端点ID": "a6220a6fee071a29b83e30f9aeb9b9e7ec5008f04f593ff3fb2464477a7e54aa","MacAddress": "02:42:ac:13:00:02","IPv4Address": "172.19.0.2/16","IPv6 地址": ""},a97078c28c7d221c2c9af948fe36b72590251be69e06d0e66eafd2c74f416037":{"Name": "akkaremotetest_client_1","端点ID": "39bcb8b1047ad666d9c568ee968602b3a93edb4ac2151ba9c3f3c02359ef84f2","MacAddress": "02:42:ac:13:00:03","IPv4Address": "172.19.0.3/16","IPv6 地址": ""}},选项": {},标签": {}}]

当容器启动时,结果是以下之一:

  • 客户端通过 Ask 成功,actor 将接收到的消息写入控制台,客户端确认成功,
  • 客户端永远挂起,actor 永远不会收到消息,不会发生超时.

问题是后者大部分时间都会发生,但只有在主机和客户端部署在Docker容器上时才会发生.独立运行时,不存在通信问题.

我想我尝试了所有方法都没有结果,而且我不知道我还能做些什么来调查为什么客户端的 Ask 会永远持续下去,而这两个 Actor 系统中的任何一个都没有记录任何错误.

这里是 Docker 配置(yml):

版本:'2'服务:主持人:端口:- 8081:8081建造:语境: .dockerfile: Dockerfile参数:PROJECT_DIR:主机PROJECT_NAME:主持人WAIT_FOR_HOST: 0重启:失败客户:取决于:- 主持人端口:- 8082:8082建造:语境: .dockerfile: Dockerfile参数:PROJECT_DIR:客户端PROJECT_NAME:客户WAIT_FOR_HOST:1重启:失败tcp转储:图片:kaazing/tcpdump网络模式:主机"卷:- ./tcpdump:/tcpdump

这里是客户端系统的配置(config.hocon):

akka {演员{提供者 = 远程}偏僻的 {点netty.tcp {启用传输 = ["akka.remote.netty.tcp"]主机名 = 客户端端口 = 8082}}标准输出日志级别 = 调试日志级别 = 调试登录配置启动 = 开启演员{创建超时 = 20 秒调试{接收 = 打开自动接收 = 打开生命周期 = 开事件流 = 开未处理 = 打开fsm = 开事件流 = 开日志发送消息 = 开日志接收消息 = 开路由器错误配置 = on}}}

这里是主机系统的配置(config.hocon):

akka {演员{提供者 = 远程}偏僻的 {点netty.tcp {启用传输 = ["akka.remote.netty.tcp"]主机名 = 主机端口 = 8081}}标准输出日志级别 = 调试日志级别 = 调试登录配置启动 = 开启演员{创建超时 = 20 秒调试{接收 = 打开自动接收 = 打开生命周期 = 开事件流 = 开未处理 = 打开fsm = 开事件流 = 开日志发送消息 = 开日志接收消息 = 开路由器错误配置 = on}}}

遵循有关

这是连接成功时发生的情况:

172.19.0.3 ->172.19.0.2:同步172.19.0.2 ->172.19.0.3:同步,确认172.19.0.3 ->172.19.0.2:确认172.19.0.3 ->172.19.0.2:PSH、ACK172.19.0.2 ->172.19.0.3:确认172.19.0.2 ->172.19.0.3:PSH,确认172.19.0.3 ->172.19.0.2:确认172.19.0.3 ->172.19.0.2:PSH、ACK

版本:

  • Akka.NET 1.3.8
  • .NET 核心 2.1.1
  • Docker 18.03.1-ce,构建 9ee9f40
  • Docker-compose 1.21.1,构建 7641a569

解决方案

事实证明,问题源于这样一个事实,即项目依赖于 .NET Core 2.1,根据 这个:

<块引用>

我们尚未正式支持 .NET Core 2.1.哎呀,我们甚至没有netstandard 2.0(虽然工作正在进行中).但感谢确认确实存在问题:)

切换到 .NET Core 2.0 后,我无法再重现所描述的问题.

There is a simple host with a TestActor that only writes a string it receives to the console:

using (var actorSystem = ActorSystem.Create("host", HoconLoader.FromFile("config.hocon")))
{
    var testActor = actorSystem.ActorOf(Props.Create<TestActor>(), "TestActor");

    Console.WriteLine($"Waiting for requests...");

    while (true)
    {
        Task.Delay(1000).Wait();
    }
}

On the other side there is a simple client that selects the remote actor and passes a TestMessage to it, then waits on an ask without a timeout specified.

using (var actorSystem = ActorSystem.Create("client", HoconLoader.FromFile("config.hocon")))
{
    var testActor = actorSystem.ActorSelection("akka.tcp://host@host:8081/user/TestActor");

    Console.WriteLine($"Sending message...");

    testActor.Ask(new TestMessage($"Message")).Wait();

    Console.WriteLine($"Message ACKed.");
}

The client and the host are deployed on two Docker containers (docker-compose), whose network configuration is as follows (docker network inspect ...):

[
    {
        "Name": "akkaremotetest_default",
        "Id": "4995d7e340e09e4babcca7dc02ddf4f68f70761746c1246d66eaf7ee40ccec89",
        "Created": "2018-07-21T07:55:39.3534215Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.19.0.0/16",
                    "Gateway": "172.19.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "6040c260c5195d2fe350bf3c89b5f9ede8a65d44da6adb48817fbef266a99e07": {
                "Name": "akkaremotetest_host_1",
                "EndpointID": "a6220a6fee071a29b83e30f9aeb9b9e7ec5008f04f593ff3fb2464477a7e54aa",
                "MacAddress": "02:42:ac:13:00:02",
                "IPv4Address": "172.19.0.2/16",
                "IPv6Address": ""
            },
            "a97078c28c7d221c2c9af948fe36b72590251be69e06d0e66eafd2c74f416037": {
                "Name": "akkaremotetest_client_1",
                "EndpointID": "39bcb8b1047ad666d9c568ee968602b3a93edb4ac2151ba9c3f3c02359ef84f2",
                "MacAddress": "02:42:ac:13:00:03",
                "IPv4Address": "172.19.0.3/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {}
    }
]

When the containers are started, the result is one of the following:

  • the client succeeds with the Ask, the actor writes received message to the console, and the client confirms success,
  • the client hangs forever, the actor never receives the message, timeout does not occur.

The problem is that the latter happens most of the time, but only when the host and the client are deployed on Docker containers. When run independently, there are no communication issues.

I think I tried everything without results, and I don't know what else I could do to investigate why the Ask of the client lasts forever, with no errors logged by any of these two actor systems.

Here is the Docker configuration (yml):

version: '2'

services:

  host:
    ports:
      - 8081:8081
    build:
      context: .
      dockerfile: Dockerfile
      args:
        PROJECT_DIR: Host
        PROJECT_NAME: Host
        WAIT_FOR_HOST: 0
    restart: on-failure

  client:
    depends_on:
      - host
    ports:
      - 8082:8082
    build:
      context: .
      dockerfile: Dockerfile
      args:
        PROJECT_DIR: Client
        PROJECT_NAME: Client
        WAIT_FOR_HOST: 1
    restart: on-failure

  tcpdump:
    image: kaazing/tcpdump
    network_mode: "host"
    volumes:
      - ./tcpdump:/tcpdump

Here is the configuration of the client system (config.hocon):

akka {     
    actor {
        provider = remote
    }

    remote {
        dot-netty.tcp {
            enabled-transports = ["akka.remote.netty.tcp"]
            hostname = client
            port = 8082
        }
    }

    stdout-loglevel = DEBUG
    loglevel = DEBUG
    log-config-on-start = on        

    actor {      
        creation-timeout = 20s  
        debug {  
              receive = on 
              autoreceive = on
              lifecycle = on
              event-stream = on
              unhandled = on
              fsm = on
              event-stream = on
              log-sent-messages = on
              log-received-messages = on
              router-misconfiguration = on
        }
    }
}

Here is the configuration of the host system (config.hocon):

akka {     
    actor {
        provider = remote
    }

    remote {
        dot-netty.tcp {
            enabled-transports = ["akka.remote.netty.tcp"]
            hostname = host
            port = 8081
        }
    }

    stdout-loglevel = DEBUG
    loglevel = DEBUG
    log-config-on-start = on        

    actor {        
        creation-timeout = 20s  
        debug {  
              receive = on 
              autoreceive = on
              lifecycle = on
              event-stream = on
              unhandled = on
              fsm = on
              event-stream = on
              log-sent-messages = on
              log-received-messages = on
              router-misconfiguration = on
        }
    }
}

Following the documentation concerning Akka remote configuration, I attempted to change the client configuration like this:

remote {
    dot-netty.tcp {
        enabled-transports = ["akka.remote.netty.tcp"]

        hostname = 172.19.0.3
        port = 8082

        bind-hostname = client
        bind-port = 8082 
    }
}

and the host configuration by analogy:

remote {
    dot-netty.tcp {
        enabled-transports = ["akka.remote.netty.tcp"]

        hostname = 172.19.0.2
        port = 8081

        bind-hostname = host
        bind-port = 8081 
    }
}

with a slight change in actor selection as well:

var testActor = actorSystem.ActorSelection("akka.tcp://host@172.19.0.2:8081/user/TestActor");

Unfortunately this has not helped at all (nothing has changed).

In the logs that are generated during the process, there is a crucial entry that is generated by the host system. Only when it appears, the communication is successful (but most often it does not):

[DEBUG][07/21/2018 09:42:50][Thread 0006][remoting] Associated [akka.tcp://host@host:8081] <- akka.tcp://client@client:8082

Any help will be appreciated. Thank you!

-- EDIT --

I added the tcpdump section to yml and opened the generated dump file in Wireshark. I also added a 5-second timeout to waiting on ask. It is hard for me to interpret the results, but here is what I got on a failed connection attempt:

172.19.0.3 -> 172.19.0.2: SYN
172.19.0.2 -> 172.19.0.3: SYN, ACK

172.19.0.3 -> 172.19.0.2: ACK

[a 5-second period of silence (waiting till timeout)]

172.19.0.3 -> 172.19.0.2: FIN, ACK

172.19.0.2 -> 172.19.0.3: ACK
172.19.0.2 -> 172.19.0.3: FIN, ACK

172.19.0.3 -> 172.19.0.2: ACK

and here is what happens when connection succeeds:

172.19.0.3 -> 172.19.0.2: SYN
172.19.0.2 -> 172.19.0.3: SYN, ACK

172.19.0.3 -> 172.19.0.2: ACK
172.19.0.3 -> 172.19.0.2: PSH, ACK

172.19.0.2 -> 172.19.0.3: ACK
172.19.0.2 -> 172.19.0.3: PSH, ACK

172.19.0.3 -> 172.19.0.2: ACK
172.19.0.3 -> 172.19.0.2: PSH, ACK

Versions:

  • Akka.NET 1.3.8
  • .NET Core 2.1.1
  • Docker 18.03.1-ce, build 9ee9f40
  • Docker-compose 1.21.1, build 7641a569

解决方案

It turns out that the issue stems from the fact that the projects are dependent on .NET Core 2.1 which Akka does not support yet according to this:

We don't officially support .NET Core 2.1 yet. Heck, we aren't even on netstandard 2.0 yet (although work is underway). But thanks for confirming that there are indeed issues :)

After switching to .NET Core 2.0, I can no longer reproduce described issue.

这篇关于Akka.net 通过 Docker 容器远程处理:客户端随机无法连接到主机的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆