I grew up in the 60's and 70's with Star Trek. In those days you didn't have hundreds of TV channels or many options of things to watch and Star Trek stood out for good reasons. I continue to be a fan today, but the original series is my favourite. So it was with great sadness that I heard of the death of Leonard Nimoy. I watched him in Mission Impossible back then too, but it was as Spock that I'll remember him the most. I thought about how I'd want to put my thoughts down but realised that someone else said it a lot better than I could many years ago.
"We are assembled here today to pay final respects to our honored dead. And yet it should be noted that in the midst of our sorrow, this death takes place in the shadow of new life, the sunrise of a new world; a world that our beloved comrade gave his life to protect and nourish. He did not feel this sacrifice a vain or empty one, and we will not debate his profound wisdom at these proceedings. Of my friend, I can only say this: of all the souls I have encountered in my travels, his was the most... human."
I work for Red Hat, where I lead JBoss technical direction and research/development. Prior to this I was SOA Technical Development Manager and Director of Standards. I was Chief Architect and co-founder at Arjuna Technologies, an HP spin-off (where I was a Distinguished Engineer). I've been working in the area of reliable distributed systems since the mid-80's. My PhD was on fault-tolerant distributed systems, replication and transactions. I'm also a Professor at Newcastle University and Lyon.
Saturday, February 28, 2015
Saturday, February 21, 2015
Microservices
I've been meaning to write up some thoughts I've had on microservices for quite a while but never really had the time (or made the time). However, when I was asked if I'd like to do an interview on the subject for InfoQ I figured it would be a forcing function. I think the interview was great and hopefully it helped to make it clear where I stand on the topic: whatever it's called, whether it's services-based, SOA, or microservices, the core principles have remained the same throughout the last 4 decades. What worries me about microservices, though, is the headlong rush by some to adopt something without understanding fully those principles. Yes there are some really interesting technologies around today that make it easier to develop good SOA implementations, such as Docker, Vert.x and Fabric8, but building and deploying individual services is the least of your worries when you embark on the service/SOA road.
Of course identifying the services you need is an important piece of any service-oriented architecture. How "big" they should be is implicitly part of that problem, though most successful implementations I've come across over the years rarely consider size in terms of lines of code (LOC) but rather business function(s). The emphasis on size in terms of LOC is one of the things I don't really like in microservices - unlike in the scientific world, micro here is not well defined and one persons "micro" could easily be another's "macro".
This brings us to the concept of service composition. Not all applications will be built from atomic (indivisible) services. Some services may be composed of other services. Of course there are different ways of approaching that from an implememtation perspective. For instance, a composite service could just be an intelligent endpoint (service) which acts as a coordinator for remote interactions on the other (constituent) services, such that a client never gets to interact with them directly. Another implementation could be to co-locate the consituent services in the same address space as the coordinator. Of course a good service-based implementation would not allow these implementation choices to be exposed by the composite service API to the client so that implementations could be changed without requiring changes to users.
Some other factors that must be taken into account when considering the "size" of a service or how the constituent services relate to a composite service include:
(i) performance - remote invocations, whether using a binary protocol such as AMQP, and especially text based protocols such as HTTP, are significantly slower than intra-process communication. Therefore, if performance is important and there will be many cross-service interactions, it may make sense to either consider merging services or deploying them within the same address space so that intra-process communication can be used instead. A service does not have to reside in its own distinct operating system process.
(ii) fault tolerance - despite the fact that you may be able to replicate a specific service to try to obtain high availability, there's always going to be a finite probability that your service will become unavailable - catastrophic failures do happen (entropy always increases!) And remember that it may not be possible, or at least easy, to replica some services, e.g., active replication of a service requires the business logic to be deterministic otherwise you need to use a passive replication protocol, which may adversely impact performance to the point of making it unrealistic to replicate in the first place. Therefore, if the failure of a service causes other services to be unusable (no Plan B), it may make more sense to co-locate these services into a unit of failure, such that if one is going to fail (crash) they all fail anyway.
Of course there are a number of other considerations when building applications from services and again we've been addressing them over the years in SOA deployments or earlier with services-based applications. One of the most critical is service (or task) orchestration - rarely is an application constructed from just one service and even if it were, that service may itself be using other services to perform its work. As such, applications are really the flow of control between different services and rarely is this some static a priori determination; the failure of a service may cause the application logic to determine that the next action is to invoke an operation on some other (compensation?) service. But again, as I said earlier, this is something we really should be taking for granted as understood, at least at a fundamental level. Whether or not the microservices community likes standards such as BPMN, the aims behind them or their bespoke implementations, remain and we would be ill advised to ignore. At least if you're going to build a new wheel it's a good idea to understand why the current wheel isn't good enough!
For a long time I wrote about and considered the necessity for SOA governance. In fact even before the term SOA was coined, governance has been a crucial component of any distributed system. Unfortunately it's also one of the most overlooked aspects. As we moved to a more service-oriented approach, runtime and design time governance became more and more important. How do you know the service you're about to use actually offers the right business capabilities as well as the right non-functional capabilities, e.g., can respond within the desired time, is secure, offers transactions etc? Of course there are a number of ways in which these questions can be answered, but essentially you need a contract between the client and the service. Part of the contract will inevitably have to include the service API, whether defined in WSDL, WADL, IDL or something else entirely. These days that part of (SOA) governance is not subsumed within the new term API Management. No less important, just a different categorisation. And microservices needs exactly the same thing because it really doesn't matter the size of a service - it'll have an API and hence need to be managed or governed.
Despite what I've heard about microservices, I really do believe that the existing SOA community had a lot to offer their microservices cousins; we've got to build on the experiences of the past decades and deliver better solutions to our communities rather than think that starting from scratch is the right approach.
Of course identifying the services you need is an important piece of any service-oriented architecture. How "big" they should be is implicitly part of that problem, though most successful implementations I've come across over the years rarely consider size in terms of lines of code (LOC) but rather business function(s). The emphasis on size in terms of LOC is one of the things I don't really like in microservices - unlike in the scientific world, micro here is not well defined and one persons "micro" could easily be another's "macro".
This brings us to the concept of service composition. Not all applications will be built from atomic (indivisible) services. Some services may be composed of other services. Of course there are different ways of approaching that from an implememtation perspective. For instance, a composite service could just be an intelligent endpoint (service) which acts as a coordinator for remote interactions on the other (constituent) services, such that a client never gets to interact with them directly. Another implementation could be to co-locate the consituent services in the same address space as the coordinator. Of course a good service-based implementation would not allow these implementation choices to be exposed by the composite service API to the client so that implementations could be changed without requiring changes to users.
Some other factors that must be taken into account when considering the "size" of a service or how the constituent services relate to a composite service include:
(i) performance - remote invocations, whether using a binary protocol such as AMQP, and especially text based protocols such as HTTP, are significantly slower than intra-process communication. Therefore, if performance is important and there will be many cross-service interactions, it may make sense to either consider merging services or deploying them within the same address space so that intra-process communication can be used instead. A service does not have to reside in its own distinct operating system process.
(ii) fault tolerance - despite the fact that you may be able to replicate a specific service to try to obtain high availability, there's always going to be a finite probability that your service will become unavailable - catastrophic failures do happen (entropy always increases!) And remember that it may not be possible, or at least easy, to replica some services, e.g., active replication of a service requires the business logic to be deterministic otherwise you need to use a passive replication protocol, which may adversely impact performance to the point of making it unrealistic to replicate in the first place. Therefore, if the failure of a service causes other services to be unusable (no Plan B), it may make more sense to co-locate these services into a unit of failure, such that if one is going to fail (crash) they all fail anyway.
Of course there are a number of other considerations when building applications from services and again we've been addressing them over the years in SOA deployments or earlier with services-based applications. One of the most critical is service (or task) orchestration - rarely is an application constructed from just one service and even if it were, that service may itself be using other services to perform its work. As such, applications are really the flow of control between different services and rarely is this some static a priori determination; the failure of a service may cause the application logic to determine that the next action is to invoke an operation on some other (compensation?) service. But again, as I said earlier, this is something we really should be taking for granted as understood, at least at a fundamental level. Whether or not the microservices community likes standards such as BPMN, the aims behind them or their bespoke implementations, remain and we would be ill advised to ignore. At least if you're going to build a new wheel it's a good idea to understand why the current wheel isn't good enough!
For a long time I wrote about and considered the necessity for SOA governance. In fact even before the term SOA was coined, governance has been a crucial component of any distributed system. Unfortunately it's also one of the most overlooked aspects. As we moved to a more service-oriented approach, runtime and design time governance became more and more important. How do you know the service you're about to use actually offers the right business capabilities as well as the right non-functional capabilities, e.g., can respond within the desired time, is secure, offers transactions etc? Of course there are a number of ways in which these questions can be answered, but essentially you need a contract between the client and the service. Part of the contract will inevitably have to include the service API, whether defined in WSDL, WADL, IDL or something else entirely. These days that part of (SOA) governance is not subsumed within the new term API Management. No less important, just a different categorisation. And microservices needs exactly the same thing because it really doesn't matter the size of a service - it'll have an API and hence need to be managed or governed.
Despite what I've heard about microservices, I really do believe that the existing SOA community had a lot to offer their microservices cousins; we've got to build on the experiences of the past decades and deliver better solutions to our communities rather than think that starting from scratch is the right approach.
Saturday, February 07, 2015
Container-less development
In the Java world been hearing a lot lately about container-less development. (Note, I'm not talking about containers such as docker.) Whether it's to help build microservices, to reduce complexity for Java EE developers, or some other reasons, moving away from containers seems to be the theme of the day. One of the core aims behind the movement away from containers appears to be simplifying the lives of application developers and that's definitely a good thing.
In general anything we can do to improve the development experience is always a good thing. However, I worry that the idea of moving away from containers is not necessarily going to make the lives of developers easier in the long term. Let's spend a moment to look at some of the things we've heard as complaints for container-driven development. I'll paraphrase, but ... "They make it too complex to do easy things." Or "Containers are just too bloated and get in the way of agile development." Or "The notion of containers is an anti-pattern from the 20th century." Or even "Testing code in containers is just too hard."
Now before we try to address these concerns, let's look at something I said to Markus in a recent interview. "Any container, whether it's something like docker, the JVM or even a Java EE application server, shouldn't really get in your way as a developer but should also offer you the capabilities you need for building and running your applications in a way that is easy to use, understand and manage. If you think about it, your laptop is a container. The operating system is a container. We take these for granted because over the years we've gotten really really good at building them to be unobtrusive. Yet if you look under the covers at your typical operating system, it's doing a lot of hard work for you and offering you capabilities such as process forking and scheduling, that you don't know you need but you do need them."
It's easy to make blanket statements like "containers are bad for agile development" or "containers are not fit for modern web apps", but the reality is somewhat different. Of course there may be specific examples of containers where these statements are correct, but let's try and remain objective here! As I mentioned to Markus, we're using containers in our daily development lives and not even aware of them most of the time. A good container, whether an operating system or a Java EE application server, shouldn't get in your way but should be there when you need it. When you don't need it, it's sitting in the background consuming limited memory and processor time, perhaps still ensuring that certain bad things don't happen to your application while it's running and which you didn't even consider initially, e.g., how often do you consider that your operating system is providing red zone protection for the individual processes?
As I said, a good container shouldn't get in your way. However, that doesn't mean it isn't needed. Many applications start out a lot simpler than they end up. You may not consider security initially, for instance, but if your application/service is going to be used by more than you and especially if it's going to be available globally, then it's something you're going to need eventually and a good container should be able to either take care of that for you opaquely or offer a simple to use interface. In essence, a good (ideal?) container should be like your favourite operating system - doing things in the background that you need but don't want to really understand, and offering easy to use APIs for those services you do need.
For enterprise users (and I include Web developers in that category) those services would include security, data management (RDBMS, NoSQL), messaging (not everything will communicate using HTTP) and transactions (yes, some people may not like them but they're essential for many types of application to ensure consistency in a local and distributed case). I'm not going to suggest that there's any such thing as the ideal/perfect container in the Java world today. There are definitely some implementations that would want you to consider seriously looking at container-less solutions! However, there are several implementations that have made significant strides in improving the developer experience and pushing themselves into the background, becoming part of the substrate. And a number of developer tools have sprung up to help developers further, such as Forge and Arquillian.
If you consider what lead to the rise of containers, it wasn't because someone somewhere thought "Oh wouldn't it be good if I threw everything and the kitchen sink into a deployment environment". Believe it or not there was a time before containers. Back then we didn't have multi-threaded languages. Everything was interconnected individual services, communicating using bespoke protocols. Your application was probably one or more services and clients, again communicating to get things done. If all of these services ran on the same machine (entirely possible) then once again you could consider the operating system as your application deployment container.
These services were there for a reason though: applications needed them! The development of containers as we know them today was therefore a natural evolution given improvements in language capabilities and hardware performance (reduce the interprocess communication at the very least). Granted we may not have focussed enough on making the development of applications with containers a seamless and natural thing. But that doesn't obviate the need.
Consider the container-less approach. For some applications this may be the right approach, just as we've never said that container-based development (or Java EE) was right for all applications. But as the complexity of the application or individual service grows and there's a need for more functionality (e.g., caching or security) then application developers shouldn't have to worry about which caching implementation is the best for their environment, or which version works well with the other functional components they're relying upon. Eventually container-less frameworks will start to address these concerns and add the "missing" features, whether as interconnected individual (micro?) services in their own address spaces or co-located with the application code/business logic but (hopefully) in an opaque manner that doesn't get in the way of the developer. Once we start down that road we're heading towards something that looks very similar to a container.
Rather than throw away the inherent benefits of containers, I think we should be working to make them even easier to use. Maybe this requires changes in standards, where those containers are based upon them. Maybe it's giving feedback to the container developers on what's getting in the way. Maybe it's working with the container-less efforts to build next generation containers that fit into their development and deployment experience seamlessly. There are a number of ways this can go, but none of them are really container-less.