Back to Blog
Team reviewing a tablet together in a dim office, titled "Ambassador Design Pattern"
Engineering
Dec 18, 2022
7 Min Read

Ambassador Design Pattern in Microservices

What Is the Ambassador Pattern?

The Ambassador pattern is a microservices design approach that gives external requests a single way in to a group of microservices. It does this by moving common client-connectivity tasks like routing, security, and resiliency into a separate, language-independent proxy. This setup is often used to add networking features to older applications or systems that are hard to change. The main goal is to separate clients from the microservices they use, making deployments more flexible and scalable while reducing how much backend changes affect client code.

Generic Ambassador pattern architecture

Consider using the Ambassador pattern when:

  • You need a common set of client-connectivity features that must work across multiple programming languages or frameworks.
  • You want to move cross-cutting tasks like monitoring, routing, security, and resiliency to a specialized team, which makes the system easier to maintain and more modular.
  • You need to extend the networking capabilities of legacy applications or systems that are difficult to modify directly.

It’s a poorer fit when:

  • Request latency is critical, since the extra network hop through the proxy introduces overhead.
  • The connectivity features are only ever consumed by a single language, where a client library is usually a better fit.
  • The connectivity features aren’t generalizable and need tighter integration with the client application itself.

Advantages

The pattern offers several concrete benefits:

Modular and reusable. Since the ambassador’s logic is in its own container, it stays separate from the application it supports. This separation makes the ambassador easier to maintain and reuse with different services.

Faster development. After you build the ambassador container, you can use it with many applications. Teams do not need to write the same connectivity logic for each service. This makes development easier and more efficient, saving time and effort.

More consistent, higher-quality implementation. When you write the logic once and reuse it in different places, you avoid repeating work and get more consistent, better-tested code than if each team built it on their own.

Using an Ambassador for Service Sharding

When a dataset becomes too big for one machine, sharding breaks up the storage into several parts, each on a different machine. This spreads out the load instead of putting it all on one host. Here, we focus on how to adapt an existing service to use a backend that is already sharded, rather than how to build the sharded service itself.

This brings up two practical questions: how do you connect existing code, which was written for a single storage backend, to the new sharded service? And how do you share configuration across environments like Dev, QA, UAT, and Prod? An ambassador helps with both. It gives a single entry point for requests to the sharded service and takes care of routing, security, and resiliency. This lets you update existing code to work with sharding and makes it easier to deploy across different environments.

Combining shards with an ambassador in a microservices architecture

The ambassador can either live on the client side or be built directly into the sharded service itself.

There are two ways to handle this. One way is to put the sharding logic and a stateless load balancer directly into the sharded service. This makes the service’s deployment more complex but means you do not need a client-side ambassador. The other way is to use a single-node ambassador on the client side to route traffic to the right shard. This makes the client more complex but keeps the sharded service simpler. Which option is best depends on your architecture and how much control you have over the code you write and the code you deploy. The rest of this section explains the client-side approach: using a single-node ambassador for sharding.

The client-side ambassador is a container with all the routing logic needed to send requests to the right storage shard. To the frontend or middleware application, it looks like it is connecting to a single storage backend running locally. In fact, it is connecting to a sharding ambassador proxy that catches each request, sends it to the correct shard, and returns the response to the application.

This setup clearly separates responsibilities. The application container only needs to know how to reach a storage service on localhost. The ambassador proxy handles the sharding logic and can be reused with different applications. If there is an open-source ambassador available, using it can make system development much faster.

Using an Ambassador for Service Brokering

Making an application work in different environments, such as a public cloud, a physical datacenter, or a private cloud, creates challenges with service discovery and configuration.

Simply put, the application’s frontend must connect to the right utility services wherever it is deployed. For example, if it needs a MySQL database to store data, in a public cloud this might be a managed service. In a private cloud, it could mean setting up a new virtual machine or container running MySQL.

A portable application therefore needs a way to find the right MySQL service by introspecting its environment at runtime. This process is called service discovery, and the component that performs it is called a service broker.

This is where the ambassador pattern helps. It separates the application’s logic from the service broker’s logic. The application always connects to what seems like a local service on localhost, which is the ambassador. The service broker ambassador then checks the environment and manages the real connection.

MySQL service discovery in portable applications

A service broker ambassador connects a frontend to the right MySQL instance across public cloud, datacenter, and private cloud environments.

Using an Ambassador for Experimentation and Request Splitting

Production systems often need to send some requests to a different version of a service. This is usually done to test a new or beta version and see how reliable and fast it is before making it available to everyone.

Request splitting means sending some incoming requests to a different version of a service instead of the main production one, mainly for testing. For example, you might send a small part of the traffic to a beta version to check how well it works. Another method is traffic teeing, where each request goes to both the production system and a new, not-yet-deployed version at the same time. Only the production system’s response goes back to the user; the other response is ignored. Teeing lets you test a new version under real production load without any risk to users.

The ambassador pattern works well here because it keeps the main service logic separate from the experimental service logic. In practice, the application container connects to what seems like a local service, but it is actually the request-splitting ambassador. The ambassador catches incoming requests, sends some to the new or experimental service, and sends the rest to the main production service.

When the production service replies, the ambassador sends that response back to the user as if it handled the request itself. By keeping this logic separate from the application container, both codebases stay focused on one job. The modular design also means you can reuse the same request-splitting ambassador with different applications and environments, often without any changes.

Request splitting with the ambassador pattern

A request-splitting ambassador sends a portion of traffic to a new service version for testing, while the rest continues to production.

Conclusion

The Ambassador pattern is a flexible way to solve many connectivity problems in microservice architecture. It offers modularity, is easy to maintain, and can be reused. It is especially useful for service sharding, service brokering, or request splitting.

However, the Ambassador pattern is not always the best choice. Other methods may work better if you need very low latency or only have clients in one language. Think about your system’s needs before choosing this pattern, but keep it in mind as a good option for the right situation.

Join the Conversation

This dispatch is part of an ongoing series on the future of intelligence. Share your perspective or subscribe for more.

Weekly dispatches. No spam. Ever.