Shaun Abram
Technology and Leadership Blog
Blog post summary: Domain-Oriented Microservice Architecture at Uber
“Domain-Oriented Microservice Architecture at Uber” is a blog post on the Uber engineering blog. There were some comments about the post not giving credit to prior art, which I think is fair, but it is a useful post none the less. Uber provide an interesting approach to classifying and organizing their (2,200!) microservices, by using the concepts of Domains, Layers, Gateways and Extensions.
This is a shortened version here (1,200 words, vs 3,800 in the original), since I tend to learn by creating summaries, but it is mostly just a copy & paste, so check out the original with diagrams etc if you’re really interested.
Contents
Introduction
Microservice architectures have numerous benefits such as independent deployments, clear ownership, and better separation of concerns. However they can also greatly increase complexity, sometimes making even trivial features difficult to build.
With around 2,200 microservices, Uber has attempted to reduce microservice complexity while still maintaining the benefits of a microservice architecture. They do this through their generalized approach to microservice architectures: “Domain-Oriented Microservice Architecture” (DOMA), which provides a way to reduce overall system complexity while maintaining the flexibility associated with microservice.
What is a microservice?
Microservices are an extension of service oriented architectures. Microservices are applications that
- Represent a set of narrowly scoped functionality.
- Are hosted and available over the network
- Expose a well-defined interface called via RPC (you can think of a microservice as a library with a network related performance hit)
So why adopt a microservice architecture at all? Independent deployments and scaling. In other words, organizations adopt microservices for an operational benefit at the expense of performance.
Motivations
Monolithic services can have many of the operational issues:
- Availability. A single regression in a monolith can bring the whole system down.
- Risky, expensive, painful deployments.
- Poor separation of concerns. Expediency can lead to poor boundaries between logic and components.
Microservices can bring these advantages:
- Reliability. A single service can go down (and be rolled back) without taking down the whole system.’
- Separation of concerns. More clearly defined roles of different components.
- Clear Ownership.
- Autonomous execution. Independent deployments + clearer lines of ownership
- Developer Velocity. Teams can deploy their code independently
However, microservices can bring greatly increased system complexity. You trade a single monolithic code base for black boxes whose functionality can change at any time and easily cause unexpected behavior. Understanding dependencies between services can become quite difficult too. The clear lines of service ownership can be compromised as teams build code within each other’s services, modify each other’s data models, and even perform deployments on behalf of service owners. Networked monoliths can form.
Domain-Oriented Microservice Architecture
The core principles and terminology associated with DOMA are as follows:
- Domains
Instead of orienting around single microservices, we oriented around collections of related microservices, called domains. - Layers
We further create collections of domains which we call layers. The layer that the domain belongs to establishes what dependencies the microservices within that domain are allowed to take on. - Gateways
We provide clean interfaces for domains that we treat as a single point of entry into the collection. We call these gateways. - Extensions
Each domain should be agnostic to other domains. Since frequently teams do need to include logic in another team’s domain (for example, custom validation logic or some meta context on a data model), we provide an extension architecture to support well defined extension points within the domain.
In other words, by providing a systematic architecture, domain gateways, and predefined extension points, DOMA intends to transform microservice architectures from something complex to something comprehensible: a structured set of flexible, reusable, and layered components.
Uber’s Implementation
Domains
Uber domains represent a collection of one or more microservices tied to a logical grouping of functionality. This could be a single or dozens of services. The important task is to think carefully about the logical role of each collection. e.g. map search services, fare services, matching serices.
Layer Design
What service can call what other service? You can think of layer design as “separation of concerns at scale”, or “dependency management at scale.”
Uber established the following five layers.
- Infrastructure layer. Functionality that any engineering organization could use. e.g. storage or networking.
- Business layer. Functionality that Uber as an organization could use, but that is not specific to a particular product e.g. Rides, Eats, or Freight.
- Product layer. Functionality that relates to a particular product category, but is agnostic to the mobile application, such as the “request a ride” logic which is leveraged by multiple Rides facing applications.
- Presentation. Functionality that directly relates to features in a consumer-facing application (mobile/web).
- Edge Layer. Safely exposes Uber services to the outside world. This layer is also mobile application aware.
Each subsequent layer represents an increasingly specific grouping of functionality, and has a smaller and smaller blast radius.
Gateways
A gateway is a single entry-point into a domain i.e. a collection of underlying services. It abstracts away the internal details of the domains – multiple services, data tables, ETL pipelines etc. Only the interfaces – RPC APIs, messaging events and queries are exposed to other domains. Since upstream consumers only operate on a single service, gateways provide numerous benefits in terms of future migrations, discoverability, and overall reduction in system complexity. In the sense of OO design, they are interface definitions.
Extensions
A mechanism to extend domains i.e. extend the functionality of an underlying service without changing the actual implementation. Uber has two different extension models: logic extensions and data extensions.
Logic extensions provide a mechanism for extending the underlying logic of a service, like a provider or plugin pattern.
Data extensions provide a mechanism for attaching arbitrary data to an interface to avoid bloat in core platform data models.
Benefits
Almost every major domain at Uber has been influenced on some level by DOMA. and early signs have been extremely positive in terms of a simplified developer experience and a reduction in overall system complexity.
- Products & Platforms: Platform support costs often dropped an order of magnitude. Product teams benefited from guard rails and accelerated development.
- Reduced Complexity: We were able to classify 2200 microservices into 70 domains. Previously product teams would have to call numerous downstream services to leverage a domain; they now have to call just one.
- Future Migrations: Ever changing microservices constantly require upstream migrations. Gateways enable teams to avoid dependencies on the underlying domain services, which means those services can change without forcing an upstream migration.
Practical Advice
Startups
In small organizations, the operational benefit likely does not offset the increase in architectural complexity of microservices. Furthermore, microservice architectures often require dedicated engineering resources to support which may be out of budget.
Midsize
Once a company becomes midsized with multiple teams and the clear separation of concerns becomes hazy between different features and platforms, microservice architectures become more obviously useful.
There is the possibility to avoid tech debt here if one can create completely product agnostic business platforms and avoid arbitrary product logic in core platform services. It might make sense to adopt extensions at this point to accomplish that goal.
It’s worth noting here that a domain )in the context of Uber’s DOMA implementation) can contain a single service, so it may still be useful to think in a “domain-oriented” way.
Large
There will likely be obvious clusters of microservices that can be easily grouped together into domains with a gateway in front of them.
Clear hierarchy will also become increasingly important with some services operating as “product” services for particular features or grouping of features, and other services will increasingly support multiple products and be thought of as “platforms.” It’s critical at this stage to keep arbitrary product logic decoupled from platforms.
Tags: microservices, summary, uber