Micro architecture & design patterns for microservices

Asim Aslam
Aug 30, 2016 · 12 min read

We’ve had a lot of questions about the micro architecture and design patterns for microservices over the past few months. So today we’ll try cover both.

About Micro

Micro is focused on addressing the fundamental requirements for building microservices and has looked to do this by taking a thoughtful and measured approach to it’s design.

If you would like to read up on the Micro toolkit check out the previous blog post here or if you would like to learn more about the concept of microservices look here.

We’ll quickly recap on the features of Micro before delving into further architecture discussion.

The Toolkit

Micro API is an API Gateway that serves HTTP and routes requests to appropriate micro services. It acts as a single entry point and can either be used as a reverse proxy or translate HTTP requests to RPC.

Micro Web is a web dashboard and reverse proxy for micro web applications. We believe that web apps should be built as microservices and therefore treated as a first class citizen in a microservice world. It behaves much the like the API reverse proxy but also includes support for web sockets.

Micro Sidecar provides all the features of go-micro as a HTTP service. While we love Go and believe it’s a great language to build microservices, you may also want to use other languages, so the Sidecar provides a way to integrate your other apps into the Micro world.

Micro CLI is a straight forward command line interface to interact with your micro services. It also allows you to leverage the Sidecar as a proxy where you may not want to directly connect to the service registry.

That’s the quick recap. Now let’s go deeper.

RPC, REST, Proto…

We’re not alone in this belief.

Google is creator protobuf, uses RPC internally and more recently open sourced gRPC, an RPC framework. Hailo was also a strong advocate of RPC/Protobuf and benefited tremendously, interestingly more so in cross team development than systems performance. Uber choosing their own path has gone on to develop a framing protocol for RPC called TChannel.

Personally we think the APIs of the future will be built using RPC because of their well defined structured format, propensity for use with efficient encoding protocols such as protobuf with the combination offering strongly defined APIs and performant communication.

HTTP to RPC, API…

The API gateway is a pattern used for microservice architectures. It acts as a single entry point for the outside world and routes to an appropriate service based on the request. This allows a HTTP API itself to be composed of different microservices.

This is a powerful architecture pattern. Gone are the days where a single change to one part of your API could bring down the entire monolith.

The micro API uses path-to-service resolution so that each unique request path can be served by a different API micro service e.g. /user => user api, /order => order api.

Here’s an example. A request to /customer/orders will be sent to the API service go.micro.api.customer with method Customer.Orders.

Image for post
Image for post

You might be wondering what the heck an API service is. Now is about the right time to discuss the different types of services.

Types of Services

I’ll acknowledge right now that these concepts are nothing new but they are compelling given they’ve been proven in very large successful technology companies. Our goals are to spread these development philosophies and guide design decisions via tooling.

So here’s the types of services we currently define.

API — Served by the micro api, an API service sits at the edge of your infrastructure, most likely serving public facing traffic and your mobile or web apps. You can either build it with HTTP handlers and run the micro api in reverse proxy mode or by default handle a specific RPC API request response format which can be found here.

Web — Served by the micro web, a Web service focuses on serving html content and dashboards. The micro web reverse proxies HTTP and WebSockets. These are the only protocols supported for the moment but that may be extended in the future. As mentioned before, we believe in web apps as microservices.

SRV — These are backend RPC based services. They’re primarily focused on providing the core functionality for your system and are most likely not be public facing. You can still access them via the micro api or web using the /rpc endpoint if you like but it’s more likely API, Web and other SRV services use the go-micro client to call them directly.

Image for post
Image for post

Based on past experiences we’ve found this type of architecture pattern to be extremely powerful and seen it scale to many hundreds of services. By building it into the Micro architecture we feel it provides a great foundation for microservice development.

Namespacing

The micro api and web will compose a service name of the namespace and first path of a request path e.g. request to api /customer becomes go.micro.api.customer.

The default namespaces are:

  • API — go.micro.api
  • Web — go.micro.web
  • SRV — go.micro.srv

You should set these to your domain e.g com.example.{api, web, srv}. The micro api and micro web can be configured at runtime to route to your namespace.

Sync vs Async

Micro treats asynchronous communication as a first class citizen and a fundamental building block for microservices. Communicating events through asynchronous messaging allows anyone to consume and act upon them. New standalone services can be built without any modification to other aspects of the system. It’s a powerful design pattern and for this reason we’ve included the Broker interface in go-micro.

Image for post
Image for post

Synchronous and asynchronous communication are addressed as separate requirements in Micro. The Transport interface is used to create a point to point connection between services. The go-micro client and server build upon the transport to perform request-response RPC and provide the capability of bidirectional streaming.

Image for post
Image for post

Both patterns of communication should be used when building systems but it’s key to understand when and where each is appropriate. In a lot of cases there’s not right or wrong but instead certain tradeoffs will be made.

An example of where the broker and asynchronous communication could potentially be used is in an audit trail system for keeping track of customer event history.

Image for post
Image for post

In this example every API or service publishes an event when some action occurs such as a customer logs in, update their profile or places an order. The audit service will subscribe for these events and store them in a time series database of some kind. An admin or anyone else can then view the history of events that have taken place within the system for any user.

If this was done as a synchronous call we could easily overwhelm the audit service when there’s high traffic or as the number of bespoke services increases. If the audit service was taken offline for some reason or a call failed we would essentially lose this history. By publishing these events to the broker we can persist them asynchronously. This is a common pattern in event driven architectures and for microservices.

OK wait, brief pause, but what defines a microservice?

We’re covering a lot of what the Micro toolkit provides for microservices and we’ve defined the types of services (API, WEB, SRV) but there’s nothing really about what a microservice actually is.

How does it differ from any other kind of application? What gives it this special name of a “microservice”.

There’s varying definitions and interpretations but here’s a couple that fit best in the Micro world.

Loosely coupled service oriented architecture with a bounded context
Adrian Cockcroft

An approach to developing a single application as a suite of small services, each running in its own process and communicating with lightweight mechanisms
Martin Fowler

And because we love the unix philosophy and feel it fits perfectly with the microservice philosophy.

Do one thing and do it well
Doug McIlroy

Our belief and the idea we build on is that a microservice is an application focused on a single type of entity or domain, which it provides access to via a strongly defined API.

Let’s use a real world example such as a social network.

Image for post
Image for post

A well defined software architecture pattern that became popular with the rise of Ruby on Rails was MVC — Model-View-Controller.

In the MVC world each entity or domain would be represented a model which in turn abstracts away the database. The model may have relationships with other models such as one to many or many to many. The controller processes in coming requests, retrieves data from the models and passes it to the view to be rendered to the user.

Now take the same example as a microservice architecture. Each of these models is instead a service and delivers its data through an API. User requests, data gathering and rendering is handled by a number of different web services.

Each service has a single focus. When we want to add new features or entities we can simply change the one service concerned with that feature or write a new service. This separation of concerns provides a pattern for scalable software development.

Now back to our regularly scheduled program.

Versioning

Image for post
Image for post

Versioning is an important part of developing real world software. In the microservice world it’s critical given the API and business logic is split across many different services. For this reason its important that service versioning be part of the core tooling, allowing finer grained control over updates and traffic shaping.

In go-micro a service is defined with a Name and Version. The Registry returns a service as a list, splitting the nodes by the version they were registered with.

This is our building block for version based routing.

type Service struct {
Name string
Version string
Metadata map[string]string
Endpoints []*Endpoint
Nodes []*Node
}

This in combination with the Selector, a client side load balancer, within go-micro ensures that requests are distributed across versions accordingly.

The selector is a powerful interface which we’re building on to provide different types of routing algorithms; random (default), round robin, label based, latency based, etc.

By using the default random hashed load balancing algorithm and gradually adding instances of a new service version you can perform blue-green deployment and do canary testing.

Image for post
Image for post

In the future we’ll look to implement a global service load balancer which ties into the selector allowing for routing decisions based on historic trends within a running system. It will also be capable of adjusting the percentage of traffic sent to each version of a service at runtime and dynamically adding metadata or labels to a service, which label based routing decisions can be made on.

Scaling

Again the notion of separation of concerns and doing one thing well. Scaling infrastructure as well as code is very much about simplicity, strongly defined APIs and a layered architecture. By creating these building blocks we allow ourselves to construct more scalable software and address higher level concerns elsewhere.

This is something fundamental to the way Micro is written and how we hope to guide software development in a microservices world.

We’ve briefly discussed cloud architecture patterns in a previous post about Micro on NATS and will re-address some of the ideas here.

When deploying services in a production setting you’ll be looking to build something scalable, fault tolerant and performant. Cloud computing now gives us access to pretty much unlimited scale but nothing is impervious to failure. In fact failure is one of the key aspects that we look to address when building distributed systems and you should take this into consideration when building your infrastructure.

In the world of the cloud, we want to be tolerant of Availability Zone (datacenter) failures and even entire Region (Multi DC) outages. In past days, we used to talk about warm and cold standby systems or disaster recovery plans. Today the most advanced technology companies operate in a global manner, where multiple copies of every application is running in a number datacenters across the world.

We need to learn from the likes of Google, Facebook, Netflix and Twitter. We must build systems capable of tolerating an AZ failure without any impact on the user and in most cases dealing with region failures within minutes or less.

Micro enables you to build this kind of architecture. By providing pluggable interfaces we can leverage the most appropriate distributed systems for each requirement of the micro toolkit.

Service discovery and the registry are the building block of Micro. It can be used to isolate and discover a set of services within an AZ or Region or any configuration you so choose. The Micro API can then be used to route and balance a number of services and their instances within that topology.

Image for post
Image for post

Summary

Microservices is first and foremost about software design patterns. We can enable certain foundational patterns through tooling while providing flexibility for other patterns to emerge or be used.

Because Micro is a pluggable architecture it’s a powerful enabler of a variety of design patterns and can be appropriately used in many scenarios. For example if you’re building video streaming infrastructure you may opt for the HTTP transport for point to point communication. If you are not latency sensitive then you may choose a transport plugin such as NATS or RabbitMQ instead.

The future of software development with a tool such as Micro is very exciting.

If you want to learn more about the services we offer or microservices, check out the blog, the website micro.mu or the github repo.

Follow us on Twitter at @MicroHQ or join the Slack community here.

Micro

A cloud native development platform

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch

Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore

Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store