We're getting a lot of requests lately to produce a Microservices course. It's been high up on our (growing) todo list so it will definitely happen, but for some reason I've held off. I think this might be because we've tended to favour courses based on specific tools and concrete techniques rather than high level architectural stuff.
But we're definitely doing it - possibly as a standalone course, possibly spread across multiple videos (the upcoming courses on Messaging in Spring Boot and Wildfly would both be good candidates to contain some microservices, and our series on DevOps would be a good place to cover how to deploy microservices). Or maybe we'll do both, a short course addressing the overall ideas and then we'll apply those ideas in the appropriate courses.
This will happen over the coming months, in the meantime here's a bit of an unstructured exploration of Microservices.
What are Microservices?
Simply put, the Microservice movement is a shift away from the old-school technique of building huge, single applications that have cross business scope (these are commonly known as Monoliths).
As an honest example, our website at VirtualPairProgrammers has been developed as a traditional monolith - a single WAR file containing, effectively, our entire business.
Ok, we're not a huge business. We're not Spotify (yet). It's just a simple shopping cart site I hear you cry! Well, there's a lot more going on behind the web interface:
- Video production (rendering pipelines)
- Video Subtitling
- Newsletter Production
- Customer Lists
- Sales Data
- Viewing Figures
- System Administration
- Support and Ticketing
- International Currencies
- International Business Rules (eg VAT, tax rates)
- The usual CMS stuff (content management)
- Standard eCommerce/Shopping Cart
- Affiliate Management
- Subscriptions billing and re-billing
Probably more. Our marketing manager loves nothing more than shoving in hideous cartesian join SQLs and exports to Excel, because - that's what marketing managers do. It annoys the purist developers who think that their Hadoop based Viewing figures code is so beautiful it should be framed and put in an art gallery - but that's a consequence of running a Monolith - we have different business areas with very different needs treading on one another's toes.
We're not ashamed of this monolith. It made absolute sense in our early days to deploy this as a single WAR file - it was the simplest thing that could possibly work, and work it did, for many years. But today, there's so much complexity in there, it's becoming more brittle over time. A simple tiny change (like a change in the VAT rate for a country) means a full rebuild (taking around 5 minutes) and then a complete reboot of the Java Server (Tomcat in our case).
A move to a Microservice based architecture would see us deploy multiple, small or tiny applications, each aligned to a specific area of the business.
In Part 2 of this series (next week), I'll describe our first steps in migrating this monolith to Microservices. In this blog, I'll talk about the general principles we should be adhering to.
In one sense, there's nothing exciting in Microservices - it's just good software engineering principles.
Loose Coupling / High Cohesion
At the core of Microservices is the same principle that is at the heart of any good software design. Loose coupling in this context means that a single microservice must do ONE thing, and do that ONE thing well. What "ONE thing" means is vague and is down to judgement, but key to a microservice is that it should be aligned to a specific area of the business. I've said that once already, but it's of utmost importance. It's absolutely no use making your Microservices align along tiers - if you have a "Web" microservice and a "Middle Tier" microservice and a "Database" microservice, then you don't have microservices at all - you've got three monoliths with an enormous amount of coupling between them. Which brings me to...
...loose coupling, meaning that the dependencies between the services should be as minimal as possible. In development terms, a change to one microservice should have minimal impact on the other microservices in the overall system. In run-time operations terms, ideally, we should be able to take down an entire microservice with no degradation of the performance of the overall system.
Code Repository Isolation
So at one level a microservice is a simple expression of good software engineering, but it leads to difficult architectural choices. If your system is now a hundred microservices, should you have a source code repository that contains all of the microservices (with the services being in subfolders)? Or would you have to maintain a hundred seprate git/mercurial repositiories?
The answer is separate respositories - if you go with one huge repository, the temptation will be to start doing mega-builds and this will lead to "lock step" deployments where all 100 microservices are deployed at the same time - you therefore have much of the unpleasantness of a monolith. There are in fact many successful Microservice projects that do keep single repositories, this is something of an "ideal" goal, and it's probably not a killer - but it makes sense that services which are deployed independently should also be developed independently.
In a similar vein, is it ok to deploy all of your microservices to a single server/VM instance/EC2 Instance/Azure Thingy?
Ideally a microservice should be deployed onto it's own standalone "instance". Many projects do deploy multiple their microservices to a single machine, but again, this can lead to the temptation of coupling them together, leading again to "lock step" deployment.
This can be expensive, which is where container services such as Docker step in. A container can be thought of as much lighter than a Virtual Machine - a single VM can host multiple containers, each container responsible for a single microservice.
We love Docker at VirtualPairProgrammers, and yes, we will be doing a course on it!
Automate, Automate, Automate
You might be able to put up with the pain of manually deploying a monolith. Or manually spinning up a few Cloud Instances to host it. Or manually installing software onto those instances. Some people like pain, especially if there's a bit of drama involved. Scaling that up to 100 deployments, 1000 instances, forget it. Microservices absolutely depend upon the automation of deployment, of provisioning, of configuration management. Continuous Delivery (http://martinfowler.com/bliki/ContinuousDelivery.html) is a prerequisite.
No Integration Databases
This is my favourite principle of Microservices - there should be no Integration Databases - avoid them at all costs. (For a recap of integration vs application databases, you can watch a chapter from our NoSQL course here).
There will be much wailing and gnashing of teeth over this - the integration database is the most precious possession of many businesses. But a database into which anything can delve in, read and write at will, is both incohesive (ie it captures many different parts of the business, by definition) AND it is tightly (not loosely) coupled (again by definition, as many disparate applications DEPEND upon it).
So it's unarguable really, that integration databases have no part in microservices, it's part of the definition. However, in the real world, expect to see many projects proudly proclaim that they use microservices, of which one "micro"service is the "database service". Which you can't change without the permission of the DBA. Oh look, there's a "Business Logic" Microservice!
These are just my unstructured thoughts about the main ingredients of a Microservice - in part 2 (next week), I'll describe a concrete example of how we at VirtualPairProgrammers are slowly migrating our IT across to a Microservice architecture.