Peter Albanese
Peter Albanese

Reputation: 57

Microservices and duplicating database tables

I have been working on splitting up a monolithic system (.NET) into smaller bounded contexts and thus multiple class libraries. Address records are central to the system, so its important for the unrelated entities to reach back to a MASTER address record. Each microservice has its own database with tables related to that bounded context. I've run across a challenge with regard to Address records or the Address Entity. Both of these bounded contexts or libraries need the use of an Address table and the related lookup tables, such as State, Country, etc. Should I duplicate the Address related tables in each database and also duplicate the Address related domain classes? If I duplicate, I will have a ton of duplicate address records in both databases and this has me stuck. If I put the Address tables in something like a "Location Service", it will be difficult to display address fields in search results. Maybe this isn't the proper scenario for microservices?

EXAMPLE: Microservice-1 (product A) Incident -> one to one -> Address

Microservice-2 (product B) Fire Hydrant -> one to one -> Address

Microservice-3 (product C) Inspection -> many to one -> Address

Upvotes: 4

Views: 2054

Answers (2)

sschrass
sschrass

Reputation: 7166

For better illustration I assume REST APIs for each Microservice.

As I see it you have a IncidentService, a FireHydrantService and an InspectionService that all rely on the LocationService.

By following the Microservice approach, you have to be aware of two goals you want to achieve:

  • Loose coupling
  • Cohesive behavior

this implies that your services are not allowed to share a Database (it could be the same physically, but not logically), so that a service cannot modify the data of a different service or access its data directly by bypassing the responsible service. This has to be done by the responsible service through its API exclusively. Otherwise Cohesive behavior would be put at risk.

A RESTful API is great because we want to also couple loosely.

A Resource could look like this:

"incident": {
    "time": "...",
    "location" : {
        "name": "an arbitrary address"
        "href": "apis.yourdomain.com/locationservice/address/1"
        "type": "application/json"
    },
    "nearestHydrant": {
        "name": "hydrant 42"
        "href": "apis.yourdomain.com/firehydrantservice/hydrant/42"
        "type": "application/json"
    }
}

As you can see, those enitites (better its representations) are only represented as Link referencing (an entity in) the responsible service. This coupling is loose because a Link is less likely to change as a representation of a Entity throughout the lifetime of you application. By naming the field you also get the semantics of the relation between FireHydrant and Incident.

But things could get complicated very easily. Assume a rule like "A domain object can only be emitted by the responsible service" in order to maintain Cohesive behavior. This means that only the FireHydrantService is allowed to serve FireHydrant. Now imagine a request like "Incident at address 1". Which service should be queried for the nearest FireHydrant? Following the above rule, it should be the FireHydrantService. But how does the FireHydrantService know, it doesn't know what nearest means?

In such a case there is a thing called non-authoritative cache (which could also be persisted in a DB). This just means that the LocationService is allowed to store FireHydrant in a cache or in a database, but is not allowed to share them with others. This way the above rule is still followed and the Cohesive behavior still at hand. The non-authoritative cache does not need to reflect the full domain object FireHydrant, but everything necessary to fulfill the UseCases. So the IncidentService asks the FireHydrantService for the nearest FireHydrant(s), what gets delegated to the LocationService, that queries its non-authoritative cache for the nearest location with type FireHydrant, the response is a reference (Link) to the FireHydrantService itself, that checks if the FireHydrant has had its Inspection and therefore is valid according to business rules (if not it would check for the next) and return a reference (Link) to the IncidentService.

My rule of thumb is, that every service can be queried on every domain object, but can only serve the domain object it is responsible for. The "queried on domain objects" could live in the forementioned non-authoritative cache. This of course leads to duplication and the interesting part is to keep them in sync. A thing that instantly comes to mind is the use of Event Sourcing. A Service emits an Event "Hydrant 42 out of order" and the LocationService would remove Hydrant 42 from its cache.

Upvotes: 5

Abhijeet
Abhijeet

Reputation: 4309

As I'm from java background I don't know the libraries and bounded context related to .Net mentioned above. But I will try to answer this question in generic way. To solve this issue you can store address related tables in different database which can be accessed by all these three microservices.

As lookup tables for each microservice will have same tables/data, so you can use same lookup tables for all microservices. If your address table have different columns then you can store address for each microservice in different table else you can store data in same table by storing address_type for each microservice.

Upvotes: 0

Related Questions