Software applications built using microservices have multiplied rapidly in recent years, and the trend shows no signs of slowing down. A host of tech industry titans, including Netflix, Amazon, eBay, Uber and Comcast, have all written about their experiences working with a microservices architecture. Many in the industry have attributed the swift rise of microservices to the growth of Docker, claiming that microservices would not be possible without relying on Docker containers. But what exactly is microservices architecture and how can microservices benefit your engineering team?
What Are Microservices?
Simply put, a microservices architecture is a software design pattern in which a larger application is composed of multiple smaller services, each with its own objective, that collaborate and communicate over a network in order to achieve a particular goal. Within a microservices architecture, each service runs in its own process and communicates with other processes using a lightweight mechanism such as HTTP/REST with JSON.
The concept of breaking down an application into discrete parts is not a new one. The idea for microservices originates in the broader service-oriented architecture design pattern, in which independent services perform distinct functionalities and communicate using a designated protocol. However, unlike service-oriented architecture, a microservices architecture (as its name suggests) must contain services that are explicitly small and lightweight and that are independently deployable.
Why Use Microservices?
According to the traditional “monolithic” software design pattern, applications should be developed as a single entity. Standard enterprise applications often consist of three parts: a client-side interface that runs in the user’s browser, a database and a server-side monolithic application. This server-side application mediates between the client and the database — handling HTTP requests, retrieving information from the database and assembling the code that will be sent to the user.
Monolithic Architecture vs. Microservices Architecture
While monolithic applications can be appealing, they also present challenges, especially when working in cloud environments. As the application grows in size and complexity, it can be difficult to maintain the original structure and hierarchy, making development messier. The application’s scalability suffers since the entire application must be made scalable — as opposed to only those parts that are under greater demand. In addition, changes and updates to the application require the entire application to be rebuilt and redeployed, which can cost valuable time and effort.
This is one of the reasons microservices have emerged as an alternative design pattern, delivering benefits for project engineering, scalability and performance. Dividing a single application into various components means that each component can be developed and deployed concurrently yet separately. The application can scale more efficiently, as only those components under the greatest load need to be duplicated, rather than the whole application.
Furthermore, the separate components can be distributed among several servers or data centers, allowing for greater uptime than by using a monolithic application on a single machine. If one service stops functioning, it can fail gracefully while the other services continue.
Pros and Cons of Microservices
Before making the transition to a microservices architecture, it’s helpful to know the benefits as well as the potential downsides.
- Separate development and deployment. One service can be developed, built and tested without affecting other services or the entire application. And, because the unit being deployed is smaller, the workflow is generally faster than deploying a monolithic application.
- Scaling and resilience. In a microservices architecture, you can scale only those services that need it, rather than the whole application. By isolating functionalities into different services, the failure of one of the components will not cascade and result in the failure of the others.
- Independent tech stacks. Because each component is separate from all other components, services can use their own technology stacks without having to alter the way the other services or the entire application are built. This makes it easy to try out new languages or tools and to roll back changes. Microservices also enable greater application composability, so you can reuse or repurpose code.
- Difficulty. Distributed systems such as microservices can be difficult to develop. Deploying them can be more complicated than monolithic applications, requiring a detailed script that loads and connects all the various components. Handling requests between services can be tricky in the event of a service that is failing or slow to respond.
- Changes and dependencies. Microservices components use APIs to exchange data, which can create issues and errors when the API itself is changed. In addition, microservices architectures often rely on outside services for functionalities such as load balancing and scaling, putting developers at the mercy of external cloud providers.
- Complex testing and troubleshooting. Testing microservice-based applications can be more complicated due to the increased number of moving parts. Creating use cases that utilize multiple services requires substantially more effort than with a monolithic application.
Microservices and Docker
Because Docker containers are extremely portable and can operate in isolation from one another, it is simple to create a Docker microservices architecture, especially with container management tools such as Amazon ECS. Each of these microservices containers can be run independently, removing the risk of any friction or conflict between languages, libraries or frameworks.
To deploy an updated version of a service, you can simply stop the current container and start a new container based on a Docker image that uses the updated code. Using Docker monitoring tools like Weave Scope give you a real-time view of your containers, reducing the complexity of your microservices-based architecture.