January 30, 2017
The term “Microservices Architecture” is now a popular trend. Unlike many trends, this one seems to have some momentum and is more about how people are developing services versus vendors commandeering and needlessly complicating something simple. For example, SOA started off as a rather simple set of concepts and became something vast and complex. Services are excellent. Web Services are good. SOA has a bad reputation and is associated with being overly complicated (WSDL, BPEL, WS-blah, etc.). Microservices is not SOA. In fact, it in many ways it is directly the opposite. For example, SOA often embraces WSDL which is a very strongly typed and rigid way to define a service endpoint. WSDL and XML schema takes all of the X out of XML.
There is no concrete definition of Microservices Architecture, but there are certain thematic aspects in its application. Just like some things are hard to define, but you know when you see it. The focus on Microservices is a focus on business capability, and a refocus on object oriented programming roots and organizing code around business domains with data and business rules co-located in the same process or set of processes. Microservices attempt to deploy independent services with bounded contexts.
To adopt the Microservices style is to recognize that the world is polyglot programming, and the easiest integration is around JSON, HTTP and other web standards like WebSocket. Microservices embrace smart endpoints and dumb pipes. A Microservices Architecture embraces JSON and tolerant readers with the idea that the interface may change a bit and it is nicer to allow some flexibility in what properties/fields make up a message.
A smart endpoint and a dumb pipe would be the opposite end of the spectrum than something like BPEL and ESB style of development does or other orchestrations mechanisms for SOA. While SOA embraces services being stateless, Microservices embrace the need for state and embrace OOP fundamentals of keeping your business logic and data together.
Before you roll your eyes and buck against the goad, realize that words have power. People were doing Ajax before it was called Ajax. Giving something a name helps guide its evolution and development. People were doing NoSQL before the industry coined the term, but the ideas were compelling, and in many ways Microservices is a term like Ajax and NoSQL, it is a post adoption name for what people are mostly already doing to a certain extent. Many concepts exist in Microservices that you find with systems like Akka, 12-factor deployments and even principles of high-speed systems (LMAX white papers come to mind).
“Microservices” - is a powerful term. It is one you need to embrace. It is very pragmatic. It is likely that you have been doing some or all of what Microservices Architecture is already. One day Microservices will go the way of Ajax, it will be so common it will be a forgone conclusion. Microservices is about pragmatism, not vendors raising barriers to competitors by creating overly complicated specifications.
We need to define Microservices a little more formerly, so it does not go the way of SOA and every vendor gets to form a committee and dishonor its intentions with a set of nifty shiny baubles. SOA was a huge success and a failure. A failure because the term has no meaning or rather so many meanings, and yet Amazon and Google’s version of SOA are a huge success. Look at successful things that we had to call SOA, and those are probably more like microservices and plain web services.
From here on out, when I refer to SOA, I am referring to the big enterprise WSDL, SOAP, stateless, course-grained, BPEL, ESB vendor lovefest that is SOA, not the useful SOA implementations. Good SOA is called web services and is HTTP calls, REST and WebSocket. SOA is the quagmire mentioned above.
One thing well principle and fallacy of the monolith
Continuous delivery: The microservices architectural approach is to create smaller services focused on a small business domain or crosscutting concern. Microservices adopt the Unix single purpose utility approach to service development. They are small, so they can be released more often and are written to be malleable. They are easier to write. They are easier to change. Microservices go hand in hand with continuous integration and continuous delivery. The services are independent enough not to need a large release train to release improvements or new features. In the Java world, this means you will be using other microservice like Jenkins to provide frequent releases.
Do not try explaining the microservice style by comparing it to the monolithic application. No one ever set out to purposely build a huge monolith, and a monolith is not a three-tiered web application. Yes monolithic applications happen. But comparing microservices to a huge unmaintainable monolithic application is like comparing agile development to not having any process.
The huge unmaintainable monolith was never an architecture style. It is usually a mistake. Collection of technical debt absorbed by a development team when the product team goes off the rails. Also even if someone was building a large web application, it is often the case (ok not that often) that they broke their code up into modules and have internal services that might be easier to break off into service and then one day microservices. If their application is a big ball of spaghetti code, then that has nothing to do with lack of microservices or them trying to develop a monolithic, their process, training, and culture is the issue. And it probably has a lot to do with product pressures and process.
The first issue I have with calling something a monolith which gives it a negative connotation is that what you are really describing is a web application in the context of most discussions of microservices, and not a true monolith. If you have a successful web application and it is getting so large that you have to break it up into many web applications or services, this is a good thing. You have what we call a successful application. There are tools that simplify writing basic web applications like Rails, Grails, Django, some PHP framework and their ilk. These are great tools. Better to have a successful application that is a monolith than not deliver business value. But even successful application reach a limit in size where it becomes harder to deliver new features and the release train gets larger and larger. This is where breaking things into microservices can really help.
There is nothing wrong with the basic web application. If your application is growing larger in features and functionality than you expected then using these tools to create a basic web application might be the wrong approach or you may have to go off the rails with these tools and start breaking features off into services and perhaps microservices. If you know that many of your clients are going to be mobile clients and you have potentially hundred thousand or 1 million users then these tools are probably the wrong approach event to start with. If you’re writing a department level application and these tools are exactly the right approach and you may not need to use microservices. Don’t be dogmatic. In the end, the goal is to provide business value and ROI for your company, not impress your friends at the next JUG meeting. Not every tool or architecture fits every application.
Not every application has scalability concerns or the same types of scalability concerns. A microservice may benefit greatly by using some of these monolithic tools and frameworks to provide admin visibility and diagnostics into the microservice. Don’t throw the baby out with the bathwater. It’s all about engineering trade-offs and knowing what are the driving factors that are going to form your architecture. Sometimes this is an easy thing to do. Other times you have to write that first version, get it going and then come back and revisit the architecture. Microservices are a great approach for many things, and increasingly so with disparate clients, cloud and mobile, but don’t let the tail wag the dog.
Enterprise Applications flashback
Microservices and NoSQL are two trends that are more focused on how to address software development where deployments are increasingly cloud-based and clients are increasingly mobile-based. Just like you can’t compare client/server development of the mid-90s to mainframe development from the 70s, you can’t compare enterprise applications from 2001 to microservice development targeting mobile and web clients and other microservices in 2015. The world changes. We adjust. Microservice trend is course correction not a new religion.
History of Enterprise Applications
Remember 1990s, the reason why Enterprise Applications are written with three tiers was was to avoid DLL hell, and the monolith. We just did it with the tools available at the time. Back in the day, we used to build apps that were two tiered. You had to actually go to each users machine and help them install the app. There was a damn good chance they downloaded some shareware that installed a DLL that screwed up the install, and you were in hell. It was not like we were, “Hey James!”” .. “What Martin?” “Do you want to build a huge monolith?” “Sure Martin!”“.
Microservices exists since mobile, cloud, cheaper RAM, cheaper disks, and improved virtualization. It is just taking the world where it is. It is not revolutionary at all.
Server components, EAR files, and WAR files.. may they rest in peace
If you have lived through COM, DCOM, CORBA, EJBs, OSGi, J2EE, SOAP, SOA, DCE, etc. then you know the idea of services and components is not a new thing, but they are a date expired concept for the most part. One issue with enterprise components is they assume the use of hardware servers which are large monoliths and you want to run a lot of things on the same server. This was before AWS and modern cloud computing. This is why we have WAR files and EAR files, and all sorts of nifty components and archives. Well turns out in 2017, that makes no sense. Operating systems and servers are ephemeral, virtualized resources and can be shipped like a component. We have AWS, ECS, EC2 images AMIs, OpenStack, Vagrant and Docker. The world changed. Move on.
Microservices just recognize this trend, so you are not developing like you did when the hardware, cloud orchestration, multi-cores, and virtualization was not there. You did not develop code in the 90s with punch cards, did you? So don’t use an EAR file or a WAR file in 2015.
Now you can run a JVM in a Docker image which is just a process pretending to be an OS running in an OS that is running in the cloud which is running inside of a virtual machine which is running in Linux server that you don’t own that you share with people who you don’t know. Got a busy season? Well then, spin up 100 more server instances for a few weeks or hours. This is why you run Java microservices as standalone processes and not running inside of a Java EE container.
The Java EE container is no longer needed because servers are not giant refrigerator boxes that you order from Sun and wait three months for (circa 2000). Don’t fight classpath, classloader hell of Java EE. Your whole OS is now an ephemeral container (Docker). Deliver an image with all the libs you need, don’t deploy to a Java EE server which has to be versioned and configured. You are only running one service in it anyway. Turns out you don’t have five war files running in the same Java EE container since about 2007. Let it go.
If you are deploying a WAR file to a Java EE container, then you are probably not doing microservice development. If you have more than one WAR file in the container or an EAR file, then you are not doing microservice development. If you are deploying your service as an AMI or docker container and your microservice has a main method, then you might be writing a microservice.
Microservices architectures opt to break software not into components but into reusable, independently release-able, small services which run as one or more processes. Application and other services communicate with each other. So where we might have used a server side component, we use a microservice running in independent processes. Where we might have had WAR files or EAR files now, we have a Docker container or an Amazon AMI that has the entire app preloaded and configure with exactly the libraries it needs (Java and otherwise).
JSON, HTTP, WebSocket … NO WSDL!
Now you just have to document the Microservices HTTP/JSON interface so other developers can call it. We could say REST, and certainly, you can use concepts from REST, but hey HTTP calls are enough to be considered a Microservice.
Keep this in mind: No XML. No SOAP. No WSDL. No WADL. JSON! Ok, you can add some meta data and document how to talk to your service, but the idea is the docs should be documented with curl. If you are only using SOAP or XML, then you are not producing a microservice. JSON is a must. (Although swagger seems to be a JSON version of WSDL.)
Documents should sound more like: I give you this request with these headers, params and JSON body and you respond with this JSON. Keep it simple. You can provide things in addition to JSON, but JSON is the minimum requirement. If you are not delivering up JSON and consuming JSON over HTTP or HTTP WebSocket then what you wrote is probably not a microservice.
Call speed, non-blocking calls
One of the issues with remote calls is speed. This is why you will want to organize services around a domain that will help keep the data for that service with that service and it will not need to interact with other services or a foreign database every time it gets a request for its data. While remote calls are expensive this can be accommodated for by using async calls, batching, and WebSocket/JSON (Reactive Programming Microservice Java Lib). Remember WebSocket allows bi-directional communication. For speed, you should prefer RPC calls that are non-blocking and can be sent in batches (POST or WebSocket). If you are able to handle requests in streams in an async manner and utilize the hardware efficiently, then you might be doing microservices development.
Another approach for increasing remote call speed is to go all SOA on your API and focus on coarser-grained responses, but this is almost always a mistake. You can write coarser-grained HTTP APIs so more is delivered with each call. This is a problem because it is harder to write and use coarser-grained HTTP APIs as they often conflate many subdomain data in the same call in the name of speed and aggregation. It is easier to batch many smaller calls and create service aggregators. You will need to do both batching and aggregation of domains (coarser grained). Dumb fast pipes and batching calls (turning them into streams) are a good indication that what you wrote is a microservice. Some call this style reactive programming and reactive programming goes hand in hand with microservices. They are intrinsically related.
Depending on scalability needs services may need be sharded. While a service runs in a single process for scalability, the service may be running in many processes on many virtual machines. Microservices are not stateless. Microservices should own their data. Data ownership may mean a private database. Data ownership may mean using a data lease model for elasticity. Or a private database shard per sharded service. We will talk more about this later when we talk about high-speed microservices.
If your service is getting all of its data from a database that is shared by one or more web applications, or other services or other applications, then you did not write a microservice. If your service is 100% stateless, then what you wrote is probably not a microservice.
Microservices do not negate the need for having libraries. If you are making many calls to a microservice, there is an indication that you maybe needed a library instead of a microservice. Adopting microservice architecture does not make you a better systems engineer. You will need some common sense, systems knowledge or a very good perf testing regiment. Many will fail and go back to a traditional three tier, web development version of services or some form of enterprise SOA or write a more traditional stateless web service.
Microservice, Process, DevOps
Conflating Microservices is bad. There is a point in the discussion where people conflate a lot of ideas from other pet projects or pet processes and shove that into the microservice realm. Let’s not. Something that has so many definitions tends to get diluted and meaningless.
Concepts like DevOps, continuous delivery, continuous integration, cloud computing, agile processes etc. are compelling in their own right. You don’t need to have an Agile, DevOps, Cloud setup to start getting benefits from microservice development. Indeed, they complement each other. Don’t combine them as one concept. Microservices has a lot more to do with cloud, virtualization, OS containerization, etc. then it does agile development vs. RUP. 12 factor deployment are also used for Microservices as is Docker but Microservices is not Docker or 12-factor deployment. CI and CD work really well with Microservices and vice versa but Microservices is not CI/CD.
The idea of the cradle-to-grave development of an application or service is not an idea that was invented in the early or late 2000s. Hiring software developers that were also systems engineers and responsible for software development, load testing, testing, and deployment is not a new concept to me at all. This is a recurring concept that I have seen in my 25-year career over and over. It is the more rare concept and one that I find completely dysfunctional where the developers tossed something over the wall to QA and ops to deploy.
Smart endpoints and dumb pipes: Actors, Reactive and Active Object
Enterprise Service Bus (ESB), and vendor driven SOA is a bad idea. It is one you hear a lot of talk about but you never see actual successful deployments of. Complex message routing, choreography, transformation, and applying business rules willy nilly and providing a graphical representation of your overly complicated runtime software process is a horrible idea. I am not saying it is never needed. You can, do and will need to integrate with legacy applications and tools like Camel et al can help, but you should not start designing your system from scratch around ESBs and Camel. It is a necessary evil at times. But evil none the less.
Yes wrapping legacy “monolithic” or yesteryears CORBA, DCOM, TPS, expensive message bus, from a high-priced vendor in SOA and ESB or even good old “REST” is sometimes needed, but that does not mean that you get to redefine microservices into it. Microservices is not legacy integration. Microservices is how you develop greenfield services in 2015. It is not a legacy turd polish like SOA and ESB. (Even if sometimes you do need legacy turd polish.)
You know where a good place to store your business logic, code. Business people almost never, never, never change business rules on the fly because if they did that would be like editing code and would require testing or production would go down. This is not to say that there are not real use cases for things like Drools. This is to say Drools and Activiti are the exception not the rule. You know who is good at changing business rules in code and making sure production does not go down, your software development team. All developers prefer smart endpoints and dumb pipes because BPEL, Activiti, WS-Choreography or BPEL or orchestration are hard to test and maintain. If you have ever had the joy of maintaining or trying to grok a big mass of spaghetti, you realize that creating cool, neato tools around legacy integration batch jobs does not make them easier to comprehend or maintain.
JSON, HTTP, WebSocket work everywhere. This technolgies work in browsers. They work from Python, Ruby, Perl processes. They work from Java. They work from PHP web applications. They work in all mobile clients. They are the least common denominator, and they are simple to read and understand and document. Pick them first.
Web Services are great. Vendor-driven SOA orchestration and ESBs are a nightmare to debug. Not all Web Services should be microservices. But you should have a strong and compelling reason for using SOAP/WSDL/Vendor SOA.
Developers the world over prefer to use protocols that the world wide web and Unix are built on. The protocols and tools are simple to grok. Operationally predictable. Easy to cache even with third parties like Akamai and tools like Varnish. Prefer Unix cron jobs, web monitoring, cloud, etc. to ESB. Sometimes a batch job is just a batch job. Wrapping it in ESB or making a Map/Reduce cluster might make you feel more important, but is it providing business values. Sometimes it is. More often than not, it is misapplied tech. Not every batch job needs to be a Hadoop Map/Reduce or ESB orchestration, sometimes they can just be batch jobs that are kicked off by cron (or AWS Lambda). (ESBs and Hadoop are needed. I am not anti-ESB or Map/Reduce).
You invoke micro services through HTTP and WebSocket or some form of messaging (like Kafka or Kinesis). You should prefer HTTP and WebSocket and only use messaging (with MOM) if you want durability or want the ability to mine that data. WebSocket is lightweight messaging. It is supported by all programming languages, mobile platforms and the web and it exists today. 0MQ, RabbitMQ, JMS, Kafka are all great if you need some level of durability or speed or the ability to mine the calls later or split the calls for real-time analytics. If you do not, then WebSocket should be enough for 70% of your needs and has some added benefit of being reachable from web clients (and Kafka or Kinesis for the rest).
The message bus delivers an opaque message, so you will need to encode the message in a universally understood format, which usually ends up being JSON. There are times when you may need something faster and binary JSON-like formats abound (binary should be the exception, JSON is as fast as most binary formats, and faster than many). If something is available via a message bus call, then it should also be available via an HTTP/JSON call (REST). If you can’t exercise your service API via curl and have it return JSON, then you did not write a microservice.
With tools like Akka, QBit, Reakt, Vertx, Kafka, etc. the concept of an event bus or a message bus or streaming messages or streaming calls exists as core concepts to the async invocation model which is essential for microservices. Messages can be handled at first in-process by a service, as more scale is needed, those messages can be batch/forwarded to other nodes. You can write services internal to your application which are somewhere between a library and a microservice which can one day be more readily broken out into actual microservices. Reactive, Actor and Active Objects embrace the concepts of streams, message queues and event busses. They are a natural fit for a microservice architecture.
Batching of messages, back pressure based batching, are used to send courser grained messages over the wire which can minimize the performance loss of moving services to processes running on other machines. Since Akka, Finagle, QBit and Vertx support in-proc services and out of proc services using the same underlying interface to a dumb pipe, it is easier to move services in-proc or out of proc (microservice) as performance needs dictate.
If you are making a lot of blocking calls, then what you wrote is not a microservice.
Tool-stacks, polyglot programming languages
Standards are great that is why there are so many of them. Attempts to standardize on technology platforms are often thwarted by using vendor products, merging with other companies, buying companies, adopting new mobile platforms, constant churn of new client frameworks and platforms, etc. Microservices Architecture embraces polyglot programming languages and programming languages. This is where microserver HTTP/WebSocket and JSON/tolerant readers come into play as it provides a minimal pipe and format to support change and polyglot of programming languages.
Services own their data
Databases are used for reporting and offline analysis. Service stores (which could use a database), is for a service or a service shard. Operational data and reporting / historical / backup data should be split up. Operation data for a service should only be editable by that service.
Microservices architecture is back to OOP basics. Objects, services when you expose them remotely, own their data and business logic. Each service stores data and models data in its view of the world. Data is specific for its service. This is not a new concept. This is basic OOP.
In additional evidence of going back to OOP roots and domain-driven development, microservices own their data storage. Data ownership could mean a database or key/value store on the same docker node as the JVM running the service (which gets replicated and backed up of course). Microservices do not use a shared database for operational data. A micro-service might fallback to a shared database if data is not in the service, but this would be the exception, not the rule.
If someone thinks that Microservices are stateless it is ok to roll your eyes at them. A Microservices service edits data, and it may replicate it, shard it, and use eventual consistency to back that data up, but it owns the data and it and it alone can edit its data. If that is not what you wrote, then you did not write a microservices. In-memory computing, eventual consistency, replication, fit nicely with microservices. Remember RAM is the new disk, and the hard drive or SSD is the new tape backup. True speed is when you can edit your data without first checking to see if you have the latest copy from the database that sits on another server.
Service Discovery - Design for Failure
In addition to automated deployment, virtualization, and cloud orchestration/automation, microservices use microservices service discovery and microservices monitoring to recover from failure and to spread load across more nodes. The ability to discover service nodes, and adding them into the mix is called elasticity. This includes monitoring of services, detecting failures and removing unhealthy nodes out of the mix (and replacing them). Adding additional services into a running system.
A key component of microservices architecture is reactive programming, which is an async programming mode, and the ability to use back pressure to fail gracefully if the load surpasses the capacity of a node rather than having a cascading failure.
If your service under unexpected load becomes unresponsive then you did not write a microservice. If your service under load, throws error messages and tells clients it is under too much load, and you can spin up new nodes, and the nodes can discover each other (service discovery) and live another day, then you wrote a microservice. Microservices are resilient and elastic.
Reactive Microservices Architecture also know as just Microservices!
By the original definition of microservices, all microservices are reactive. A microservices that is not reactive is akin a bird without wings or a fish who can’t swim.
The Reactive Manifesto outlines qualities of Reactive Systems based on four principles: Responsive, Resilient, Elastic and Message Driven.
Responsiveness means the service should respond in a timely manner, and never let clients or upstream services hang. A system failure should not cause a chain reaction of failures. A failure of a downstream system may cause a degraded response, but a response none-the-less. A key ingredient to be responsive is the ability to handle back pressure and involves systems that are async and handle requests in streams of requests/messaging. If you framework is blocking, then any sort of responsive is usually bolt-on, which is less the ideal when dealing with microservices.
Resilience goes in line with responsiveness, the system should respond even in the face of failure and errors in a timely fashion. It can respond because it can detect an async response is not coming back in time and serve up a degraded response (circuit breaker). It may be able to respond in spite of failure because it can use a replicated version of a failed downstream node. Failure and recovery is built into the system. Monitoring and spinning up new instances to aid in recovery may be delegated to another highly available resource. A key component of resilience is the ability to monitor known good nodes and to perform Service Discovery to find alternative upstream and downstream services. The key to resilience is to avoid cascading failures. Failures should be isolated. Failure isolation is called bulkheading. Resilience is the ability or self-heal and/or the containment of failure. This is why traditional blocking frameworks do not do well with resilience as the strong coupling of synchronous communication does not fit at all with microservices.
Elasticity works with resilience. The ability to spin up new services and for downstream and upstream services and clients to find the new instances is vital to both the resilience of the system as well as the elasticity of the system. Reactive Systems can react to changes in load by spinning up more services to share the load. Imagine a set of services for a professional soccer game that delivers real time stats. During games, you may need to spin up many services. On non-game times, you may need just a few of these services. A reactive system is a system that can increase and decrease resources based on demand. Just like with resilience, Service Discovery aids with elasticity as it provides a mechanism for upstream and downstream services and clients to discover new nodes so the load can be spread across the services.
Message Driven: Reactive Systems rely on asynchronous message passing. This established boundaries between services (in-proc and out of proc) which allows for loose coupling (publish/subscribe or async streams or async calls), isolation (one failure does not ripple through to upstream services and clients), and improved responsive error handling. Having messaging allows one to control throughput (re-route, spin up more services) by applying back-pressure and using back pressure events to trigger changes to shape traffic through the queues. Messaging allows for non-blocking handling of responses. A common messaging platform to use with microservices is Kafka. Akka is an actor system that works well with distributed messaging and often gets used with microservices (Akka Microservices), and Reakt and QBit are two Java centric reactive libs and microservices libs respectively.
A well-written microservice should always apply the principles of the reactive manifesto. One could argue that a microservices architecture is just an extension of the reactive manifesto that is geared towards web services.
There are related subjects of reactive programming and functional reactive programming which are related to the reactive manifesto. A system can be a reactive system and not use a reactive programming model. Reactive programming is often used to coordinate asynchronous calls to multiple services as well as events and streams from clients and other systems.
An example: Client calls Service Z. Service Z calls Service A and Service B, but sends back only the combined results of Service A and Service C. The results of Service B are used to call Service C. Thus Z must call A, B, take the results of B and calls C, then return A/C combined back to the client. And, all of these calls must be asynchronous, non-blocking calls, but we should be able to handle errors for A, B or C, and handle timeouts such that the Client does not hang when Z calls downstream services. The orchestration of calling many services requires some sort of reactive programming coordination. Frameworks like RxJava, Reakt, Akka, RxJS, etc. were conceived to provide an Object Reactive programming model to better work in an environment where there are events, streams and asynchronous calls.
References and related links
- Bla Bla Microservices Bla Bla by Jonas Boner
- Reakt streaming and promise lib to do async call coordination and circuit breakers
- QBit Microservices Lib for Java
- Akka Consulting and Akka Training
- Kafka Consulting and Kafka Training
- What is Microservices Architecture?
- Reactive Microservices
We hope you enjoyed this article. Please provide feedback. Cloudurable provides Kafka training, Kafka consulting, Kafka support and helps setting up Kafka clusters in AWS. Cloudurable also provides Spark training, and Spark consulting.
Check out our new GoLang course. We provide onsite Go Lang training which is instructor led.Tweet
AWS Cassandra Database Support
Kafka Support Pricing
Cassandra Database Support Pricing
Advantages of using Cloudurable™
Cloudurable™| Guide to AWS Cassandra Deploy
Cloudurable™| AWS Cassandra Guidelines and Notes
Free guide to deploying Cassandra on AWS
Kafka Tutorial PDF