Data Design and Microservices
As companies move to a microservices architecture a few areas of data design need to be considered, they are: data sovereignty and database complexity including use of foreign keys and joins. Data sovereignty and its implications on your microservices architecture is sometimes a contentious topic that comes up during the design phase. One of the rules or at least strong guidelines for microservices design is that each microservice owns its domain data and its logic. The services should be loosely coupled - a change in one service does not require a change to another service — and highly cohesive — services that perform a similar function reside together and services that meet a different functional requirement reside elsewhere. Related to loose coupling is data sovereignty, which is a difficult concept to grasp when you are used to dealing with large monolithic systems that have one large data store with foreign key constraints.
Data Sovereignty
Data sovereignty is a design choice where each microservice or a set of services that are highly cohesive own their own database - these is not one large dB as there typically is with a monolithic system and the loss of a “single source of truth” has to be addressed. This is a more difficult design to implement because you have data split across databases, communications costs have to be managed, sometimes a single ACID transaction can not be made across databases (eventual consistency needs to be considered).
Foreign Keys & SQL Joins
Foreign keys are another consideration when building out microservices. FK are usually a given in monolithic systems but this is not necessarily so with microservices. I want to be clear here, you definitely can use FK with microservices but its not always a default decision. SQL joins are another area of complexity when using a RDBMS, they are a powerful tool but can be difficult to debug and scale. Microservice teams have often opted to limit SQL joins in favor of a caching mechanism to offload work from the dB.
If you are reading this you already know what foreign keys and a SQL joins are and why they are used so the question is why would you not always employ them with microservices? When teams are very small and operating without a dedicated database staff, simplicity of logical/physical database design is often a priority so constraints are moved out of the dB layer. As discussed above, designing for data sovereignty means encapsulated data and microservices tends to operate with small more nimble teams often times without a full-time traditional DBA role. Scalability is another reason to move away from a more complex dB designs. The dB layer can be the most difficult area to scale so making this less complex and moving the workload to a caching tool is another design option. To improve dB simplicity, ease maintenance, improve performance and scalability, and to lighten the dB load you can do key-value lookups using an in memory data store. An early choice for this was Memcached and remains a viable option for ease of use but Redis seems the better option these days. Redis is feature rich and it’s part of the portfolio in Amazon Web Services and Microsoft Azure making it an easy choice for most cloud deployments. I have seen benchmarks where caching can improve performance time of key-value lookups from from O(n) to O(1).
A microservices architecture does not prevent you from using the dB as you would with a monolithic system; if you do just make sure you have a strong dB staff on the team however if you are making the move to to microservices you should consider all options.