负载平衡多实例集群背后的事件源

I wrote a simple Web application to print the http request via Eventsource. However I realized then when deployed in a typical ECS cluster, i.e. upon at least two instances behind a load balancer, if the user is connected to one instance and the hook is received by the other instance (assuming load balancer dispatches two different instances), the request will not be shown.

I've seen this sort of problem before fitting other (stateful?) applications into this AWS scaling style of deployment of spinning new instances behind a load balancer. Is there a name for it? Any suggestions how to fix my program so that it can fit the AWS model? I guess the hook would need to be written to some datastore and the eventsource publisher needs to poll or rather preferably event from it?

EventSource SSE behind a Load Balanced Multi-instance Cluster

Pull request: https://github.com/unee-t/showhook/pull/1

The servers behind the load balancer need to be kept informed of /events. When the event is received on the neighboring server, that server must inform the group of the received event.

EventSource Golang Server

Example Usage

Get the repository.

git clone git@github.com:stephenlb/showhook.git
cd showhook

You have to setup the project with make.

make build
make network

Now you can run your containers. Note that we have a 12MB container with your binary. We made the container small by creating a build-container and a runtime-container in the Dockerfile. This takes the container from 400MB down to 12MB.

My personal opinion is that you should find a key piece of technology (Push notifications, PubNub, Aws IOT, Firebase) to helps you solve this problem instead of building your own.

These HTTP instances are stateful and so you need to be able to share state between them. Scaling persistent connections is difficult and it becomes even harder with a round-robin load balancer in front of it. I suggest you look for a service that does all of this for you.

If you want roll your own i would suggest you look into:

  • Redis. Using one queue per user.
  • Rabbit MQ - Creating a queue per user. I don't think this will scale but maybe it works for your case.
  • Use some sort sort fo clustering framework. I have no idea about GO. Platforms like Erlang/Elixir or Akka have support for clustering. Typically you can connect to any of the nodes of the cluster and the messages will be delivered to you.

These realtime systems don't scale well using a request/response/polling model. If you don't need it to scale just store your data in mysql or REDIS and poll it.

SNS + SQS Fanout

In my view, this is a problem that can be neatly solved using SNS + SQS, with the Fanout pattern. You can architect this by having a SNS Topic where one service would publish a specific message (not caring about consumers at all - this helps decoupling) and you would have queues subscribed to this topic where other services would be able to consume it, in their own pace, the same messages. So, yes, this would solve the many receivers (or subscribers) problem.

SNS + SQS Fanout

It would be something like this:

You have a topic (TopicX) on SNS

Service B has its own queue (QueueB); QueueB is subscribed to TopicX

Service C has its own queue (QueueC); QueueC is subscribed to TopicX

Service A performs an operation that needs to be shared across your network

Service A publishes Message1 to TopicX

QueueB receives Message1

QueueC receives Message1

ServiceB consumes Message1

ServiceB deletes Message1 from QueueB

ServiceC consumes Message1

ServiceC deletes Message1 from QueueC

Check https://docs.aws.amazon.com/sns/latest/dg/SNS_Scenarios.html for more details on this pattern.