akkadotnet / akka.net

Canonical actor model implementation for .NET with local + distributed actors in C# and F#.
http://getakka.net
Other
4.7k stars 1.04k forks source link

Support Multihoming #7170

Closed gunters63 closed 5 months ago

gunters63 commented 5 months ago

Is your feature request related to a problem? Please describe.

I have a use-case here where an Akka.Net server runs on an industrial controller with several network interfaces.

One of the interfaces is the "outer" interface connected to the company network.

The other "inner" interfaces (there are 4 of them) are used for several internal private networks and connect to other controllers/devices inside a control cabinet which are not reachable from the outside.

No bridging is happening, the internal and the outer subnets are completely separated. For connecting to the server from the outside you have to use the outer IP, from the inside you have to use one of the inner ones (each internal interface is in a seperate subnet).

The service which is running Akka.Net (and lots of other stuff) is acting as an application level bridge between the outer network and the internal network.

Now I have the problem that actors of the Akka.Net server have to be reachable from the inner AND the outer network.

If I understand correctly you can either specify a single specific address for the hostname or 0.0.0.0 to bind to all interfaces.

In my case I would have to use 0.0.0.0 of course.

So I would have to use public-hostname too, but this is limited to a single value. So I could only connect to Akka from the outside or one of the inside networks, not from several at once.

Describe the solution you'd like

Make it possible to connect to a multi-home Akka.Net service to several interfaces, not only a single one.

Describe alternatives you've considered

Specifying several enabled-transports doesn't seem to work in this case. I looked in the documentation and the source code (EndPoint.cs), but I didn't see a way to make my use-case happen.

Aaronontheweb commented 5 months ago

Do you need Akka.Cluster for this use case?

gunters63 commented 5 months ago

Maybe in the long run, I won't rule that out. But for the foreseeable future, no.

Aaronontheweb commented 5 months ago

Got it, so this is more of a remoting-only scenario - that's simpler to support. And you mentioned that running with multiple transports enabled didn't do the trick?

gunters63 commented 5 months ago

Hmm tbh, I not even tried it. How should that look like? I would have to have to several enabled transports of the same value:

        enabled-transports = ["akka.remote.dot-netty.tcp", "akka.remote.dot-netty.tcp"]
        dot-netty.tcp {
           .....
            public-hostname = 10.0.0.1
        }
        dot-netty.tcp { // illegal
           .....
             public-hostname = 10.0.0.2
        }
gunters63 commented 5 months ago

ah, i misunderstood this, probably something like this could work:

        enabled-transports = ["akka.remote.dot-netty.tcp-1", "akka.remote.dot-netty.tcp-2"]
        dot-netty.tcp-1 {
            transport-class = "....., Akka.Remote.DotNetty"
            port 8000
            hostname = 10.0.0.1
        }
        dot-netty.tcp-2 {
             transport-class = "....., Akka.Remote.DotNetty"
             port 8001
             hostname = 10.0.0.2
        }

I have to find out the correct value of transport class and will give it a try.

But I would to have to use different ports for each transport I guess because one transport <-> one socket,

Easier and more straight-forward would be if public-hostname could be either a string or an array of strings to check the incoming connections for the hostname.

gunters63 commented 5 months ago

I think I got it working like this (Hocon in JSON, only two interfaces configured yet):

    "remote": {
      "enabled-transports": [
        "akka.remote.dot-netty.tcp-eth0",
        "akka.remote.dot-netty.tcp-eth1"
      ],
      "dot-netty.tcp-eth0": {
        "transport-class": "Akka.Remote.Transport.DotNetty.TcpTransport, Akka.Remote",
        "transport-protocol": "tcp",
        "batching": {
          "enabled": true,
          "max-pending-writes": 30
        },
        "port": 50051,
        "hostname": "192.168.178.46"
        }
      },
      "dot-netty.tcp-eth1": {
        "transport-class": "Akka.Remote.Transport.DotNetty.TcpTransport, Akka.Remote",
        "transport-protocol": "tcp",
        "batching": {
          "enabled": true,
          "max-pending-writes": 30
        },
        "port": 50053,
        "hostname": "10.49.35.4"
        }
      }
    }

Specifying batching was needed, otherwise I got a null reference exception in Akka.Remote Batchwriter.

I think I can live with several sockets being used :).

Aaronontheweb commented 5 months ago

Specifying batching was needed, otherwise I got a null reference exception in Akka.Remote Batchwriter.

That is probably a HOCON lookup bug - we can probably harden that code inside Akka.Remote easily enough.

Aaronontheweb commented 5 months ago

So were you able to get this working @gunters63 ?

gunters63 commented 5 months ago

I couldn't test it thoroughly yet, but I am pretty confident it will resolve my issue. I can close the issue and re-open it if i unexpectedly find problems during testing. Maybe I don't find the time for testing until next week.

Aaronontheweb commented 5 months ago

Great! Let us know.