Microservices are the hottest design concept in programming today. The concept is not new: they basically carry out the principle of modularity taught to programmers over the past several decades. But microservices take modularity to a new height and thereby satisfy many needs of modern application developers.
In this two-part series, I will discuss ten trends in computing during the 21st century—including both challenges and opportunities—that have made microservices the architecture of choice for many organizations:
- The urgency of high availability and quick, flexible scaling
- Classic advantages of modularized programs for development and testing
- The continuing growth of third-party (cloud) compute services
- Cheap, high-capacity networks in data centers
- The dominance of RESTful APIs for interprocess communication
- The convenience of Platform as a Service (PaaS)
- The efficiency of containers for virtual applications
- Applications moving online in Software as a Service (SaaS)
- The productivity of small programming teams
- The race to speed up innovation through DevOps and rapid deployment
The series will help you understand the technologies used in microservices, as well as see how they contribute to today's development environments. The second article in the series will also discuss the challenges created by microservices.
A short posting by LeanIX defines microservices and points to a longer white paper listing the key traits that the authors think are important. Another paper laying out the concept of microservices was written by James Lewis and Martin Fowler. I won't bother to offer another definition. Instead, I'll illustrate the basic idea behind microservices with a business case and return to some of the implementation details as I discuss the ten trends.
Suppose you run an online travel agency. Your strength is offering a complete marketplace for hotels along with flights or train tickets and reservations for cars, bicycles, and scooters at the traveler's destination. Because each type of booking has unique characteristics and calls on you to negotiate with different organizations, you've decided to try a modular approach. (I am not basing this example on a real corporation but inventing the use case to suggest the benefits of microservices.)
In the travel app, one microservice passes dates and other requirements to hotels, getting back from them a list of appropriate bookings and offering the choices to your customer. Another microservice deals with airlines, and another with rail services. You may feed the offerings from airlines and rail services into yet another microservice that performs tasks that airlines and rail services need in common. And you might also create a microservice for car rentals, a microservice for bicycle rentals, and a microservice for scooter rentals, feeding their results into a general microservice that covers local transportation. The grandmother of all your microservices is the customer-facing application: it combines information from all the others and interacts with the customer. This application architecture is shown in Figure 1.
Advantages of microservices for this application include the following:
- Each microservice can manage its own data: data about hotels in the lodging microservice, data about airlines in the air microservice, and so on.
- The team focusing on each microservice can hire people who understand the business requirements (for hotels, airlines, etc.).
- New microservices, such as home-shares or bus lines, can quickly be added.
- Common services can be centralized, while each microservice can be tuned for its unique type of booking.
It might be worth scrutinizing here the relationship between a microservice and an application. To the system administrator and the operating system, each independent instance of each microservice is a separate application, running in a runtime environment consisting of an operating system and supporting libraries. (Current development processes are making these runtime environments leaner and leaner—they are not general-purpose operating systems but just the minimal support needed for the microservice to function.) To our travel company, however, all the microservices are just components of one big application. I'll use "application" in this larger business sense during this series.
Now let's turn to the details of microservices and the needs they're meeting.
Urgency of High Availability and Quick, Flexible Scaling
For several reasons, there is more and more load on online services nowadays:
- There are simply more people in the world, and they are increasingly coming online. In 2020, this trend culminated in a rush to the internet during the COVID-19 pandemic.
- People in general are growing more affluent—despite some persistent poverty and a global income gap—and are therefore purchasing more goods and services.
- Offerings themselves are getting richer and more complex.
Increases in bandwidth and cloud capacity, channeled through the business policies of telecom companies, encourage people to spend more time online and use more services.
Every successful company therefore has to plan for growth that can be rapid at times and with unexpected spikes or drops in demand. No company can afford to ever take down its application, because people may request it at any time of the day or night from different parts of the world. The company may well be holding on to critical data that people need to access.
These requirements call for redundancy, which is easy to achieve by adding copies of microservices and inserting a load balancer. Scaling can also take place incrementally by adding or shutting down instances of a microservice. If some parts of the application need to scale up more than others, the separation between microservices allows fine-grained choices in starting just the services needed at the moment. Unexpected failures can be handled by spinning up new microservices quickly. (Automated initialization, as well as the containers we’ll look at later, allow fast spin-ups.) Finally, the company can upgrade a microservice by creating a new instance that runs new code and then replacing the old instance with a new one.
Advantages of Modularized Programs for Development and Testing
Much of the advocacy for microservices contrasts them with an alternative called the "monolithic application." The advantages that advocates cite for microservices echo the advantages of modular programming over the poorly modularized programs of the 1960s and 1970s, which programmers termed "spaghetti code."
Programmers have been separating activities into functions since the beginning of software, and today's so-called monolithic applications are certainly modularized. But microservices provide many of the same benefits that modules historically provided:
- Different functions can be assigned to different teams and developed independently, each on its own schedule.
- Each microservice has a small, well-defined purpose that is easy to understand.
- Each microservice presents a small set of entry points. It is easy to define strictly what is allowed and what outputs to expect. Side effects are avoided.
- Just as each module traditionally maintains its own internal data structures, avoiding conflicts with the data used by other modules, each microservice works mostly on its own database tables.
- New features can be added to a particular microservice with only a small risk of breaking another microservice.
- Each microservice can be quickly tested without touching other parts of the system. (To do so, teams take advantage of mockers and other tools to set up a test environment that simulates the production environment.)
- Errors can quickly be isolated and diagnosed.
- Different programming languages and libraries can be used for different microservices. Each just has to adhere to the interface defined by the microservice at the other end of the communication.
Conceptually, therefore, microservices apply the lessons of modularization from the early years of software development to our modern times.
Onward March of Third-Party (Cloud) Compute Services
Before the marketing term "cloud" was invented, many companies were turning their computer systems over to third-party data centers. Why worry about air conditioning, power outages, the dangers of rogue administrators, and the headaches of purchasing servers?
Most of those data centers devoted each computer to a particular customer, but some were virtualizing systems pretty early on. With virtualization, a single, powerful chip could run loads from multiple customers, just as the computer on which you're probably reading this article can simultaneously count your steps and display pop-up news notifications. When hardware support for virtualization made it efficient and secure enough, cloud computing advanced rapidly.
Modern, virtualized data centers excellently fulfill the requirements listed in the section "Urgency of High Availability and Quick, Flexible Scaling." The major vendors allow autoscaling and other forms of automation, along with detailed metrics to help you plan growth. Microservices are very likely to run in some kind of cloud setting, even if the cloud is a private one maintained by the organization developing the application.
Cheap, High-Capacity Networks in Data Centers
The internal networks used within data centers and cloud vendors have evolved to handle the intensive communications that take place among microservices. Older data centers were built to handle lots of web requests, and did not put a priority on network nodes communicating internally with each other. The microservice architecture makes heavy use of internal communications, so data centers have changed their cabling and configuration to a model called the Clos network. The new networks are more resilient for today's applications.
Dominance of REST for Interprocess Communication
I'll end this first article in the series with a powerful technology that ties microservices together: REST. I have covered the history and contribution of REST in another article. Basically, REST simplifies distributed computing. An easily grasped concept that is supported by libraries in every modern programming language, REST makes it possible for components in different languages to expose functions and respond to queries from other components. When programmers formed the ideas behind microservices, REST stood ready at hand, as a mature programming practice to carry messages between the microservices.
In the second article of the series, I'll describe the remaining five trends and step back to look at the challenges of programming microservices.