Moleculer v0.14 — Making Microservices Accessible for Everyone

André Mazayev
Published in
9 min readFeb 24, 2020

--

We are happy to announce that the latest (v0.14) version of Moleculer has been released! This release makes microservices even more developer-friendly. But before we dive into the features that this release brings, let’s think for a moment about what’s necessary to build a robust and scalable web application. To name a few:

  • Logs — Any application that goes into production must produce logs about the internal state changes and events of the system.
  • Metrics — In addition to logs, an application must be observable. It should be possible to track in real-time the resources that are being consumed by each service.
  • Tracing — Another crucial element is tracing. Tracking the interactions and identifying the bottlenecks between different parts of an application is a must.
  • Easily deployable — Nowadays the application must be easily containerized, replicated and deployed, either with Docker, Kubernetes or any other tool.
  • Fault-Tolerant — Even if you think that you’ve designed your application perfectly it will still fail, either by some external force (e.g., power outage, network issues, host crash) or internal one (e.g., bug). Therefore the application must be prepared for such situations and it must handle them gracefully.
  • Load Balancing — An application must also be capable of handling high loads and redirect requests to services that can rapidly process them.
  • Discoverable — All of the components of an application must be discoverable in an automated way, i.e., in a way that doesn’t require human intervention.

By now you must be thinking “Yes, these things are important but there are a lot of tools that provide these features. I can simply integrate them with the good old Express.js and be done with it.”. There is nothing wrong thinking this way. However, think about how much time you would have to invest in order to develop and integrate all of these features into your app. The answer to this question is quite simple: a lot! Moleculer, on the other hand, embeds all of the previously mentioned features directly into its core. That’s right, all of these features are available out-of-the-box with any Moleculer-based project. Moreover, Moleculer supports both RPC and event-driven architectures, it has built-in caching, data validation, it supports multiple messaging protocols (e.g., MQTT, NATS, AMQP) and much more.

Quick Overview

To speed-up the development process we’ve prepared a template that packs all the features into a simple demo project. So let’s take a look at it. First thing to do is to install Moleculer CLI:

npm i moleculer-cli -g

Next, we are going to use the CLI to generate the template project. To do it, run the following command:

moleculer init project moleculer-demo

After downloading the template, the CLI is going to ask you some questions. Press “Enter” for every prompt. This will configure the template and install the dependencies.

Questions asked during template installation

Inside of the project you will find:

Three Moleculer (micro)services:

  • api.service.js — Service responsible for handling the incoming HTTP requests.
  • greeter.service.js — Simple “Hello World” service with two service actions. One returns “Hello Moleculer” and the other one returns “Welcome <name>”, where the <name> is passed as an input parameter.
  • products.service.js — DB service with CRUD methods that uses NeDB during the development and MongoDB in production.

Tests (unit and integration) showing how to ensure that all of the components work as expected.

Docker and Kubernetes files that allow to deploy the application in a containerized way.

File structure of template project

Moreover, by answering “Yes” to all of the prompts, you’ve enabled tracing and metrics. This means that when you start the application Moleculer’s Service Broker will collect the metrics and it will trace the application calls. There is no prompt asking to enable service discovery because it is enabled by default. Moleculer uses master-less architecture where all of the nodes (OS process that host service instances) are equal. What this means is that Moleculer’s nodes exchange messages about the services that they host and their health status. By doing this we ensure that services discover themselves in an automated way, provide a way for load balancing the incoming requests and guarantee that our application is fault-tolerant. If some of the nodes goes offline, other nodes will simply redirect their calls to the other ones that are still up and running. To find out more about the available load balancing strategies and fault tolerance mechanisms check the documentation.

Being a progressive microservices framework means that there are multiple ways of deploying an application. For example, you can deploy it as a monolith where single node hosts all the services. Right now you might be questioning: What’s the purpose of deploying microservices as a monolith?. Well, not only this is great during the development process because you don’t have to worry about the networking issues, but it’s also good for your wallet! When you start a new project you probably won’t have a lot of users, so there is really no need to waste your money by renting a large amount of hardware resources. In the beginning, a monolith deployment might be enough. Then, when your project starts to grow, you can easily scale your app, but more on this later… Another benefit of deploying multiple services as a monolith is that it can improve the responsiveness of your app. For example, imagine that you have `posts` service that calls `users` service multiple times. To cut down the network latency between the services you can deploy them on a single node. When services are running on the same node they bypass the networking module (transporter) and communicate with each other via local bus. By doing this kind of deployment you can greatly reduce the response time for the incoming requests. Of course, you can create replicas of nodes that contain multiple service instances or you can deploy your services in a completely distributed manner. Progressive simply means that you can easily create a deployment configuration that fits your needs.

But enough of talking, let’s finally start the application. To do it run

npm run dev

This command will start the application in development mode, i.e., it will create a single node that will host all of the services. Visually this deployment looks like this:

Development configuration

Let’s also take a look at the “greeter.service.js” to see how a typical service looks like.

Service schema of greeter service

The greeter service has two actions (hello and welcome) and both of them are accessible via API gateway at /hello and /welcome endpoints. With Moleculer v0.14 you can declare the HTTP endpoints directly in action schema. Thanks to the service discovery that we’ve mentioned before, the api service will discover other services and it will automatically generate the mappings between the HTTP routes and service actions.

Routes generated by the API gateway service

By default, the api service starts the HTTP server at http://localhost:3000/. Clicking on this link will open the web interface that has the information about the configuration of the node, it’s health status and it also allows to call service actions.

Web interface of the template project

Notice that when you call an action the terminal prints the logs and the tracing information. By default, this information is shown in the terminal but you can easily select other solutions. For example, for logging you can use one of the following loggers: Pino, Bunyan, Winston, debug, Log4js, Datadog. If necessary, you can even use multiple loggers at the same time! For tracing you can select Jaeger, Datadog or Zipkin. To find out more check the logging and tracing documentation.

Logs and tracing information

Docker Deployment

Now that you’ve seen the contents of the template project, let’s see how Docker can help us deploying the services in a distributed way. To deploy the application run the following command:

npm run dc:up

This will create 6 containers:

  • Traefik — For for load balancing the incoming HTTP requests.
  • API Gateway — API gateway that will handle the incoming HTTP requests and map them into service calls.
  • NATS — NATS server that services will use to exchange messages.
  • Greetergreeter service.
  • Products products service that will store the products in MongoDB.
  • MongoDB — MongoDB that will be used by products service to store the data.

Visually this deployment looks like this:

Production configuration

Notice that we’ve just went from a monolith deployment to a completely distributed one without changing a single line of code. The deployment is configured in the docker-compose.env and the docker-compose.yml files. The first one contains common configurations that all of the nodes share, such as the address of the NATS server. Then in docker-compose.yml file we specify, via environment field, what service instance(s) should start in a particular container. In this case, we start only one service per Docker container.

Docker environment variables
Docker-compose configuration for “products” service

Now imagine that your services are under high load and are no longer capable of dealing properly with the incoming requests. In this case you need to scale your app and create multiple replicas of your services. But how? Just run the following command and you’re done.

docker-compose up -d --scale api=2 --scale greeter=2 --scale products=2

This will create 2 instances of each service. Once again, Moleculer’s service discovery and Traefik, that uses docker-compose labels for service discovery, handles everything for you. Traefik will load balance the incoming HTTP requests between the 2 instances of API gateway and Moleculer will handle the balancing between the services. Open up the web interface and check the Services tab. You will see that services are in fact running on multiple node instances. Awesome, right?

Web interface showing that there are 2 instances of each service

Metrics

Once the application is up and running the Service Broker will start collecting the metrics stats. Moleculer supports multiple (e.g., Datadog, Prometheus, StatsD) metrics solutions out-of-the-box. By default, Prometheus is used in the template project. If you’re familiar with Prometheus you know that it uses “pull model” where the Prometheus server pulls the metrics data from a set of targets. However, at this moment Prometheus doesn’t support docker labels to discover the targets (Traefik is great at doing this). Once again, Moleculer’s service discovery solves this issue. Thanks to the service discovery we can generate on-the-fly a target file that Prometheus can read and, therefore, monitor the stats of the services. We’ve created a Github repository with a detailed guide about how to set the things. Once Prometheus starts to scrap the metrics you can easily create beautiful dashboards such as the one presented below:

Grafana interface with the collected metrics

Conclusion

As you saw throughout this article, Moleculer covers all of the items in the list that we’ve created in the beginning. By providing all of these features out-of-the-box, Moleculer drastically increases your productivity and helps you to quickly build and deploy your application.

If you have any questions please come chat with us at Discord. Happy coding!

--

--