The Challenges of Architecing for the Cloud
If you’re building a large modern enterprise software application, it’s really important that you get the architecture right. We have high expectations these days.
Performance and scalability
We want our applications to perform really fast and to be able to scale to meet demand without having to pay for compute resources we’re not using.
We also want our applications to be resilient so that if there’s any temporary outages or failures, they don’t take down our whole system.
Easy to deploy and zero-downtime upgrades
And we’d like our applications to be easily deployable so that we can rapidly release new versions to meet changing requirements. On top of that, we’d also like the upgrades to our application to be seamless, without requiring downtime.
For large applications, we need the code to be written in such a way that lots of developers can work on it simultaneously, without getting in each other’s way of breaking things.
And we want the codebase to be easy to evolve, allowing us to adopt new technologies and adapt to new requirements without the need for a major upheaval.
It’s also really important that our applications are observable, so that we can easily monitor them, checking that they’re working as expected and responding quickly to any problems in production, ideally even before our end users know there’s an issue.
And, of course, We must have first-class security. If we’re storing valuable and sensitive data in the cloud, then it’s critical that we have extremely robust defences against hackers.
Now, that’s a pretty tall order. It’s not at all easy to design a software architecture that excels at meeting all of those criteria.
And this is where microservices comes in. Microservices is an architectural style that’s rapidly grown in popularity over recent years and can help a lot in meeting the challenges we’ve just mentioned. In this executive briefing, We going to introduce you to the main characteristics of microservice architectures, and we’ll learn about what benefits they can bring. But we’ll also be very realistic about some of the challenges that will be introduced if you decide to adopt a microservices architectural style, and we’ll see how we can overcome those challenges.
What Are Microservices?
Before we go too much further, we need to define what exactly do we mean by a microservice. There isn’t really an official definition, but there are some key characteristics that all microservices should have. A very simple definition is that microservices are small autonomous services that collaborate to form a broader application.
Microservices are small autonomous services that collaborate to form a broader application
Let’s go into a little bit more detail about exactly what we mean by that.
It’s important to understand that microservices should be autonomous, this means that they’re independently deployable. In other words, you can upgrade just one microservice to a new version without having to upgrade all the others at the same time.
Microservices own their own data
Microservices should also own their own data, that means each microservice has its own independent database rather than sharing a database with other services.
Synchronous or asynchronous API
Each microservice exposes an API, it’s quite often an HTTP API, but asynchronous communication with messaging is also commonly used. Anyone who wants to access the data owned by a microservice must do so via its API, which is essentially its public interface.
Each microservice should have a single, well‑defined responsibility, usually organized around business capabilities. Because microservices have a single responsibility, they ought to be relatively small, hence the name Microservices.
Microservices should be small
We’re trying to avoid creating gigantic services that have huge codebases and do everything, and this means that a microservice can be built and maintained by a small team of just a few developers, and in some ways, this is one of the most compelling arguments for microservices, it gives us a way to scale our teams. And because microservices are autonomous, these teams are free to make progress and release new versions of their microservice without being held up by other teams.
Microservices enable us to scale our teams
What Problems Do Microservices Solve?
We’ve talked a bit about what microservices are, but why do we need them? What problems are they trying to solve? This is a very important question to answer because microservices aren’t necessarily the right approach for every application.
Microservices aren’t necessarily the right approach for every application
Let’s start by describing an architectural style that microservices are often contrasted with. A software architecture where we implement all the functionality inside a single large application with a single code base and all our data stored in a single database is often described as a monolith.
Now although the term monolith is sometimes used quite dismissively, there’s nothing necessarily wrong with a monolithic architecture. In fact, it can have many benefits.
Benefits of “Monoliths”
Code is easy to navigate
For example, if all your code is in one place, then within your IDE, you can find the code and debug directly into it for all the features of your whole application.
And if everything builds into a single executable, then deployment may only involve updating one single server with the new version of the code, which is relatively straightforward.
So there’s a certain simplicity that comes with a monolithic architecture, which can be very beneficial. However, it’s very common to start running into serious problems as your application grows over time.
Monoliths can cause serious problems as applications grow over time
Challenges of “Monoliths”
Codebase grows larger and complex
First of all, over several years, your single code base may have grown to millions of lines of code, making the application as a whole very unwieldy and complex to work on. If you’ve got large teams of developers working on a project like this, it’s very common to find them treading on each other’s toes and making conflicting changes.
Can get stuck on legacy technology
With monoliths, you’re likely to get stuck on legacy technology, and that’s because the programming framework you originally built your monolith with will eventually become obsolete. But by that stage, there’s often so much code that migrating the whole thing away to something more modern is too large a task to attempt.
Deployment requires downtime
Although deploying a new version of a monolith tends to be relatively straightforward, it often requires some downtime, with the whole application needing to be stopped to allow the server to be updated before the new version can start up. But in the modern era of cloud‑based computing, our expectations are that applications will continue to run without noticeable downtime even during an upgrade.
Scalability can be difficult
Scalability can also be a real challenge with monoliths. If your application is under heavy load, you can scale up by upgrading to a more powerful server. But scaling up can only take you so far. To go further, you also need to be able to scale out where you run multiple instances of your application on many servers. But in order to do that, you must ensure that your entire application has been written to be stateless. And, unfortunately, in many monolithic applications, that just isn’t the case.
Tight coupling reduces flexibility
Finally, it’s very important that our applications are flexible and can easily adapt to changing business requirements. But without great care, monolithic codebases tend to become very tangled and tightly coupled due to their nature of having all the code in one place. And that can really hinder progress.
And all of these problems that you can run into with monolithic architectures are the reason why, in recent years, many companies have chosen to start moving away from this approach and towards microservices.
Microservices can help address the challenges of monolithic architectures
Of course, We have oversimplified things here. There is, in fact, a whole spectrum of architectural options all the way, on the one hand, from having a genuine monolith through to maybe a more distributed service‑oriented architecture all the way through to microservices.
But now we’ve identified some of the problems we can run into with monoliths, let’s look in more detail about how microservices can help solve these problems.
How Can Microservices Help?
Let’s look now at the ways in which microservices can address some of the challenges that we’ve identified with monolithic architectures.
Reduce code complexity
For one thing, microservices can be a helpful way to avoid our codebase becoming very tightly coupled and complex. By breaking responsibilities out into their own microservices, each of those smaller codebases is much more simple and focused, which makes for code that’s much easier to maintain and evolve.
Freedom to choose the right tool
Breaking our application up into microservices also gives us the freedom to choose the right tool for the right job. For example, one microservice might use a document database, while another uses a relational database.
Small, independent development teams
Each microservice can be owned and maintained by a small team, and this greatly reduces the problems associated with having too many developers trying to work on the same code base at the same time.
Migrate to new technology more easily
Microservices also allow us to migrate to new technology more easily. Rather than having to update everything in one go, each microservice can be upgraded individually as needed.
Possible to rewrite if necessary
In fact, their small size means that microservices can also be completely rewritten if necessary, which is typically cost-prohibitive with a monolithic application.
Microservices can also help us achieve a more resilient architecture that copes better with transient failures. Even if one microservice is temporarily unavailable, it’s possible for the rest of the system to keep working.
So we no longer have a single point of failure where one problem takes down the whole system, and this characteristic of microservices helps us to achieve high availability even during upgrades.
Support continuous delivery
The microservice architecture supports continuous delivery where we can frequently and safely perform rolling upgrades of individual microservices, allowing us to deliver new functionality quickly without requiring periods of downtime. With microservices, we can scale specific capabilities independently.
So we might, for example, dedicate several virtual machines to share the load for one particularly busy microservice, while other microservices may only require a single instance.
Finally, when you create small, focused microservices with clear responsibilities, you often find some of them can be reused in other contexts, essentially becoming building blocks, enabling you to innovate faster.
And those are just a few of the benefits that microservices bring, and hopefully, that gives you an idea of why they’re becoming so popular.
What Are Some Challenges of Microservices?
Now, so far, We’ve been very positive about microservices and talked a lot about the benefits they can bring. But it’s important that we make it very clear, microservices aren’t magically going to make all of your problems go away. In fact, microservices can bring some really significant technical and operational challenges, and you need to be aware of those before choosing to adopt a microservices architecture. Let us give you a brief overview of some of the key challenges you’re likely to run into sooner or later on your microservices journey.
Defining microservice boundaries
First of all, in order to get started with microservices, you need to come up with a way of dividing up responsibilities between those microservices. That might sound relatively easy, but it’s actually quite tricky to make good decisions here that will serve you well in the long term.
Difficult to make good choices
If your microservice boundaries are in the wrong places, you can end up with a poorly performing system, as there’ll be lots of chatty network communication between microservices and the need to fetch data from multiple different databases. You can also miss out on the benefits of having small, independent teams of developers who take ownership of microservices if your division of responsibilities means that most new features end up requiring all the microservices to be updated at the same time.
Apply “Domain-Driven Design” principles
A good way to avoid this pitfall is to learn about domain‑driven design. This approach encourages us to identify what is called bounded contexts within our application. These are natural boundaries of business‑focused responsibilities, and often it makes sense to create a microservice for a specific bounded context.
Another challenge is that when you have many microservices, it can become really difficult for your developers to work effectively on the project. Do they need to fetch the source code for all the microservices and build them all and run them all locally? That can be a very slow and error‑prone process. The secret here is to find ways of automating and streamlining the development experience. Making use of Docker containers is one great way of achieving this, as developers can use docker‑compose to easily start up all the microservices locally without having to build them first.
The deployment must be automated
It’s also critical that you automate the deployment of your microservices. You might be able to get away with a manual deployment process for a monolithic architecture, but when you have many microservices, it’s simply too time‑consuming and error-prone to deploy each one manually. Instead, you should consider implementing continuous delivery principles so that every time a new version of a microservice is released, it can be published into a production environment with minimal effort.
Another way in which microservices can be a step backwards compared to monoliths is getting the operational insight you need to know what’s going on and what’s going wrong in a live production system. With a monolith, there’s often just one server to monitor and one place to view all the logs. But with microservices, you have many processes running on many virtual machines and each outputting their own logs. And this means it’s well worth your time investing in aggregating all the logging, telemetry, and metrics into a single centralized dashboard that can be easily monitored.
Microservices can get bloated
Finally, if you don’t take care, over time it’s quite possible that some of your microservices will get bloated and take on many more responsibilities than they ought to have, making them more like the monoliths that we were trying to get away from in the first place.
So, there are several challenges that you do need to be aware of before deciding to embrace microservices, and you need to have a plan to deal with them. Fortunately, you’re not alone in this. The challenges of building, deploying, and monitoring microservice applications are pretty much the same whatever business context you’re in. And because of that, we’ve seen many tools and frameworks emerging over the past few years which have the explicit goal of making it easier to build and run microservice applications.
Pluralsight Couse Microservices Archtecture