Communication between two microservices - java

I am creating a project with microservices architecture. And I created two microservices.
One of them is for product entity, the other is for bill entity. They have their own endpoints and they are connected together with the gateway (i am using jhipster microservices architecture).
The bill-ms should access to list of products. I'm wondering how I can communicate between those two ms. I have three approaches in my mind:
Send a request from bill-ms to queue - like rabbitMQ, to get these products with these ids from product-ms (I don't know what is bottleneck of this)
Send a request to gateway for product service and get the product from there (I'm worried about the latency because of the data size between them and in this way I'm not touching the database directly so I always depend on the gateway)
I can duplicate the repositories, services and entities in bill-ms (it's an ugly way, and I think it breaks the rule of ms-architecture and the maintenance is very difficult)
If you have any other approaches, I appreciate you to share it with me.
Edit
Now I know what the bottleneck is: say that there are 3 instance of bill-ms and how does rabbitMQ decide which instance to respond? or how should I say to ribbon "give me the free instance of bill-ms to subscribe to the request from rabbitMQ" for load balancing.

I'm not sure if what I am going to answer is thé right way. I'm still learning myself.. But I can tell you how I've implemented my microservices attempts..
First, I started with HTTP communication based microservices using this blog. This works fine, but the problem is, that you create dependendies between your services. Service A needs to be aware of a service B and needs to call it directly (via service discovery etc of course). This is what you generally are trying to avoid when developing microservices.
Another approach that I've started with lately, is using a message bus. It's actually the 3rd option that you touched in your question.
I have a service A, which stores persons (just an example). What the service does when it creates a new person is: It sends an event on a RabbitMQ bus: personCreatedEvent.
If there are any other services interested in events like this, they can subcribe to them. These interested services keep the relevant information that they are interested in, in their own datastores.
With this last approach, there is not really a dependency between your services, because they don't communicate with each other directly. Service A is not aware of service B, because B just sends events to RabbitMQ to whichever service is interested to these events and vice versa.
Of course, you have duplications between datastores over the service. But this can be profitable as well, e.g. service B doesn't need to use the same schema or data store mechanism as service A. It only stores the relevant information in the way that is best for this service.

Have you looked at http://stytex.de/blog/2016/03/25/jhipster3-microservice-tutorial/ Part 2: inter-service communication section. It walks you through a specific example of how it is achieved

Let me try and add some more details to this scenario to stress what may or may not qualify as an event in the context of Product and Biiling. The Billing-MS would need to talk to Product-Ms only in case an Order is placed. Placing an Order would mostly be for a separate MS let's say Order-MS. When an order is created or placed, it will contain information of Products as line items.
Creation of an Order can be considered as an event. When Order creation event occurs, it can be pushed to a Queue for the Billing service. Queue should be implemented as a Work-queue in RabbitMQ. This way, multiple instances of the Billing-MS can subscribe to the same Queue but it'll be processed by one and only one Worker. There is no role of RIBBON in registering a service as a Worker to RabbitMQ. Each instance registers to a Queue and RabbitMQ decides RoundRobin which instance of Billing Service gets to process this event.
Getting details of Products in an Order for the Billing-Ms should be a Service-to-Service call load balanced via Ribbon (if that's what you are using). Getting Product details is not really an event, placing an Order is, hence the difference.
Also, Gateway should be used for exposing your Edge services. For Service-to-Service calls, it would not be ideal to hop via Gateway service.

One option is sending a request to bill microservice using it's registred name on the eureka registry.

you can use below solution :
Microservice A (i.e UAA-SERVICE), and Microservice B.
Microservice B want to connect microservice A and call services with Feign client.
1)This code for Microservice B
#AuthorizedFeignClient(name = "UAA-SERVICE")
public interface UaaServiceClient {
#RequestMapping(method = RequestMethod.GET, path = "api/users")
public List<UserDTO> getUserList();
#RequestMapping(method = RequestMethod.PUT, path = "api/user-info")
public String updateUserInfo(#RequestBody UserDTO userDTO);
}
UAA-SERVICE : find this name with running Application Instances with registry.
2) In Microservice B (application.yml)
Increase feign client connection Time Out------>
feign:
client:
config:
default:
connectTimeout: 10000
readTimeout: 50000
enter image description here
Increase hystrix Thread time out-------->
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 60000
shareSecurityContext: true
enter image description here
3) add #EnableFeignClients in main #SpringBootApplication class.------->
This solution is working fine for me.

In general, you have two good options to communicate microservices and also several more to avoid as possible:
Don't use shared db's
Don't use FTP file sharing
Don't use in-memory shared databases
Don't use CSV or the kind
What to use:
Option 1 (the best): Use a queue system to share messages, so if Microsoervice B needs some information from Microservice A, A will send a message to the queue and B will consume it. This is the most resilient solution as, if B is down, it will consume the message anyway when it recovers.
Option 2: Use a RESTFul endpoint, you can call from A to inform B or from B to get information from A. The problem is that, if the receiver is down or failing, the request will break and you will desync. You need to implement a circuit-breaker then to avoid losing it.
You may find more information on how to communicate microservices properly in my article on Communicating microservices the proper way.

Related

Persisting related data after client has completed some web service calls in a chain

Consider that our application has some configs that user set them, and we need to have a backup of those data in order to restore them later.
Configs are list of different Objects and I have created some web services for each List of Object and application calls them in a chain, it means that with getting success response from one service they call the next one.
Now what the problem is...
I need to store each services data somewhere and after finishing the last service call in front end, I will create the final Object with received data from client and persist it in database(here MongoDB).
What is the best way for implementing this strategy?, consider that I don't want to persist each List of Object per service, I need to persist whole Object once.
Is there any way for storing body of a request somewhere until other services to be called?
What is the best for that?
I will appreciate any clue or solution that help me!
BEST WAY:
store all objects in client side and send only one request to server.
it reduces resource usage of server side.
ALTERNATIVE:
if you realy want to handle it by several requests (which I do not recommend it) then one strategy is : store objects of each request by an identifier related to that session (best candidate is JSESSIONID) to a temporary_objects_table and after final request store it in main tables.
and in failure of any service for that session, remove records with that sessionid from temporary_objects_table.
it has much more complexity comparing first approche.
After some research I found my answer:
REST and transaction rollbacks
and
https://stackoverflow.com/a/1390393/607033
You cannot use transactions because by REST the client maintains the client state and the server maintains the resource state. So if you want the resource state to be maintained by the client then it is not REST, because it would violate the stateless constraint. Violating the stateless constraint usually causes bad scalability. In this case it will cause bad horizontal scalability because you have to sync ongoing transactions between the instances. So please, don't try to build multi-phase commits on top of REST services.
Possible solutions:
You can stick with immediate consistency and use only a single
webservice instead of two. By resources like database, filesystem,
etc. the multi phase commit is a necessity. When you break up a
bigger REST service and move the usage of these resources into
multiple smaller REST services, then problems can occur if you do
this splitting wrongly. This is because one of the REST services will
require a resource, which it does not have access to, so it has to
use another REST service to access that resource. This will force the
multi phase commit code to move to a higher abstraction level, to the
level of REST services. You can fix this by merging these 2 REST
services and move the code to the lower abstraction level where it
belongs.
Another workaround to use REST with eventual consistency so you can
respond with 202 accepted immediately and you can process the
accepted request later. If you choose this solution then you must be
aware by developing your application that the REST services are not
always in sync. Ofc. this approach works only by inner REST services
by which you are sure that the client retry if a REST service is not
available, so if you write and run the client code.

How to manage Many To Many relations in microservices architecture?

If i have the below entities in tow separate microservices :
class Employee {
#Id
private Long employeeId;
private String name;
...
}
class Department {
#Id
private Long deptId;
private String name;
...
}
How can i add a many to many relation between the entities ?
I thought of combine the two entities in one entity on the gateway :
class Empl_Dept{
List<Long> employeeIds;
List<Long> departmentIds;
}
so the junction table will be on the gateway side.
Is there any better solution??
Assuming you have your domains modeled properly, this seems like an easy fix with Integration Events.
Add an EmployeeIds table to your Departments Service and a DepartmentIds table to your Employees service. When you make, break, or change an assignment between an Employee and a Department, publish a EmployeeDepartmentUpdated event that both services subscribe to. Then, each service can process the event and update their own data to keep in sync.
You do NOT want to start putting data into your gateway API, that's not what it's for (and it means that if you have multiple gateways to the same back-end services, only one will know that information).
Embrace Eventual Consistency and your microservices journey will be the better for it!
EDIT:
To your question about the impact of Events on performance and complexity, the answers are "no" and "yes."
First, no I would not expect event-sourcing to have a negative impact on system performance. In fact, their asynchronous nature makes event processing a separate concern from API responsiveness.
I'm sure there are ways to build a Service Oriented Architecture (SOA, of which microservices is essentially a subset) without a messaging plane, but in my experience having one is a fantastic way to let loosely-coupled communication happen.
Any direct calls between services - regardless of protocol (HTTP, gRPC, etc.) means tight coupling between those services. Endpoint names, arguments, etc. are all opportunities for breaking changes. When you use messaging, each service is responsible for emitting backward-compatible events and every other service can choose which events it cares about, subscribe to them, and never have any knowledge of whether the emitting service is running, dead, changed, etc.
To your second question, the answer is absolutely "yes" - event processing is additional complexity. However, it's part of the complexity you sign up for (and far from the worst of it) when you choose a microservices architecture style. Distributed authorization, keeping UI performant with multiple back-end calls organized between multiple services, fault tolerance and health/performance monitoring are all (at least in my experience) bigger challenges.
For the record, we use a hosted instance of RabbitMQ from CloudAMQP.com and it works great. Performance is good, they have lots of scalable packages to choose from, and we've had zero issues with performance or downtime. The latest RabbitMQ 3.8 release now includes OAuth as well so we are currently working to integrate our Authz flows with our message broker and will have a nice end-to-end security solution.
Each microservice sould have it own database, so the junction table has no sense because it's a relational solution.
You may consideer one of this two approaches, if the Empl_Dept is a Domain object you should put it in a third microsevice, if it isn't put the employees relation into department and vice-versa.
I hope it helps.
I am assuming, This many to many map is required in a third microservice. Then It's straightforward you create a map table between employee and department
If you have only those 2 microservices then you will have to add employee_department_map in one service and department_employee_map in second service.
While designing a microservice always consider that you can't change anything in another service (let's say if it's third party api)

Two processes reside in different AP servers and refer to a same boolean flag. (Spring, Java)

I am using Spring Framework to develop a web application. I have two services which are going to store some processed results into one table T in Database. The logic now is:
Service A
for all items:
result = func(item)
store result to Table T (with status = new)
is_running = False
Service B
for some items:
if is_running == False:
result = func(item)
store result to Table T (with status = new)
else:
store result to Table T (with status = inprogress)
The boolean flag is_running will be a field in Service A.
Since we have MicroService Architechture for the domain server, Service A and Service B may reside in different AP servers. How can I ensure Servie A and Service B refer to the same is_running?
Is it possible to use Spring's bean scope to achieve this?
Sprin is injection framework and itself does not have such functionality.
I'd re-write your question as following: how to implement cross-machine Boolean flag?
There are a lot of ways to do this. Te most straight forward ways are:
1. Via database. You can create table with single column and single line where you will store tor flag. You can even lock the table prior accessing it, so inter process communication will be guaranteed.
2. Use other tool that provides such functionality. For example I'd recommend you Haselcast. It is a java grid that among other features has atomic variables that share state among different processes and machines. BTW they have also a spring integration.
Short answer, No. Spring, is just a programming framework. It does nothing that Java inherently does't do. Cross process communication is one such thing. As suggested, you can store that is_running flag in some shared database and have both services access it before running their logic. There can still be race conditions and you need to consider your application's appetite for that. However, the logic might not just be that simple where you're not even checking what result is being stored with the given status. There must be some business logic around that, which would give you leverage with the synchronization logic to implement. The current logic mentioned will always depend on point in time value of is_running flag. Doesn't really look right.
Because we speak of microservices you are not allowed to share a database between them. One microservice should not depend/know/care about the other's technology stack. The state is owned by each microservice, it should not be accesed otherwise but through one's microservice API.
That being said you need a technology agnostic way of sharing that boolean flag between the two microservices. You can synchronously or asynchronously update the flag, that depends on your system's resilience requirements. You can use REST with JSON to hide the technology stack.
If you share a database you would loose the main benefits of the microservices architecture.
Global state is BAD for microservice architecture.
To solve your problem, both Service A and B should own their states (is_running) in its own database which is NOT shared with any other service.
Then expose that state via a simple API /serviceA/state and /serviceB/state. These endpoints should return the state (via JSON e.g.).
Each Service then should call the API of the other service(s) to check the state of that other service.

Cqrs + microservices architecture : how to get data from another service

I'm playing around with setting up a microservices / cqrs architecture for a personal project, and there's one point I don't understand in the "standard" setup.
By standard setup, I mean
https://www.ibm.com/developerworks/cloud/library/cl-build-app-using-microservices-and-cqrs-trs/index.html
Say I have an orders service and a pickup points service, and I have a command like "send order summary email".
How should the orders service get the data about the pickup point (eg opening hours etc) that it needs to send the email ? I see 4 possibilities, but there are surely others.
The command goes directly to the orders service, and then the orders service queries the pickup points service to get the data.
The command goes to the pickup points service, and then pickup points service publishes a new event for orders service with the needed information attached.
The command goes directly to the orders service, and the orders service then queries the read-only client-facing database.
Merge the 2 services... given that they have no other shared context, this would be a pity...
Thanks !
how to get data from another service
There are two use cases for this. In your specific case, what you are describing is somewhat akin to UI Composition; you are creating a view that pulls data from two different sources.
Key point #1: the data you are composing is stale -- by the time the email reaches its destination, the truth understood by the services may have changed anyway. Therefore, there is inherent in the requirements some flexibility about time.
Key point #2: In sending the email, you aren't changing the state of either service at all. You are just making a copy of some part of it. Reads are a safe operation.
Key point #3: Actually sending the email changes the "real world", not the services; it's an activity that can be performed concurrently with the service work.
So what this would normally look like is that one of your read models (probably that of the order service) will support a query that lists orders for which emails will be sent. Some process, running outside of the service, will periodically query that service for pending emails, query the required read models to compose the message, send it, and finally post a message to the input queue of the order service to share the information that the message was successfully sent. The order service would see that, and the read model gets updated to indicate that the message has already been sent.
You are describing a process of sending an order summary email to the customer after the order is completed.
In CQRS this is implemented with a Saga/Process manager.
The idea is that OrderSummaryEmailSaga subscribe to the OrderWasCompleted event; when such event is fired, the saga queries the Pickup service for the information it needs (most probable from a read-model) and then:
it builds+sends a complete SendOrderSummaryEmail command to the relevant aggregate from the orders service or
it calls an infrastructure service that, having all the data, it builds an email and send it to the customer
or a combination of the previous points, depending on how you want to manage this process
The details are specific to you case, like what domain services (building and formatting the email) or infrastructure services (actual sending of the email using sendmail or postfix or whatever) you need to build.

Is that possible to replay events via RabbitMQ with Axon 3

I have an application built with the framework Axon 3.
There are 2 instances (jvm)
The first one handles commands and notifies the second one with RabbitMQ to construct a read model database.
There is an event store for this application (MongoDB)
Now I want to build a third instance and Is that possible to replay all historic events of the first instance via RabbitMQ to construct the initial state of the third instance ? and how to configure it ?
I tried the doc Axons for an answer, it seems that I should use TrackingEventProcessor instead of the default one SubscribingEventProcessor, but it does not allow to use with SpringAMQPMessageSource (mentioned in the doc)
Axon has two modes: Tracking and Subscribing. Depending on the source of your events, you can chose either one or sometimes both styles.
AMQP is a specification for a message broker. Once a message is delivered, it is removed from the Queue it was placed on. Therefore, conceptually, it is impossible to replay those events, since they don't exist in the broker anymore.
If replays are important, make sure you use a messaging mechanism that stores the messages. In Axon, the EventStore does exactly that. For now, Axon only has the EmbeddedEventStore, but you could have an Event Store in the receiving node point to the same database as the sending node.
At the moment, at AxonIQ, we are working on an Event Store Server, that deals with this in a cleaner way (no need to share datasources between instances).

Categories