Moleculer: Not entirely redundant

Created on 18 Sep 2018  Â·  6Comments  Â·  Source: moleculerjs/moleculer

Hi,
From what I can tell from this image on the sites documentation
Service graph
You can see the API Gateway is the single point of failure. It looks like it is the same problem with the transporter too.

Could we make it so that a instance of API Gateway is on each node and which node is used for the API Gateway is dependent on some sort of load balancing.

This guy implemented it fairly well: https://medium.com/@cramirez92/build-a-nodejs-cinema-microservice-and-deploying-it-with-docker-part-1-7e28e25bfa8b.

Thanks,
Jamie

Most helpful comment

Hey there,
first of all, I think the image in the docs is meant to illustrate that it is possible to run an arbitrary (mixed) amount of services in multiple nodes. So don't try to see it as a 1-by-1 schema of an architecture implementation (although it would be possible :)

Regarding transporter and API-Gateway: Nothing prevents you from starting more instances (replicas) of these nodes.
For transporter node (e.g. a NATS-server instance with docker) I would even prefer to have 3 or more nodes running in cluster mode, so that it is high-available. Many transporter types that are supported in moleculer provide a cluster-mode.

You can also start multiple instances of the API-Gatway node in the same fashion. But there I would recommend to have some sort of reverse-proxy (e.g. nginx) in front of them that has a load-balancing functionality.

So it totally depends on how you handle your architecture (and of course what needs you have).
I hope this helps somehow.

All 6 comments

Hey there,
first of all, I think the image in the docs is meant to illustrate that it is possible to run an arbitrary (mixed) amount of services in multiple nodes. So don't try to see it as a 1-by-1 schema of an architecture implementation (although it would be possible :)

Regarding transporter and API-Gateway: Nothing prevents you from starting more instances (replicas) of these nodes.
For transporter node (e.g. a NATS-server instance with docker) I would even prefer to have 3 or more nodes running in cluster mode, so that it is high-available. Many transporter types that are supported in moleculer provide a cluster-mode.

You can also start multiple instances of the API-Gatway node in the same fashion. But there I would recommend to have some sort of reverse-proxy (e.g. nginx) in front of them that has a load-balancing functionality.

So it totally depends on how you handle your architecture (and of course what needs you have).
I hope this helps somehow.

  1. That image is just an example. You can scale the API Gateway as you want and thus avoid having a single point of failure.

  2. You also can have API Gateway on each node. Just use mixins. However, in this case, inter service communications will incur some additional overhead due to HTTP. Other communication protocols are better suited for this kind of task

Also, check this site. It has a lot of different microservice-related design patterns

I agree with what has been said, but I want to point out a couple points that aren't on the moleculer site.

Running multiple services on the same node has some of the same characteristics as a monolithic app. One is that different services on the same node share resources (memory, for example). Another is that you can't scale each service individually.

The site @AndreMaz shared is a great resource and does a good job of explaining the trade-offs involved.

@faeron Yeah I don't know why but I thought the API Gateway service was a unique one where you couldn't do that. Annoyed with myself for assuming that now.

@Nathan-Schwartz I don't believe it would have the same characteristics as a monolithic app, because it's running vertically and horizontally in a service based manor. By having more than one instance of a service on a node you are scaling that service, the memory depends on how much you have. The whole point is that if one service goes down the app still functions even if you can't use that particular service. That can't happen in a monolith. You would be right if it were SOA.

Hey @jbonnett92, I tried to respond point by point, but please let me know if I missed something.

I don't run multiple services per node for my use cases; please feel free to correct me if I'm misunderstanding something. To clarify my position, I'm not saying that the Mixed Architecture is equivalent to the Monolithic Architecture, just that it shares some of the same characteristics. Pardon the long post, I want to be as clear as I can to avoid further miscommunication.

Please note that in my responses I'm assuming each node in the diagram you posted has the preferLocal option set to true. I think this is a reasonable assumption because my impression is that low latency is the primary motivation for the Mixed Architecture (as opposed to Microservices Architecture). This benefit is documented in the docs page where I found the diagram.

By having more than one instance of a service on a node you are scaling that service, the memory depends on how much you have.

I agree that if a set of services is available on a node and multiple nodes are running that same set of services, each service is scaled horizontally. It is also possible to scale a whole node vertically, but in the topology shown in the diagram it isn't possible to scale up any specific service independently. This was part of what I was trying to get at in my previous post.

Each "node" is run in a single Node.js process and when multiple services are loaded into one "node", they have to share that process's resources (the example I used was memory). I think this is similar to node.js monoliths: multiple application components that are available within a process. To be clear, I'm not saying that sharing resources between services is always a disadvantage, but it could be depending on the resource requirements of each service.


microservices.io touches on the advantages of not sharing the resources in the monolith page: "Also, different application components have different resource requirements - one might be CPU intensive while another might memory intensive. With a monolithic architecture we cannot scale each component independently".

The whole point is that if one service goes down the app still functions even if you can't use that particular service.

I'm interpreting this to mean that if one service goes down we want reroute requests to another instance of that service. I agree that this is a desirable property.

I think the "mixed" part of this architecture really presents here. I see two cases main cases:

  1. Request is made to a service that is not available locally. Example from diagram: Mailer service makes a request to Users service.
  2. Request is made to a service that is available locally. Example from diagram: Users service makes a request to Comments service

Please note that for the sake of brevity I've ignored the delay that might take place between a node going down and remote node registries marking the node as unavailable.

Case 1:
If Node 4 goes down, we can make our requests to Node 5 and things are good. (This is somewhat optimistic, given the assumption I mentioned.)

Case 2:
Note that since a node with multiple services runs in a single process with only one broker, its service's availability to remote nodes is tied to the remote nodes' registry.

My understanding after re-reading the code is that the request would be handled by the local service since we have preferLocal=true, unless the local action's circuit breaker was tripped. If this happens, we would try to make a request to a remote service if one is available.

In the case that we have tripped our local endpoint's circuit breaker and our node is unavailable due to a crash, there isn't a chance of us successfully making the remote call and handling its result.

In the case that we have tripped our local endpoint's circuit breaker and our node was unavailable due to missing heartbeats, we are already disconnected from the rest of the nodes, so our remote call won't succeed. (This is somewhat pessimistic because of our assumption, realistically there is a window where this could succeed.)

Section TL;DR: When the caller and callee are not colocated, the Mixed Architecture can take advantage of available remote services and continue to function despite the callee's node going down. If the caller and callee are colocated, it is unlikely that we can take advantage of available remote services in the case of the callee's node going down.

That can't happen in a monolith. You would be right if it were SOA.

If Node 4 went down the app would continue to function because Node 5 is still up, and it doesn't depend on Node 4. I think this is very similar to a monolith with multiple instances. If one instance goes down, the others would continue to function because the instances do not rely on each other.

TL;DR: For optimal fault tolerance in the face of service outages and the ability to scale efficiently, I think the Microservices Architecture is the best choice. If scaling services independently isn't a priority and sharing resources is okay, the Monolithic Architecture might be a good fit. I believe that the Mixed Architecture has some characteristics of both.

You have at least two solutions. The first is to use any balancer like nginx or haproxy (as @faeron wrote above) and the second is to use DNS balancing. Or you can even use these both solutions together (where DNS entries point to balancers). The main thing you need to do is to run multiple API gateway instances and then balance traffic by chosen way.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

HighSoftWare96 picture HighSoftWare96  Â·  4Comments

thatisuday picture thatisuday  Â·  3Comments

ngraef picture ngraef  Â·  3Comments

Kamil93 picture Kamil93  Â·  3Comments

DarkBlaez picture DarkBlaez  Â·  4Comments