Microservices should be designed in such a way that a single service is usually the only thing that reads or writes to a particular data store. In this model, services have full ownership over the domain models involved in the business capability they provide. Having clean boundaries makes it easier to think about the life cycle of data in a system. Some models in our system will change frequently, but many will be read much more often than they are written. In these cases, we can use a cache to store infrequently changed data, saving us from having to make a request to the database every time the object is requested. Database queries are typically more expensive than cache lookups, so it's ideal to use a cache whenever possible.
In addition to help improve performance, having an effective caching layer can help improve the reliability of a service. It's impossible to guarantee 100% availability for a database, so in the event of a database failure, a service can revert to serving cached data. In most cases, it's preferable for a user to receive some data, even if it's old and potentially out of date, than to receive no data at all. Having a cache layer allows you to configure your service to use it as another source of available data to serve to users of your service.
In this recipe, we'll create a simple example service that serves information about users of your application. It will have two endpoints, the first will accept POST requests and will persist a properly formed user to a database. The second will retrieve a user representation by the ID specified. IDs are stored as UUIDs, which is preferable to autoincrementing IDs for many reasons, which we'll go into in later chapters. We'll start with the basic service, then add caching so we can see specifically what steps are required. In this recipe, we'll use Redis, a popular open source in-memory data-structure store that is particular useful for storing key-value pairs.