When we think about building an application, we visualize it as a bunch of code glued together, running somewhere on the web for the purpose of providing people some value. It could be the homepage of your coffee shop, an e-commerce site or an amazing API which collects data from your watch.
Most of the time applications are basically that, a bunch of code, and that works perfectly for most common scenarios. They are effectively monoliths.
A monolithic application is where all of the required logic is located within one unit (a war, a jar, a single application, one repository).
They are responsible for all possible functionality:
- handling HTTP requests
- dealing with authentication
- executing domain logic
- database interactions
- communication with the user
The problem is that, over time, the application evolves and its requirements become more complex. At some point, the monolithic application’s architecture becomes a liability, where even the smallest change to the system requires re-building and re-deploying the entire application. And the situation gets worse when you consider scaling: You have to run multiple instances of the monolith, even if you know that the bottleneck lies in a single component.
This is where microservices architecture can be invaluable.
What is Microservices architecture?
Microservices is an approach to application architecture and development wherein an application is built in smaller, separate pieces. Each service is developed, tested and deployed independently.
Although microservices architecture is fairly new, the basic concept behind it is one that will seem familiar to many software professionals.
You could think of the Microservices Architectural Style as a specialization of SOA.
Difference between Microservices Architecture and SOA by Tom Redfern
The only relation between different microservices is the data exchange accomplished through the APIs they expose. We can think of those microservices as built-in programs in a Unix-like OS, connected by pipes.
The Benefits of Microservices
- Faster and simpler deployments and rollbacks
- Elimination of long-term commitment to a single technology stack
- Improved fault isolation
- Independently scalable services
- Technology diversity
- Ability to write new features as plugins
The Drawbacks of Microservices
- Increased network communication
- Serialization between microservices
- Additional complexity in testing a distributed system
- Increased complexity in deployment
When should I switch from Monoliths to Microservices?
The complexity that should drive a switch to microservices can come from many sources: dealing with large teams, multi-tenancy, different business components evolving independently, and scaling. But the most common driver is when a monolithic application becomes too large to modify and deploy.
You must fully understand your module boundaries and the domain’s problem before attempting to use microservices; if you don’t, you will end up with source code that is poorly written and hard to maintain.
Also, you must be ready to support:
Rapid Provisioning: you should be able to fire up a new server in a matter of hours.
Basic Monitoring: with many loosely-coupled services collaborating in production, things are bound to go wrong in ways that are difficult to detect in test environments.
Rapid Application Deployment: with many services to manage, you need to be able to quickly deploy them.
With those caveats, take a look to the decision flow below made by akfpartners
How to implement Microservices architecture?
The API gateway
Big enterprise front-ends might need to invoke large numbers of services, like Amazon does. Invoking requests often takes longer than receiving response data.
The API gateway handles incoming requests by sending subsequent requests to a number of microservices over a high-performance LAN, then returning an aggregated response to the consumer. The gateway should not contain any logic.
For a more detailed explanation, read the Building Microservices: Using an API Gateway article written by Chris Richardson.
Keep in mind that remote calls can fail or hang without a response until a timeout occurs. There are a few techniques to deal with these issues. One of them, is the circuit-breaker pattern.
The basic idea behind the circuit breaker is very simple. You wrap a protected function call in a circuit breaker object, which monitors for failures. Once the failures reach a certain threshold, the circuit breaker trips, and all further calls to the circuit breaker return with an error, without the protected call being made at all.
CircuitBreaker by Martin Fowler
If you’d like to study the circuit-breaker pattern in greater detail, you can take a look to the Netflix techblog, where they share the principles behind their circuit-breaker implementation and how they build a fault tolerant API.
Dealing with a number of microservices can easily become a very complex endeavor. Each can be written in a different programming language, with different dependencies. But most of these problems can be avoided by packaging each service as a separate container.
Containers are extremely fast to build and start. For example, Docker containers start much faster than a VM since only the application process starts rather than an entire OS.
Cross functional teams
When looking to split a large application into parts, often management focuses on the technology layer, leading to UI teams, server-side logic teams, and database teams. When teams are separated along these lines, even simple changes can lead to a cross-team project taking time, coordination and budgetary approval.
Microservices are best implemented by a single, cross-functional team, from the start (design) to finish (deployment and maintenance). Cross-functional teams gives us the freedom to be agile, to innovate and to increase productivity by cutting out unnecessary layers.
Any organization that designs a system (defined broadly) will produce a design whose structure is a copy of the organization’s communication structure.
– Melvyn Conway, 1967
Who is using this architecture?
Large-scale web sites like Netflix and Amazon have evolved from a monolithic architecture to a microservices architecture.
Netflix is responsible for up to 30% of Internet traffic. It uses a large scale, service-oriented architecture to handle over a billion calls per day to their video streaming API from over 800 different device types.
Amazon originally had a two-tier architecture. In order to scale they migrated
to a service-oriented architecture consisting of hundreds
of backend services. Several applications call these services, including the
applications that implement the
amazon.com website and the web service API.
amazon.com calls 100-150 services to get the data it uses to
build a single web page.
Microservices have existed for a long time, but their popularity has increased in recent years. Transitioning to microservices from a monolithic architecture is a slow process: it should be done incrementally because it requires a gradual change in the team structure and dynamics, besides the application’s code.
Not every application would benefit from microservices. And some applications are better off growing monolithically to determine which services will be useful to run independently.
But don’t fear the shift to microservices: if they are implemented thoughtfully, they might just save your application as it scales!
Are you shifting from monolithic to microservices architecture? Want to share some tips? Please leave a comment, I’m looking forward to learning from your experience!
I’m attaching some links which inspired me to write this article.