There are no microservices, argued cloud pioneer Chris Richardson, perhaps trolling his audience a bit at the Oracle DevCon held in New York earlier this year. Instead, he insisted, you should think of a collection of microservices as a service architecture, he advised.
And to help system architects get a handle on microservices, Richardson is developing a pattern language that an offers templates for common use case scenarios.
Richardson is widely recognized as a thought leader in service architectures, having been a Java champion for many years. He was the founder of the original CloudFoundry.com, an early Java platform-as-a-service for Amazon EC2 that was acquired by SpringSource. SpringSource, itself soon was purchased by VMware, which later went on to use the Cloud Foundry name for the open source enterprise platform service that everyone knows today. He wrote the book “POJOs in Action,” which describes how to build enterprise Java applications with frameworks. And Richardson’s next book, Microservice Patterns, is due out later this year. He currently provides microservices consulting and training and runs Eventuate.io, which offers an application platform for “creating an open-source/SaaS platform that simplifies the development of transactional microservices.”
In his talk, Richardson described microservices architecture as one “that structures an application as set of loosely coupled services organized around business capabilities.” Microservices architecture maps technical capabilities into those services, he said, so it’s really a services architecture, not “microservices.” That settled, he said the primary goal of this new architecture is to “accelerate the velocity of software development by tackling complexity.”
But a microservices architecture creates its own complexity, so Richardson has created a pattern language to help address those challenges. This pattern language can be used as a guide to decide if you want to move into microservices architecture, said Richardson. And once implemented, it can help solve the various problems that come with that decision.
Drawbacks are often ignored when looking for solutions, he explained, and the pattern language forces you to define them.
So what is a pattern? According to Richardson, it’s “a reusable solution to a problem occurring in a particular context.” It’s the particular context that is important, he explained. “You don’t just blindly apply the same solution over and over again.”
Richardson broke down a Pattern into seven characteristics:
- a name, which makes it easy to refer to,
- a context also known as the solution,
- a problem that you are trying to solve,
- forces, which are issues or conflicts to address,
- a solution which is described,
- a resulting context, when is this pattern applied,
- and lastly, related patterns
Related patterns can offer an alternative solution to the defined problem or a separate pattern format that requires you to consider alternatives, he said.
Drawbacks are often ignored when looking for solutions, he explained, and the pattern language forces you to define them. “When you apply this pattern, here are the issues that will come up, and here are the related patterns that will solve those problems,” he said.
That drives the structure of the pattern language, he explained. In addition to describing the benefits, it requires you to describe the drawbacks and forces you to describe the issues you have to address.
The main purpose of a pattern is to simplify processes made complex by the distributed architecture of microservices. You need a set of discovery patterns, for instance, because you have to know the network location of other services. There are public interface patterns, API gateway patterns, and deployment patterns, all to help with those processes.
A set of observability patterns help requests can hop from one service to another, troubleshooting patterns help with distributed tracing and log aggregation. Testing patterns provide testing services in isolation so testing simple fast and reliable.
It All Comes Back to the Data
The key challenge in microservices architecture is how to manage distributed data. Since data is broken up by business services, each with its own database queries that used to be simple can now be really complicated.
Using an online store as an example, Richardson showed a case where the order data is siloed from the customer data, which are held in separate databases and possibly on different servers or containers. Given there is no direct access to each other’s data, the two data sources only communicate through APIs.
This creates interesting problems, said Richardson, especially in regards to transactions. Transactions are used to maintain data consistency and enforce business rules. In an on-line store, when an order is placed, the order system needs to verify customer credit limit, but the data is in a separate database, possible on a separate server or container.
In order to address this problem, the pattern language contains an eventually consistent approach called sagas.
So instead of a series of transactions spanning multiple services, a saga creates a sequence of local transactions where each step of the saga emits an event or emits a message that triggers the next step of the process. By using a sequence of transactions the data will eventually become consistent, he said.
Richardson broke down how this works in the store: An order comes in and is created without any validation. An event is created indicating “I’ve created an order” that would get processed by customer service, which would reserve credit in the customer, then emit an event indicating the outcome of that credit reservation. Either it would be a credit reserved event or a credit failed event, either of which would get consumed by the order service that would then either approve or reject the order.
Executing queries, which are simple enough to execute in a monolithic system, become much more complex in a microservices structure, he noted. The solution, according to Richardson, is Command Query Responsibility Segregation (CQRS) that uses the stream of events that is coming out of your business logic to keep the view up to date.
“In a way, he said, “it’s using an Elastic search along a MySQL database to implement tech search queries, except that we’re using a generalization of that and we’re using events to keep it up-to-date in near real-time.”
Another complexity in using microservices architecture is how to how to reliably update the database(s) and publish events. Richards has a solution for that as well: event sourcing. Event sourcing is a form of event-centric persistence.
“Each persist each domain object as a sequence of events so when an order is created, an order event is inserted into the event store, which makes it available for publishing, and then when the order is approves, we insert an event which also publishes it and then when it is shipped we insert an order shipped event,” he said.
This, he said, is the source of truth for domain objects in the system.