I've just started separating my projects out into little microservices. I have a microservice which deals with API authorization (checks if an apiKey provided in an API request is valid) and so for this, I have a separate DB for the API Authorization which has the following tables with the following schema:
APIKey:
ApiKey (VARCHAR, PK)
TenantID (INT, FK)
Tenant:
TenantID (INT, PK)
Name (VARCHAR)
As you can see the APIKey table is linked to the Tenant table.
I have another microservice, this microservice deals with storing errors for tenants and so requires reference to the tenant table, but because the Tenant table is in a separate DB, we can't actually use it.
I thought about creating a Tenant service and having a DB just for Tenants but this would cause data integrity issues on other microservices which require some reference to a Tenant so I'm not sure what I should do.
Can anyone suggest what should be done?
The microservice for tenant errors seems to be a nano service. It sounds like you're actually using it for monitoring. There are more monitoring solutions out there such as Splunk and ELK that can do more generic logging. If you have other microservices, they can also log the errors to them.
If you used a monitoring solution, you wouldn't need a tenant error microservice and you also wouldn't need a tenant microservice as you suggested. If you wanted to continue down the path of having individual services though, you could publish the error events and tenant events to a queue from the API authorization service to the tenant microservice or tenant error service. So you will have replicated data and will need to strategize keeping the data consistent.
Arguably, this leads more complexity due to how you decided to split it into those respective microservices. On the other hand, a shared architecture would solve your problem but at the same time, couples your architecture. The reason microservices exist is to essentially to move away from coupling so I would recommend going back to evaluate whether that decision on defining those bounds for the services and see what you can join together to either eliminate or minimize the complexity.
Related
i'm trying to learn Microservices by implementing a sample project, tried to pick a semi-complex one to face real world challenges in Microservice architecture.
this is a simplified version of the project flow that I designed till here:
the flow
as you can see in the image I'm trying to get the list of appointments for a specific company, but since the required data is inside different Microservices, for getting the appointments I have to follow these steps:
the API gateway (bff) will get the request from frontend that contains a token
bff will authorize the jwt token by sending it to the users ms
appointments are separated by companies ids, so before getting the appointments, I need to get the user company
company id will be sent to appointments to get the appointments for the company
appointments will check to see if actor is authorized to get the list of appointments by its role (came earlier from the user ms)
appointments will return the list of appointments
inside appointments as you can see in the entities, I do have the id of both sides (sideA, sideB)
bff will get those users details by the ids from users
inside appointments data that is returned, there is a customer_id that is the id of a customer inside the company ms so bff send another request to the company to get the customer details
inside customer details, there is an id of a project that the customer is eager to visit so, bff will send a request to get the project from the projects ms
at the end, bff will join the data and return it to the frontend application.
this is also the simplified version of entities inside Microservices:
entities
right now, i'm using composition API approach to get the data I need, but as you can see the flow is complicated, and I can't think of a way to implement pagination, since I might need to sort, filter and then paginate the data, so I think in this situation, this might be a good idea to use CQRS pattern, but the problem is since I have many situations like this, I have to implement lots of CQRS services.
I'm wondering if:
is it possible to create a single CQRS service to have all the data for read purpose, instead of CQRS for each situation?
for some situations like this, the CQRS read database will becomes almost identical to a monolith architecture db. is. this okay?!
is there any alternative way to scape the complexity of creating and managing multiple CQRSs with partial repetitive data?
CQRS will help you get all the required details in one call. A CQRS service will have multiple tables that are part of different microservices.
An example will be like "OrderViewService" will require to listen and store events from "OrderService", "DeliveryService", "AccountingService". But it wont be listening to multiple other services which are not of concern for "OrderViewService".
So the point I am making here is the database won't become so similar to the monolithic database as it would have a lot more details.
For your project you might require a single CQRS that may deliver your requirements.
As it seems your requirements have dependency on all of the microservices and so a single CQRS service could help you solve the requirements.
Also if you are concerned about the space make sure what details would be required were only be saved to the view/read CQRS database. Thereby ensuring that we are not overwhelming the db with all the details from all the services.
As application grows there can be multiple CQRS services listening to different services or a combination of services and thereby serving their responsibilities.
Reference - https://microservices.io/patterns/data/cqrs.html
I think this explains and these are my thoughts about CQRS. Let me know if you have any questions post it as comments.
I started reading microservices architecture and got confused with one below point.
Each service should have a separate database.
Does each service mean a single web(rest) api having its own database?
For example if I take motor insurance claim operation as a business scenario where I modelled business domain services in 3 part Insurance claim services , partner (automobile service providers) services and customer services.
Insurance claim settlement operation in claim api will require other information like incident , survey done by an inspector, policy detail , documents etc.
Now I can create 5 web(rest) api in Insurance claim services and will store its data in common db and other services like partner and customer service will have their own web apis and db
What is correct ?
All web api (claimAPI, PolicyAPI, IncidentAPI, SurveyAPI and DocumentAPI) in claim insurance services should have their own db or they can keep data in single data base ?
Thanks.
To follow microservice best practice, it is correct that they should each have their own database and be exposed solely by APIs. This is because every service in your architecture should be independent and de-coupled from other services. If 2+ services share a database, then there may arise problems in operation or upgrade.
One big issue with a shared database is each service would need to trust that another service doesn't modify it's information. But since they all have access to the same database, one of the others could in fact modify the underlying data and make things unstable or insecure.
Further, with 2+ services relying on a shared database, then you're forced to use the exact same database/version with all. You lose the freedom to independently use MySQL for one and MongoDB for another. Even if the same tool is used for all, when you do maintenance or migration on one you're forced to do it for the rest. All this adds up to some coupled services that make them harder to maintain and scale.
you can have common database for all microservices, it is one of the microservices patterns:
https://microservices.io/patterns/data/shared-database.html
https://docs.aws.amazon.com/prescriptive-guidance/latest/modernization-data-persistence/shared-database.html
check those links to see advantages and disadvantages of this approach.
I am new to microservices and trying to break up a big monolithic application into microservices. While scoping the microservice I am unable to decide whether I should go for a data duplication between services or ignore SRP by clubbing all requiring the same data into 1 service. Following is the scenario.
I have a service which receives Customer order say build a car with these parts and features. Now I have other 2 functionalities which uses the Parts and features to derive some runtime value say ;
If the order contains part A and Feature A then perform X operation. As each of these functionalities have there respective UI for configuration and runtime engine to derive the output and most of the time changes only comes in these respective function blocks, I thought of creating the separate microservices.
Creating the separate microservice would need data(Parts and Features) to be duplicated. Another option could be given each of these service uses the same data is clubbing all of them into 1, but with that I again create a big service which if goes down will stop all 3 functionalities and is against SRP. Another option could be when the data is required by the other 2 services make a call and get it from Order Service, but that is making it highly dependent and getting the data over network for each operation.
Can anyone suggest what would be ideal to do in such case.
Microservice should communicate via events using publisher/subscriber model and topics. See the tri-lateral design pattern. In a pub/sub system the producer writes the event to the topic and a broker makes it available to each subscriber, aka microservice. This is one advantage of eventing, one producer, and many consumers.
Order A has a BOM that expresses parts and features an order represents. When the order is placed, other services need that information such as the feature/part microservice and UI components and their respective datastores. For example, define two topics parts-ordered and features-ordered.
The order microservice writes to the parts and features topics respectively. The feature, parts, and UX microservices read and act upon those events.
You need to make a choice about your system of record. You can write to an orders DB before publishing the events, or let the pub/sub it. In your example, it sounds like you are talking about three different tables; order, parts, and events. That decomposes cleaning into the microservices you describe where each maintains the data it is responsible for. I'd be inclined to just use the pub/sub as your audit trail.
If you are writing in Go we have blueprints for the most common design patterns.
First, you mentioned that you are trying to convert the monolithic application into microservices. You can create/caters the microservices on basis of domain data, we can be called it domain-driven architecture.
Suppose you have the business functionality for customer data, customer order, customer order handling, and customer payment. And currently, it's part of a monolithic application. So you can create the subdomain for each functionality like Customer domain, Order domain, order handle domain, and payment domain respectively. Each domain contains several microservices depends on the business requirement.
For e.g you can check the Amazon website, In personal/customer data, you see the customer name, phone number, address, billing account information, delivery address type(office/home). In this case the under customer domain, there will be 3 microservices required(It totally depends on your domain design). One for customer(handles customer name, phone number, reference of Billing account id, reference of address id), second for Billing account(Billing account number, billing account information, reference if customer id), third for Address data(customer office address, preferable address). And for each microservice, there will be a dedicated database/buckets, Only that microservice can change/add the data. If any other microservice wants to add/update/get data, it needs to be get by calling that microservices HTTP endpoint over the network.
Updating the data in other microservice::
Now coming to your question about data duplication, Let's consider the above example.
If Customer microservice wants to store/ cache the billing account data for some purpose, that microservice can store that data in the database but again Customer microservice needs to make sure that, the current data of the billing account is always real one and not the old one. For this customer, microservice needs to listen to the event whenever there is update in billing account data, so old data in billing account gets purged and customer microservice always has the latest data of billing.
you can read here about event driven architecture.
https://en.wikipedia.org/wiki/Event-driven_architecture#:~:text=Event%2Ddriven%20architecture%20(EDA),sale%22%20to%20%22sold%22.
You can read more about this at the below links about Domain driven design.
https://www.thoughtworks.com/insights/blog/domain-driven-design-services-architecture
https://en.wikipedia.org/wiki/Domain-driven_design
This is my free book :)
https://github.com/vaquarkhan/microservices-recipes-a-free-gitbook
If you want to create microservice then need to follow microservice guideline.
Now come to real world :) really difficult to meet all microservice requirements as database has own licensing cost etc. so you can choose pragmatic microservices. You can get started with them faster and pick and choose the pieces that make sense for your team.
Design Domain driven design oriented microservice : DDD talks about problems as domains. It describes independent problem areas as Bounded Contexts and each Bounded Context correlates to a microservice.
Where to draw the boundaries is the key task when designing and defining a microservice.
DDD patterns help you understand the complexity in the domain, the domain model for each Bounded Context, you identify and define the entities, value objects, and aggregates that model your domain. You build and refine a domain model that is contained within a boundary that defines your context. And that is explicit in the form of a microservice. The components within those boundaries end up being your microservices.
https://martinfowler.com/bliki/AnemicDomainModel.html
https://github.com/vaquarkhan/Domain-driven-design
https://github.com/vaquarkhan/ddd-by-examples.github.io/blob/master/ddd-factory.pdf
Now you can create layers on top of you microservice and build complex logic using orchestration and choreography.
Example :
Gateway Customer order Application layer microservice --domain model layer microservice infrastructure layer
There are various ways to decompose an application into services.
1.Decompose by business capability
2.Decompose by subdomain
And there are various ways for data management also
SAGA
API Composition
Database per service
Please go through with the link for more details click
Suppose that I have a microservice for messaging. The microservice knows how to send emails. The service have templates of emails that have some sort of "template engine" like pugjs, and can replace data in the body of the message.
I have an user service (used for authentication/authorization for example), and a bank account service (each user have one). Between the User microservice and Bank Account microservice it's clear that we don't have to duplicate any data than de user's uuid.
But I want now to send every day a message to each user with their account statement. The Messaging microservice needs data from the User microservice and the Bank Account microservice.
Okay... This is a small case of the real world. Now I know that to have the benefits of decoupled microservices I must follow some rules:
I can't share databases between microservices
I can't make synchronous requests between microservices
Okay... I can use a broker and each time a new user is created/updated the Messaging microservice can store that data. But really, this is a stupid thing:
I don't want to have inconsistency with this data, and keeping things sync is hard
The development time and complexity of the Messaging Microservice must now consider: listen and extract the relevant data from events, keep data consistent about other domains/services, managing the saved data on database
And think about a Messaging microservice. Really I must store all the data needed to parse the templates?
I read a lot about microservices and people creating rules for their simple examples. But I never really saw a good explanation and real-world examples like above.
So how to have the microservices above without data duplication?
In your domain example I would not let the message service know anything about bank or user details. Instead the message service should just receive instructions to send messages to recipients along with the given content. I would use a dedicated scheduled job (maybe implemented as an account notification service) that performs the work of acquiring the user and account data from the corresponding services, compiles the information for the message service and instructs it to actually send the messages. This introduces another "higher level, business purpose entity/service" but allows you to keep a clear separation of concerns.
In general it will happen frequently that your "basic" domain services are used by another service that represents a specific business purpose and requires their data. Dependency in itself is not a bad thing as long as concerns are seperated clearly and interfaces versioned, changes communicated etc.
Don't forget the whole idea of microservices is for allowing teams to have dedicated responsibilities with clear interfacing. It is about organization as much as it is about architecture.
I know that Spring Security has a lot of role-based authorization capability. But what if I have two ordinary users accessing data. How do I keep User A from seeing records belonging to User B? For example, keeping User A from seeing the orders created by all other users?
Please note that this is NOT role-based authorization. User A and User B, etc., are all ordinary users, differing only in their identities.
In an existing Spring application I'm currently getting the job done with a filter in each DAO, ensuring that "... and user_id = $1 ..." is part of the queries. This also reduces the volume of fetched data, lowering database access costs.
In the future I will be breaking up my application into microservices. It seems to me that each microservice request must also have the UserDetails information. This sounds like an anti-pattern.
An API gateway would merely be a consumer of the approaches that I previously mentioned. So, is passing the UserDetails information to each microservice my best approach?
I hope the answer is not "create a role for each ordinary user, like "ROLE_USER_A", "ROLE_USER_B", etc.
Thanks,
Jerome.
In an existing Spring application I'm currently getting the job done
with a filter in each DAO, ensuring that "... and user_id = $1 ..." is
part of the queries. This also reduces the volume of fetched data,
lowering database access costs.
This is the correct approach
In the future I will be breaking up my application into microservices. It seems
to me that each microservice request must also have the UserDetails
information. This sounds like an anti-pattern.
There are several approaches you an use here. You could use spring security oauth, and separate the authentication server out into it's own component. Then the credentials will be stored in a central location. This will save you from having to pass the credentials around.
Another approach would be using perimeter security. Basically your gateway service would authenticate each request and then pass the user details to each component.
There are other approaches, but these two are pretty common.