An increasingly common buzzword in cloud computing is microservices. Like a lot of things associated with cloud technologies, a precise definition is difficult to find -- and it can mean a lot of things to a lot of different people, depending on the context. Since this is a blog devoted to middleware issues, I want to define microservices within the context of that middle layer in computing, for application development.
Microservices is an architectural approach for a software system. Meaning, it defines how individual services fit together and how those services are constructed (like, general constraints or best practices). What sets microservices apart from other architectural approaches is that it treats each service as a discrete and independent part of the architecture. That means that services themselves (within that system) have very clear definitions:
- A single, clear purpose
- Well-defined parameters
One of the keys to a microservice is 'loose coupling' within the overall architecture. A service only really has to interact with a direct upstream service (where it consumes data) and its direct downstream service (which consumes the data it sends). The only connective tissue between services is the messaging service (which is itself a microservice). Communication is done with simple, standard protocols, like posting JSON or YAML data to a REST API. The underlying services could be written in entirely different languages or even be frequently replaced by different services. Even the content of the messages themselves can change or can cover a variety of languages and data formats. Microservices is an architecture, not a specific product or technology or language. It is the way you do something, not the thing that you are doing.
However, that approach to the software architecture has a ripple effect because it can influence other aspects of a software rollout. Microservices are frequently conflated with technologies like containers or with development processes like agile. Again, microservices architecture is neither a technology nor a process in and of itself. But the outcome of a microservices architecture is a set of choreographed services which are modular, lightweight, and decoupled from other services.
A contrast to other architecture styles could be its own post (and will be one day). For defining microservices, however, some idea of the two major software architectures can help show what microservices isn't.
Some software was designed (or, really, evolved) into a monolithic architectural style. All services are essentially features of the same product, and the relationships between those services could be tight. In some designs, those services were tightly coupled; in Java EE, there could be modular monoliths, where there were clear separations between tiers, but the the packaging was coupled.
That monolithic software could be very complex, millions of lines of code. Object-oriented programming, and object-oriented languages like Java, introduced some measure of modularity, to break up the code into saner (and reusable) chunks. But that modularity initially only applied to how the code was written. It was still compiled into a single package or a set of packages that were tightly associated with each other; services were subsumed into the greater whole.
The next step was to create services (or clusters of services) separately but with using a clearly defined, centralized schema. This is service-oriented architecture. The services are technically independent, but they used the same internal logic, so there wasn't much flexibility how any individual service could be designed or when it could be delivered -- it had to adhere to potentially brittle schema and any major changes could crash the entire architecture.
With microservices, the services (functionality) itself is independent. The only requirement is that the individual pieces can talk with each other. As an architecture, even the micro part of microservices can be defined according to the need of the overall infrastructure -- one design may have (for example) all monitoring-related functions could be defined in a single service while another may have separate monitoring, alerting, notification, and metering services.
Microservices and Process
One thing that a microservice architecture isn’t (necessarily) is a process like agile. You can obviously do agile programming on monolithic software or develop microservices using a waterfall process -- but there is an organic association between microservices and agile-style processes.
The natural constraints of monolithic and service-oriented architectures were reflected in common development approaches.
- All services had to be developed according to the same schedule and delivered at the same time.
- All services had to be updated or replaced at the same time.
- Any enhancements a single service required updating all services (even if there were no changes to those other services).
With that much complexity in the development process, any changes had to be well planned out in advance, all services had to be tested simultaneously, and rollouts had to be done in an atomic and controlled way.
That meant that, naturally, IT departments, software developers, and executives adopted long planning and testing cycles and infrequent updates to minimize risk to the system. This fits a waterfall style approach.
By moving to a microservice architecture, the risk to the overall system of updating a single service is reduced. Services no longer need to be developed simultaneously, nor released at the same time. It is simpler to release smaller changes or to add new functionality and to iterate through changes. This allows for more rapid development styles, like agile and continuous integration / continuous delivery.
Microservices and Technology
Another thing a microservice architecture isn’t (again, necessarily) is containerized. Containers are virtualized divisions in the kernel of the operating system. Each container is isolated from any other container, and the container only has available resources like libraries that it uses, making a container very lightweight.
Because a microservice is a single service and containers host a single application, it is easy to assume that they are directly related. But, again, a microservice is an architectural choice first, not a specific technology.
For application development, microservices are well-suited to run in containers, but they can also run effectively in any distributed system. This distributed system can be fatjars within the Java space or it could be containers (especially with orchestration systems like Kubernetes. It also could mean a modular application server like Red Hat JBoss Enterprise Application Platform which has distributed services. Distributing the system allows services to be placed on appropriate hardware (e.g., putting services with heavy loads on systems with high CPU and memory) and locating services near to consumers.
Fitting Architecture to Needs
A microservice architecture has a lot of advantages, especially by increasing the delivery cadence, potentially increasing both security and quality. It can provide more flexibility in languages across stacks. It can also introduce more operational agility, such as the ability to scale or move services independently.
It’s not a perfect system, though. While the code complexity for a single service may be reduced, the overall complexity of the design is increased because it is a distributed system. This also introduces complexity in processes by potentially siloing development teams. It can make it more difficult to design and implement massive changes to multiple services, even as incremental changes are easier. And some basic tasks like monitoring and logging -- which are centralized and relatively straightforward in monolithic architectures -- can be difficult in more distributed microservices.
A microservice architecture is a tool. The requirements of the software, the abilities and culture of your IT team, and the availability of related services are all considerations in whether a microservice architecture would be an effective tool for a specific situation.