Microservices are hard — an invaluable guide to microservices.

25,791 reads

If you’re looking to move to Microservices, I have some extremely helpful advice for you that we have learned during our migration from a monolith to a scalable, maintainable microservice architecture.

Background

We’ve been building our platform now for over 18 months. It started off relatively simple. We had a small go server (using Gin) with a number of REST endpoints. It looked a little bit like this.

https://oursite.com/api/v1/places

https://oursite.com/api/v1/users

https://oursite.com/api/v1/bookings

Every resource had it’s own versioned URL. They would each support POST, GET, PATCH, DELETE as necessary. We had 2 seperate mobile clients connecting to these APIs and we had a centralized database. We used JWT for user authentication and everything was going fine. We were handling a fair number of requests per hour. However, we needed to change our platform. The mobile apps weren’t working out.

This is where we started to hit issues. We had a large number of new requirements involving 2 web applications. There were two choices, only one of which was to be viable. We could either rewrite our entire architecture and spend a number of months writing a new server with required functionality — or we could use our existing server and add new functionality to it. Given our time constraints, we used our existing server.

After a few weeks, our legacy code was already starting to grow and we were starting to encouter issues. Changing models was becoming difficult, everything seemed like a chore. We couldn’t keep this up much longer and we came to another turn in the road. Our choices were now either: keep building the current server and encounter hard problems upon scaling or migrate to a more scalable approach that was also maintainable. A silver bullet, if you will.

What are Microservices?

Microservices are not a silver bullet by any stretch of the imagination. I don’t believe there are any silver bullets when it comes to software development. If someone tells you there is, be skeptical. Basically, microservices do what they say on the tin. They’re small, isolated services that represent an equally small portion of your business domain.

Everybody has a different opinion on how a microservice should work and communicate but some beliefs are more common than others. To say that they’re simple would be a huge understatement. The concept of a microservice architecture is simple and ideal. The initial execution? Far from it.

Monolithic vs Microservice — courtesy of https://www.weave.works

The diagram above explains the difference between a monolithic architecture and a very, very simple microservice architecture. With a monolithic architecture, you have one large server responsible for handling all the requests. This is going to hit you at scale. It’s going to hit you hard. Microservices, however, can balance traffic due to your business’ needs. If you are receiving a large number of payments, you can scale up your payment service and keep the other services using a smaller number of resources. It’s horizontal scaling at it’s finest.

Microservices sound great, why are they hard?

Microservices are very idealistic and you hear a relatively small number of large companies preaching the benefits. I feel as if a large number of smaller companies mistakingly take this information as gospel. These large companies such as Uber, Google, AirBnb, Square amongst others can execute microservices well because they are absolutely loaded. They have the resources and time to invest into building this architecture.

When you start looking into Microservices, you enter a rabbit hole that’s absolutely massive. It makes Alice in Wonderland seem like a piercing. You quickly learn that you will need to manage all of these microservices and balance the load whilst monitoring everything that is happening. Oh, don’t forget that you’re going to need to test each service locally when you’re building new features.

After a few weeks of research and testing, here is a small list of responsibilities for each service and tools I would recommend researching

Containers (Docker)

Orchestration (Kubernetes)

Management (Forge)

Api Gateway / Canary (Ambassador)

Edge Proxy (Envoy)

Monitoring (Prometheus)

Local Testing (Telepresence)

Looking at that list, it’s a lot to ingest for one simple service. However, being able to monitor interactions between services and orchestrate them is immensely powerful. There are some terms in there that might seem confusing. I’ll cover the most confusing ones.

Edge Proxy — An edge proxy is a process that runs alongside your service and proxies your services traffic through it’s own internal system and usually uses some kind of middleware (such as prometheus) to monitor and track this traffic. Ambassador is built on Envoy and provides more functionality.

Containers — You’ve most likely heard of Docker by now. It’s the container standard on the web. It’s actually a play on the meaning of the word container. You can think of docker containers and small shipping containers that are running your application in the cloud with an orchestrator moving them around and optimizing them. They also use linux containers directly under the hood.

Orchestration — Kubernetes is the most popular orchestrator and it works extremely well with Docker. It essentially takes your docker container and looks after them to make sure they’re all working in an efficient manner.

I’ve heard I can use any language for each micro service, is that correct?

Sure. You can use any language for a microservice in the same manner that you can run a marathon in boots. It’s possible but it doesn’t mean it’s effective and you’re probably wasting your time. The key to creating a stable and scalable microservice architecture is to make sure that it’s maintainable and that it follows a general trend within your business.

Your architecture should have solid foundations. If somebody was to work on your project, you should be able to say:

Generally, our services are written in {main language}. They use the following frameworks: {list of frameworks}. If you think a service should use a different language, you will be responsible for ensuring it has the same functionality as our existing services.

This keeps consistency within your projects. Sure, there are exceptions. If you had a service that was performing complex mathematics and was handling a lot of traffic, you might want to opt for a language more suited to that task. It won’t be a simple task, however. If you have dependencies in your PSL (primary service language), then it might be an investment of time to rebuild such in the new language.

How do microservices communicate?

One of the major concern of microservices in the past had been latency issues. Making a number of HTTPS requests between a number of services could cause a fairly noticeable delay to the client. This isn’t a feasible approach and it’s certainly not lightweight.

A new approach was needed for microservices and along came our saviour: gRPC. gRPC is an RPC framework that is highly efficient and is designed with speed and efficiency in mind. Binary data is sent through the wire at high speeds, alongside rapid serialisation/deserialization.

Using gRPC, you define your models using a protobuf definition, which is fairly simple and they have a protobuf compiler for many common languages. Using gRPC has calmed fears about latency.

However, using these protobuf models comes with some confusion. Versioning. We’ve been looking into this the past few weeks, wondering how different services can share the same protobuf models (for example, a user model). We’ve had ideas such as keeping the protobuf models in a versioned git repository but we’re not convinced. We’re currently investigating the best mechanism for this.

There are also issues with using gRPC. You will also likely have to maintain a standard REST API for standard web clients to access. We’re making progress in this area using envoy and grpc-gateway. It’s still a complicated issue that doesn’t seem to get much coverage in the microservice world.

Migrating

If you’re considering building a microservice architecture to begin with, I would not recommend it. You’ll spend way too much time doing premature optimizations for domains you don’t really know exist yet. To create a solid microservice architecture, you’ll need to know exactly why you’re doing it and nobody can really tell you that.

However, if you’ve already got a monolith and you’re looking to migrate, here’s some advice.

Identify your business domains (bounded contexts)

Research Docker, Kubernetes and Envoy thoroughly

Research monitoring and testing tools

Spend a lot of time creating demos

That’s our personal experience. We spend a lot of time in the Google Cloud Platform creating different architectures with new tools, discovering what works best for us. We are currently using the following stack:

Primary Service Language: Go

Primary Service Datastore: Postgresq

Cloud Platform: Google Cloud

Containers: Docker

Container Orchestration: Kubernetes

Edge Proxy: Envoy

Local Testing: Telepresence

Monitoring: Prometheus

Management: Forge

It’s been an exciting number of months completing our migration. It’s been difficult. However, more recently we stumbled across a company that smashing the complicated entry barrier building a microservices architecture. They’ve created a number of tools to help you get started with microservices and through our limited experience, we’re enjoying using them. The team are also highly respectful, knowledgable and responsive.

Give them some love at https://www.datawire.io. Look at their products and read through their docs. You’ll come out knowing a lot more about Microservices.

I would love to know what you think and would appreciate your thoughts on this topic. If you could give us any advice from your experience, do let me know. I’d also be happy to answer any questions about our experience.

Tags