Why Yoda never used microservices

Microservices were meant to be a boon, but for many, they are a burden. Some developers have walked away from them even after negative experiences. Operational complexity becomes a headache for this distributed, granular software model in production. Is it possible to solve the problems of microservices while retaining their advantages?

Microservices shorten the development cycle. Changing a monolithic code base is a complex matter that carries the risk of unexpected effects. It’s like unfolding a sweater so that you can change its design. Breaking that monolith into multiple smaller services managed by two-pizza teams can make it easier to develop, update, and fix software. It helped Amazon grow from a small ecommerce organization to the beast it is today.

Microservices also present new challenges. Their distributed nature exposes developers to complex state management issues.

Yoda Doctrine

Ideally, developers shouldn’t have to deal with state management at all. Instead, the platform should handle this as the main abstraction. Database transaction management is a good example; Many database platforms support atomic transactions, which split a single transaction into a set of smaller operations and ensure that either all of them happen, or none of them. To achieve this behavior the database uses transaction isolation, which restricts the visibility of each operation in a transaction until the entire transaction has completed. If an operation fails, the application using the database sees only a pre-transactional state, as if no operation occurred.

This enables the transactional developer to focus on their business logic while the database platform handles the underlying state. A database transaction doesn’t fail half-heartedly and then leave it to the developer to resolve what happened. For example, an account will not be debited without a credit to the related party’s account. As Yoda said: “Do it or don’t do it. Trying won’t work.” Appreciate the ACIDSQL database, he will have it.

“Oh,” you think. “Thank god I don’t need to write code to know half-way operations just to find out the status of the transaction.” Unfortunately, microservices developers are still living in that era. This is why Yoda never used Kubernetes.

I have a bad feeling about this

In microservices architecture, a single business process interacts with multiple services, each of which operates and fails autonomously. There is no single monolithic engine to manage and maintain state in the event of a failure.

This lack of transactions between independent services keeps developers in the bag. They should also handle application flexibility by managing what happens when things go wrong, rather than just focusing on the functionality of their own applications. What was once a substance is now their problem.

In practice, things can go wrong quickly in microservices architectures, with cascading failures that lead to performance and reliability problems. For example, a service that a development team updates may cause other services to fail if they have not also been updated to handle those new errors.

Due to the weakest link effect, the brittle complexity of microservices is a challenge. The overall reliability of an application is only as good as its least reliable microservices. With asynchronous primitives the whole thing becomes very difficult. If the response time of microservices is uncertain, state management is more difficult.

look at the size of that thing

Another aspect of this problem is that the state on its own is not well managed. The more microservices a user has, the longer it takes to manage their state. Companies often have thousands of microservices in production, which outnumber their developers. That’s what we saw as Uber’s early developers. In 2018, Uber had 4,000 microservices. We spent most of our time writing code to manage microservices state in this environment.

Developers have taken several approaches to address home state management. Some people use Kafka event streams hidden behind APIs to queue up microservice-based messages, but the lack of diagnostics makes root cause analysis a nightmare. Other systems use databases and timers to keep track of state.

Monitoring and tracing can help, but only up to a point. Monitoring tools oversee the health of platform services and infrastructure, while tracing makes it easier to troubleshoot bottlenecks and unexpected anomalies. There are many on offer. For example, Prometheus provides open-source monitoring that developers can query, while its sibling Grafana adds visualization capabilities to trace system behavior.

These solutions may be useful, providing at least some observability in microservices-based systems. However, monitoring tools do not help with the task of state management, leaving that burden to the developer. This is why developers spend a lot of time writing state management code rather than highly differentiated business logic. In an ideal world, anything else would be the essence of state management for them.

use themiCroServices State Management Platform, Luke

The answer to simplifying state management in microservices is to introduce it as a core abstraction for distributed systems.

We worked on a statement management platform at Uber after spending too much time manually managing microservices state. We wanted a product that would enable us to define workflows that call various microservices (in the developer’s language of choice), and then execute them without worrying about it later.

In our solution, which we originally called Cadence, a workflow automatically maintains state while waiting for potentially long running microservices to respond. Its concurrent nature also enables the workflow to continue with other non-dependent tasks in the meantime.

The system manages state interrupts without the need for developer intervention. For example, in the event of a hardware failure, the state management platform will restart the workflow on another machine in the same state without the developer needing to do anything.

Doing. Don’t do

A dedicated state management platform for microservices gives us the same kind of abstraction we see in atomic database transactions. Developers can be certain that the workflow will last until it is completed. Temporal takes care of any failure and restarts under the hood. Now, microservices-based applications can guarantee that a debit from one account automatically credits another in a few lines of code. They get the best of both worlds.

This fixes a long-standing problem with microservices and supercharges developer productivity, especially now that they are generally responsible for the operation of their applications in addition to development. Finally, developers who want the benefits of microservices can enjoy them without going to the dark side.

Leave a Comment