Search code examples
architecturemicroservices

What are the best practices to use for Microservices with API Gateway?


we are going through some serious architecture refactor in my system that is still in the design phase.

Today our system has a single server side in NestJS. Instead, we want to use microservices.

I have some questions about microservices architecture best practices:

  1. We have a use case for receiving feedbacks from clients. In our flow we want the feedback to be saved in DB and also to be sent to a specific mail. We have another use cases that use mails so we want to have a specific microservice for sending mails, and the microservice will receive the mail to send using RabbitMQ. THE QUESTION: In the use case described here, is it better to (1) have microservice for feedbacks that will save in the DB and will use the mails microservice for sending the mail or (2) when a feedback is sent from the client - the mail microservice will get it and send the mail, and for the DB there will be a separate microservice that will perform DB interactions and will save the feedbacks?
  2. Is it even a good practice to do specific microservice for DB interactions?
  3. What is the right practice for communication between microservices - (1) each microservice use another microservice directly (chareography, meaning every microservice knows about the other microservices and the interface to use them) or (2) there will be something that encapsulates the other microservice and to use another microservice, the first microservice will have to go through this "middleware" (orchestrator, meaning there is something that is in the middle of each microservice)? A diagram to make my question more clear: enter image description here
  4. What are better ways for communication between microservices expect for RabbitMQ or Kafka?

EDIT: After the answers I got here and a little more research things got more clear to me. One important thing I still would like help with is deciding whether to use orchestrator or choreography in my feedback case. To make my use case more clear - failure in sending mail or in storing the feedback in DB shouldn't make the other operation to fail - they are independent. Now - there are two ways:

  1. Orchestra - I have a main feedback microservice which is the orchestrator and a utility microservice for email - when feedback sent from the client it is received in the main feedback microservice which stores it in DB and uses the mail microservice for sending the mail - while the mail microservice is a general one and doesn't aware to the feedback mail structure. Since it is an async operation then the mail will receive the mail event using async queue. It will use async operation and not pub-sub. The advantage is that there is something that manages the feedback logic, the disadvantage is when I would need to add new behavior - I will have to change the main feedback service and deploy new version that could break things.
  2. Choreography - When feedback comes from client - it will be received in queue that have two independent consumers - the first is a microservice for storing feedback in DB and the second for sending mail - this option makes the mail microservice to be aware of different types of mail structures including feedback mail structure. The queue will work using pub-sub. An advantage is that - if I want to add new operation - I just need to add another consumer. The disadvantage is there is nothing that manages the flow of feedback.

A diagram: enter image description here

What is the better option for this use case?


Solution

    1. We have a use case for receiving feedbacks from clients. In our flow we want the feedback to be saved in DB and also to be sent to a specific mail. We have another use cases that use mails so we want to have a specific microservice for sending mails, and the microservice will receive the mail to send using RabbitMQ. THE QUESTION: In the use case described here, is it better to (1) have microservice for feedbacks that will save in the DB and will use the mails microservice for sending the mail or (2) when a feedback is sent from the client - the mail microservice will get it and send the mail, and for the DB there will be a separate microservice that will perform DB interactions and will save the feedbacks?

    Common practise is to use a microservice for a dedicated (series) of tasks/responsibility. Storing feedback and sending mail are two such dedicated tasks and could/should be handled by dedicated microservices.

    It is recommended to avoid direct dependencies between different services. One service calling another service through for example a REST API is such a dependency. The other service might be not available making your first service unavailable as well (unless you implement some kind of mechanism to handle those circumstances). It also makes it difficult to maintain when the interface of a dependent service changes. This would require you to change the calling service as well.

    A possible solution would be to reply on event driven design. Your feedback services stores the feedback in its database and broadcasts an event to inform other interested parties a mail message needs to be send. This event contains everything needed to send the email message. A mail service listening for this event picks it up and handles the message delivery. This way the fact the mail service is offline, is handled by your messaging system in between.

    Letting your client call both microservices directly might make things more complicated as well and could potentially create unnecessary network calls between client and backend.

    1. Is it even a good practice to do specific microservice for DB interactions?

    I don't know I understand your remark entirely but sure, there is nothing wrong with using microservices for DB interaction. A lot depends on your intended use to choose one database or another. You could even go one step further and make dedicated services for writing and dedicates services for reading data from databases. Check CQRS for more information about this.

    1. What is the right practice for communication between microservices - (1) each microservice use another microservice directly (chareography, meaning every microservice knows about the other microservices and the interface to use them) or (2) there will be something that encapsulates the other microservice and to use another microservice, the first microservice will have to go through this "middleware" (orchestrator, meaning there is something that is in the middle of each microservice)? A diagram to make my question more clear:

    I think you misunderstood something here.

    Choreography does not mean one services knows about the other and its interface. Choreography means services talk to each other using events and an intermediate messaging system (a broker if you like). Services 'broadcast' events and other interested services 'listen' for them.

    Orchestration puts a certain 'service' or other component in the middle to handle the flow between all involved parties as you pointed out in your diagram.

    Whether to choose orchestration or choreography depends on the use case and the complexity of your entire solution. There is no silver bullet to use. One thing to keep in mind maybe, choreography makes it difficult to know who's talking to who when the number of services increase. Orchestration might keep things a bit clearer to understand.

    1. What are better ways for communication between microservices expect for RabbitMQ or Kafka?

    Again, everything depends on the use case, your experience and what you do or don't prefer. Besides the solutions you mention, you could also take a look at AxonIQ Framework/Server or Eventuate. Both of them are event sourcing solutions used in microservice architectures. Bernd Ruecker also blogged some interesting articles about using BPMN engines for microservice orchestration which might be worth looking at.

    Additional info after the author's original question edit

    Referring to your first diagram. Assuming your mail service is responding to a message sent by your feedback service, this could actually also be considered choreography instead of orchestration.

    The idea behind orchestration is to increase de-coupling. To use orchestration, a kind of 'conductor' is placed between the feedback and mail service responding to e.g. a FeedbackStoredEvent and translation it into SendEMailMessageCommand. This way, the feedback service is completely unaware of the commands the mail service can receive and the mail services does not know any events sent by the feedback service. Both are completely unaware of each other therefore decoupled. The only party knowing about both, is your orchestrator which is acceptable. If you have to add additional behavior, this is the component to be updated according to your new business case. Important is obviously not to include the 'conductor' logic as a part of your feedback service but as some kind of translator in between... This was not clearly emphasized in my previous response.