I want to use the many to one and other DB Relationship in micro-service architecture. In monolithic architecture we can create the entity relationship easily as they belongs to same project but in micro-service architecture how we can achieve the same.
Example:
There is one userDeatil service and other is productDetail service.Now there is third service called orderDetail and an order will have userID and ProductIDs associated with it. So how can we manage the relationship between 'user and order' and 'order and product'.
I have searched over net but didn't able to get the fair idea.There is another thread having same query but not having the clear answer. Link
In my opinion your case is about how you specify your services especially how you define the bounded context of each service !!
According to the situation above-mentioned I don't see any reason why the product service should know anythings about orders (even if it s just the order-id) and backwards. One more problem I see in this case: your services will not work if one service is not available (E.g when the product service it not online, your order service will not be able to work, because he needs the product details from the product service...).
I Think you should rethink the bounded contexts of your microservices. You should keep in mind:
ensure a loose coupling of the microservices
a microservice has always to work even other Microservices are not available (Resilience / Reliability).
The DDD (domain-driven-design) paradigm with its tools provides her a great help to assist you, during the definition process of your services, you encourage these qualities.
So, the following is JUST an idea (it s not a recommendation and you should review whether it matters for your business case) :
It seems like the "order" process is your core business domain. So you have to focus on it.
The user service (i hope you mean here the customer and not a user in terms of authentication/authorization) has only the responsibility to manage the customers, and may be their adresses, bank-Accountings etc.. It should not know anything about your orders or products.
The same is valid for the product service. It owns only data about products. It has no relation either to the customer nor to the order-service.
The order service by itself deals only with orders and should own only data that belong to an order (like ship Adress and some information about the product-items ordered). I think the customer-Id is also important here to keep the relation between the order and the customer. This way you can e.g get all orders made by a certain customer-id....
Related
Let’s assume I’m in the context of an admin panel for a webshop. I have a list of orders. Those orders are payed for and are ready to ship. The (admin) user would like to start making shipments based on the items ordered.
Imagine there are 2 microservices. One for orders and one for shipments. In order to create a shipment, i will send a request with a couple of items to be shipped and an order ID to the shipment service. The shipment service will then check whether the items are present in the order by querying the order service. Because i don’t want to create a shipment with items that are not present in the order.
I’d like to have immediate consistency because the shipment data will be send to a third-party application after creation. Thereby it also feels weird to allow shipments to be created if the data is not correct.
I’m also using GraphQL mutations. Which means i have to return the updated state to the user, which also makes eventual consistency a lot harder.
What is the recommended approach for these situations? Could this be a sign that these 2 microservices need to be merged? I can imagine this situation can occur multiple times.
I appreciate a straight forward answer.
Scenario 1: I need to display product information.
Product Service (PS) : Holds information about products
Pricing Service (XS) : Holds pricing information of each product
Aggregator service (AS) : Combines both product info and price.
Question: 'AS' make a call to 'PS'(With product ID) to get product info. Now, how does 'AS' fetch that specific product price, from the 'XS'?
The confusion here is, does PS Table have a DB column with ID to corresponding price in XS Table? Can we call it a foreign key? If so, does it introduce tight coupling between two services? Which is against principles of micro services.
Well you may call that field as a "foreign key" but as long as you don't enforce any constraint on it then it should be fine.
From my view it is just a reference. It doesn't bring any tight coupling it provides some binding. Which is totally fine as far as microservices architecture concerned. If you think about a little bit broader in terms of possible implementation you may see that for example you can use a totally different database like relational one for pricing service and maybe
a document database for product service. And in that case it would be more clear that what you called as "foreign key" is just the reference for the actual record.
Having said that I may still question your solution like
Why do you need a separate Aggregator service instead of directly using Product service?
And same way why do you want to have a separate Pricing Service
Would it be better if you keep the reference to product on pricing service than keeping the reference to price on product service?
But anyway foreign key part is just fine from my point of view.
Let's say I have an application where I use multiple microservices. Two of them are USERS ( /users ) and CARS ( /cars ).
Given a page called rental history ( /users/{id}/history ) which lists the rented car of the users.
Should I introduce an intermediary microservice RENTAL ( /rental ) which would query the other two microservices for the best architectural design ?
What is the correct design if I wanted to deploy this app under different brands, which means USERS database would be different , but the CARS database would be shared between the application ?
I would strongly suggest that you have a rental microservice to coordinate the process of renting (and returning etc.) a car by a user. Then the logic only appears in the rental service, not spread out over however many other services (counting UIs and such as services for this purpose).
I would actually question whether different brands would need fully-different user services, because there'd be a lot of common functionality. It might make sense to have a general user service with brand namespaces user IDs (so that, for instance, the rental service doesn't need to know about brands) and some brand-specific facades (e.g. to add the namespace to the IDs and maybe even handle things like frequent renter programs).
Suppose we have two microservices, Customers and Orders, with no dependencies between them, i.e. they don't call each other, they don't know each other. Every order, though, has a reference to a customer by means of a customer id. In other words one customer may have zero or more orders, and one order belongs to exactly one customer.
For the sake of the example, it's totally fine to delete a customer unless there are orders belonging to that customer. What is the most appropriate way to implement a constraint on Customers that prevents a customer from being deleted if one or more orders have a reference to that customer? Analogous to referential integrity in a relational database.
These are the approaches I can think of:
Let Customers ask Orders if a given customer has any orders, e.g. via API call.
Let Customers keep track of which orders are assigned to every customer, e.g. by having each customer record maintain a list of order ids.
Merge Customers and Orders into a single microservice and manage it internally.
I'm not sure which approach is the best for the given example in a microservices context. I can see pros and cons in all three approaches but I won't list them here because I'd like to hear other people's thoughts on the problem, including approaches not listed above. Thanks.
Probably the second approach would help if you're going to decouple through events, either tracking a list of ids or a counter just telling how many orders are stored for such a Customer.
On the Order microservice you will emit an event when there is a creation/deletion that will be captured by the Customer (or any other microservice interested) who will take care of updating the list of order ids (or increment/reduce the counter).
If customer order counter is 0 then you may delete the customer.
Let's start with your third approach: This will not work in a Microservice world, because you will always have those constraints between some Services. And if you want to solve all of them this way, you'll end up with a Monolith - and that's the end of your Microservice story.
The first and second approach have both the same "problem": These are async operations, that may return false positive (or false negative) results: It's possible to make api requests for delete customer and create order (or delete order) at the same time.
Though this can happen:
For your first approach: Customer Service asks Order Service if there are any Orders for this Customer. Order Service returns 0. And at the same time Order Service creates a new Order for that Customer in another thread. So you end up with a deleted Customer and still created an Order.
The same applies for your second approach: The messaging between those services is async. Though it's possible that Customer Service knows of 0 Orders, and permits the delete. But at the same time the Order Service creates a new Order for this Customer. And the OrderCreated message will hit the Customer Service after the Customer has already been deleted.
If you try to do it the other way around, you'll end up with the same situation: Your Order Service could listen to CustomerDeleted messages, and then disallow creating new Orders for this Customer. But again: This message can arrive while there are still Orders in the database for this Customer.
Of course this is very unlikely to happen, but it still is possible and you cannot prevent it in an async Microservice world without transactions (which of course you want to avoid).
You should better ask yourself: How should the system handle Orders where the corresponding Customer has been deleted?
The answer to this question is most likely dependent on your business rules. For example: If the Order Service receives a CustomerDeleted message, it may be okay to simply delete all Orders from this Customer. Or maybe the behavior depends on the Order's state property: It's okay to delete all Orders with state = draft, but every other Order from this Customer should still be processed and shipped as usual.
In the context of a Microservice architecture, a single business operation can require collaboration between two or more services.
Suppose we have an Order Management Service and a Product Catalog Service.
When the user adds an order item to an order, the Order Management Service will persist a OrderItem object which have the following attributes among many others :
OrderItem
+ Id
+ ProductId
+ ProductName
In order for the Order Management Service to fill the ProductName attribute, we have 4 choices as I see it :
Choice 1 : ProductName is given by the client app as it probably already has this data from previous requests
Choice 2 : If the architecture uses an Api Gateway, the gateway will be responsible for retrieving the ProductName from the Product Catalog Service then provide it to the Order Management Service.
Choice 3 : The Order Management Service will call directly the Product Catalog Service and asks him for the ProductName givent a product id.
Choice 4 : The Order Management Service has a duplicate (but not exhaustive) product informations in its own database and these datas will be updated each time an update event is received from the Product Catalog Service.
Among these 4 choices, the n°1 seems not ok to me as we can't trust the client to give us a correct and updated value of ProductName.
I would like to have your opinion about what you think the best choice is and why !
Thanks !
Riana
Choice 1 : ProductName is given by the client app as it probably already has this data from previous requests
Like you said, it is not the best idea because the client may have stale information. Maybe acceptable if the product information changes infrequently and/or you have a secondary verification at order processing.
Choice 2 : If the architecture uses an Api Gateway, the gateway will be responsible for retrieving the ProductName from the Product Catalog Service then provide it to the Order Management Service.
IMHO, this is not a good idea. By doing so your domain/business logic will leak into the API Gateway. The gateway now knows the relationship between Orders and Products. This API gateway configuration/scripting will need to be maintained and introduces additional coupling.
Choice 3 : The Order Management Service will call directly the Product Catalog Service and asks him for the ProductName givent a product id.
This is my preferred choice. Though I do not recommend "direct" synchronous calls. Perhaps a retrieval of the ProductName via a messaging mechanism (message queue, event bus). Chained synchronous calls will reduce the availability of your services. You can find more information at Microservice Messaging Pattern.
Choice 4 : The Order Management Service has a duplicate (but not exhaustive) product informations in its own database and these datas will be updated each time an update event is received from the Product Catalog Service.
Data duplication is generally frowned upon unless there is a really good reason for it. In this case I don't see any. Why bother splitting the databases into two for each of the services yet duplicate the data between them? Also, to have the data updated each time an update event is received indicates that some kind of event/messaging infrastructure is available, in that case, why not just use messaging?
This duplication may be justifiable for high volume, low latency look ups, but it is a slippery slope that may end up with duplicated data all over your services. Imagine the repercussions of a length or type/format change of the ProductName string...