Rick

Rick
Rick

Friday, March 20, 2015

Java Microservices (Edit 3)


The term "Microservice Architecture" is now a popular term. Unlike many trends this one seems to have some momentum and is more about how people are actually developing services versus vendors commandeering and needlessly complicating something simple.

There is no concrete definition of Microservice Architecture but there are certain aspects that are thematic in its application. The focus on Microservices is a focus on business capability, and a refocus on object oriented roots and organizing code around business domains with data and business rules co-located in the same process or set of processes.

Microservices 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.

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 end point. A Microservices embrace 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 end point and a dumb pipe would be the opposite end of the spectrum than something like BPEL and ESB provides 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. Read the SOA manifesto, and read the wikipedia page on SOA, try to do the exact opposite and you are a good ways down the road of adopting a Microservice architecture. Shun statelessness and embrace sharding, replication, eventual consistency and service data ownership. Shun WSDL and embrace JSON. 



Microservice doubters

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 it evolution and development. People were doing NoSQL before the term was coined, but the ideas were powerful, and in many ways Microservice is a term like Ajax and NoSQL, it is a post adoption name for what people are mostly already doing to a certain extent.  

”Microservices” - is a powerful term, but it is one you need to embrace. It is likely that you have been doing some or all of what Microservice Architecture is already. One day Microservice 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 complex 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 actually 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 microservices.


Microservices support mobile clients well

In the Java world, microservices has a special meaning. Besides Android, which uses the language formerly known as Java 1.6, Java on the client is dead or very insignificant. One of Java’s many roles is a platform for building services for mobile devices and web clients. This is another reason to embrace a common, flexible, HTTP standards based communication mechanism, because one of the biggest consumers of services are mobile apps, and web apps. Web Apps are thicker than before. Mobile apps might be written as Web Apps and / or have components that run in both the mobile platform and a pure browser play. This is not new. This is an ongoing trend. The idea of a pure monolithic application web application written in Java is a dinosaur. It became infeasible somewhere between 2008 and now. Java services can be the MC in the MVC world but Swift, JavaScript, ObjectiveC, Android, own the clients. Clients are getting fatter which means services are getting thinner. This is a major driving force in microservice proliferation. 


One thing well principle and fallacy of the monolith


Continuos delivery: The microservice architectural approach is to create smaller services that are 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 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 gigantic 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 monolith is like comparing agile development to not having any process. The huge monolith is not 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 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, and not a 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. 

There is nothing wrong with the basic web application. If your application is growing a lot 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 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. 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 application has scalability concerns or the same scalability concerns. A microservice may benefit greatly by using some of these tools 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.

Enterprise Applications

While it is true Enterprise Applications are often built with a three tier architecture: backend code, database code and a GUI written in HTML/JavaScript. This has more to do with the world changing than an active choice. Cloud, EC2, proliferation of mobile devices, cheaper memory, more virtualization, more cores, SSD, trend towards fatter clients, 10 GBE, 100 GBE, etc. made this style obsolete to a certain extent at least for large applications. It is not like we one day came up with a better idea, and then one day we were like hey what if we could make our code more modular. The ground changed under our collective feet. The way we build, deploy, and consume has changed. Hardware evolved. Virtualization evolved. Cloud computing became a real thing. The smart phone /  tablet / mobile revolution happened. Microservice is the response to these external events. 

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. You can’t compare client / server development of the mid-90s to mainframe development from the 70s either. The world changes. We adjust. Microservice trend is course correction not a new religion. 

History of Enterprise Applications

Remember the reason why Enterprise Applications are written with three tiers was was to avoid DLL hell. 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!”.

We tried Applets but Java GUI development back then sucked. I don't think it sucks so bad now, but it lost its window of opportunity for adoption. Then we were left with HTML/JavaScript clients and forcing everyone to use the same browser in the corporation at least for the corporate apps.  There are many reasons why this style of “Enterprise Development” does not work in the cloud and for mobile devices. The server-side application no longer need to handle HTTP requests,  get data from a database and execute all domain logic, and draw pretty pictures in HTML. Much pain, and great expense has been incurred trying get this three tier architecture to scale in the cloud for various devices written in a polyglot of languages. 


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. That is why we have WAR files and EAR files, and all sorts of nifty components and archives. Well turns out in 2015, that makes no sense. Operating systems and servers are ephemeral, virtualized resources and can be shipped like a component. We have EC2 images AMIs, OpenStack, Vagrant and Docker. The world changed. Move on.

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. 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 form Sun and wait three months for. Don’t fight class path, class loader hell of Java EE. Hell you whole damn OS is now ephemeral. 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 oh 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 definitely 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 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 we have a Docker container or a 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 into 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. 

Documents should sound more like: I give you this request with these headers 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 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. Remember WebSocket allows bi-directional communication. For speed, you should prefer RPC calls that are non-blocking and can be sent in batches.  

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 are a good indication that what you wrote is a microservice.

Depending on scalability needs services may need be sharded. While a service runs in a single process for scalability that service may really be running in many processes on many virtual machine. Microservices are not stateless. Microservices should own their data. This may mean a private database. Or a private database shard per sharded service. We will talk more about this later. To learn more about how to scale microservices check out high-speed microservices. To learn more about what a Java microservice looks like read rise of the machine. If your service is getting all of its data from a database that is shared by one or more web applications, and/or other services and/or other application, then you did not write 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 and/or a very good perf testing regiment. Many will fail and go back to a traditional three tier, web development version of services. 

If you are making a lot of blocking calls, then what you wrote is not a microservice. 


Microservice, Process, DevOps

This 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. I think 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. Certainly they complement each other. The idea of 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 and deployment is not a new concept to me at all. This is a reoccurring 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. I feel the strong urge to tell you a lot of antidotes for my career so I have pinched myself very hard, snapped my red suspenders and yanked the hair of my white beard to resist.


Smart endpoints and dumb pipes: Actors, Reactive and Active Object 

Enterprise Service Bus (ESB), and vendor driven SOA is a bad idea. It 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 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. 

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 demo ware bullshit. 



JSON, HTTP, WebSocket work everywhere. They 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. 

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 very strong and powerful 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. Because it is simple to grok. Operationally predictable. Easy to cache even with third parties like Akamai and tools like Varnish. 

You invoke services through HTTP and WebSocket or some form of messaging. You should prefer HTTP and WebSocket and only use messaging if you want durability. 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. If you do not, then WebSocket should be enough. 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. 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, then you did not write a microservice.

With tools like Akka, QBit, Vertx, etc. the concept of an event bus or a message bus exists as core concepts to the async invocation model. 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 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, 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. 



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 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, 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. 

In addition of going back to OOP roots and domain objects, microservices own their data storage. This could mean a database or key value store on the same docker node as the JVM running the service. 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. 

Service Discovery - Design for Failure


In addition to automated deployment, virtualization, and cloud orchestration/automation, microservices use service discovery and service 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. Removing unhealthy nodes out of the mix. 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. 




No comments:

Post a Comment

Kafka and Cassandra support, training for AWS EC2 Cassandra 3.0 Training