In SOA application modeling there are two basic approaches, end-to-end and hop-by-hop. The end-to-end model is based on an originating sender, a series of intermediaries and a final destination. In the hop-by-hop model each service only knows about the next hop service and nothing more. Below I argue that the end-to-end model inevitably leads to having to create a single protocol that the whole world has to support, requires a painfully sophisticated security model and all but requires that services be tightly coupled. The hop-by-hop model, on the other hand, suffers from none of these problems but does introduce extra latency. On balance I don't believe the benefits of the end-to-end model justify its costs and therefore recommend that service implementers use the hop-by-hop model.
End-To-End Versus Hop-By-Hop
The concept of end-to-end functionality in SOA means that a message will pass from a source service, through a number of intermediary services, to a final service. In the end-to-end model the 'real' communication is between the source and the final receiver, all the other services, the intermediaries, exist for the purpose of adding value to the message before it reaches its final destination. A classic end-to-end scenario is a purchase order being sent to a transformation service intermediary and then to a logging service intermediary and then finally to the actual purchase order processing service.
The alternative to the end-to-end model is the hop-by-hop model. In the hop-by-hop model once one service sends a message to another service the message becomes the receiver's problem. In the hop-by-hop model communication occurs one step at a time rather than the end-to-end model's idea of the communication extending from the source service all the way through the intermediaries to the final service.
For example, let's apply reliable messaging to the previous scenario. In an end-to-end model the reliable message contract would actually be between the source service sending the PO and the purchase service. The intermediaries, the transformation and logging services, are only incidental. This means that the source service will keep around all of its reliable messaging information and state until it receives an acknowledgment from the purchase order service.
In a hop-by-hop model the reliable messaging exchange only exists between each hop individually so there is no state stretching down the entire message chain.
A consequence of the end-to-end model is that the sending service often needs to provide explicit instructions to the intermediaries. So this means that in the end-to-end model one has to have a message format that allows one to target commands to the final service, a specific intermediary and/or to all intermediaries. In other words the original message with the PO would also include a message addressed to the transform service telling it what kind of transformation to implement, a message to the logging service telling it what kind of logging quality to provide and then a message to the final service telling it what to do with the PO. In a sense an end-to-end system requires a linear processing system that lets a set of commands, addressed to different services, to be stacked up inside of a single container message. Each step in the processing path then takes off the part of the message addressed to it, does it's part and then passes on the message to the next service.
In the hop-by-hop model the message handling is typically less sophisticated. The source service would send its PO to the transformation service and get back the result. Then the source service would send the transformed message to the logging service and get back a confirmation. Then the source service would send the transformed PO to the PO processing service. In other words, hop-by-hop systems tend to be hub and spoke based. In the most generic case where large numbers of services are involved there are typically multiple hubs each of which has its own spokes. This hub and spoke design is typical of how enterprise service bus (ESB)'s work. Usually there will be a coordination service inside of the ESB that will be responsible for calling various local services in a specific order, handling errors, etc. before passing the message onto the next (external) hub.
The Cost of the End-To-End Model
One Application Transport to Rule Them All
In the end-to-end model the expectation is that the source service will be able to communicate with both intermediaries as well as the final service. This means that there needs to be a single standard message type that can contain instructions to the intermediaries as well as to the final service. But, just to make things more complex, a common assumption of end-to-end systems is that the various hops a message takes might be over different transports. E.g. one hop could be over HTTP, the next of JMS, the next over SIP, etc. This means that the end-to-end model requires a message format that can survive all the hops and contain instructions to the various intermediaries.
In English what this really means is that the end-to-end model requires that everyone use the same transport protocol. But this is a challenge since people like their transports. But computer science tradition provides a solution – add another layer of abstraction.
First, the end-to-end system introduces its own über protocol that will be tunneled through all the other protocols, let's call this new über protocol SOAP. Of course, we can't rely on HTTP URLs since they may not be available at each hop so let's introduce a new addressing mechanism, let's call it, I don't know, um… WS-Addressing. And of course reliable messaging has to be based on the new protocol format rather than any underlying transport features (e.g. no SOA-Rity). Let's call this new reliable messaging functionality WS-ReliableMessaging.
The end result is that for the end-to-end model to work it requires that the entire world switch to a single transport protocol and treat all other transport protocols as little more than expensive implementations of TCP/IP. The inevitable irony being that in the next round of creation someone will show that SOAP isn't end-to-end in SOA++ (or whatever the next thing is called) and SOAP itself gets encapsulated. But that's another story.
In the hop-by-hop model each communication exists on its own terms and can therefore use whatever protocol best fits its need. There is no requirement to create an über protocol.
In an end-to-end architecture the source services and intermediaries are expected to be aware of other intermediaries as well as the final service and to communicate with those intermediaries directly. In that case one reasonably expects that the source service will have to authenticate itself not just to the final service but also to one or more intermediaries. This was certainly the case with HTTP where clients can authenticate themselves to both a proxy and to the final service.
Ahh but the fun doesn't stop there. Once one accepts the concept of direct intermediary communication then the next step is encryption. Encryption is really fun because in an end-to-end model one can't assume that all the intermediaries and the final service share the same encryption key. So minimally it has to be possible to encrypt the same content multiple times with different keys. To make things even more fun it's likely that some of the intermediaries need to handle content that doesn't need to be encrypted at all. So not only does one need to be able to encrypt data with multiple keys but one has to encrypt pieces of the data so that other pieces can be left in the clear or be encrypted with a different key. Keeping all this in mind suddenly XML DSIG, XML Encryption, WS-Security, etc. start to make sense.
In a hop-by-hop system the general design principle is that each hop only knows about the next hop. So authentication and encryption tend to not extend beyond the next hop. In a hop-by-hop system trust tends not to be across the entire message chain but rather between different systems along the chain. In essence this creates a transitive trust chain where the next hop only worries about trusting the previous hop and recursively backwards to the originating system. Yeah, I too can come up with scenarios where transitive trust is problematic but back in the real world it just doesn't seem to matter terribly often. Even when it does matter usually much simpler solutions like adding an encrypted or signed attachment (rather than inventing a partial message encryption/signature system) will do nicely.
There's also another cost to the end-to-end model that is a bit harder to see. end-to-end is not loosely coupled. The end-to-end model is only useful when a service (either the source or an intermediary) has some knowledge (although certainly not complete knowledge) of what services are ahead of it in the processing path and what their capabilities and supported formats are. This locks in a particular set of protocols and functionalities. If any of the upstream services should change their protocol, format, etc. then the rather than just negotiating the change with the immediately previous service they have to negotiate the change with all downstream services. This puts in place a series of overlapping tight couplings that make it somewhere between difficult to impossible to make any changes to a deployed service.
In the hop-by-hop model each service only communicates with its next service and so changes are localized.
The Cost of the Hop-By-Hop Model
The main cost to the hop-by-hop model is that it depends on using a series of hubs and spokes. This will increase the latency needed to process a request. In the end-to-end model each service just hands a request on to the next service. But in a hop-by-hop model a hub will hand out a request to a service, get back a response, hand it to the next service, get a response, etc. until it is ready to move the message to the next hub who will repeat the whole process. The actual performance penalty is typically not that high however because usually the services around a spoke are co-located so the extra round trip time isn't very high.
The end-to-end model certain has advantages in terms of performance and sophisticated security scenarios but the question one has to ask is – are these advantages worth the price of having to enforce a mono-culture protocol, introduce mind numbingly complex security models and implement a tightly coupled system? Based on my own experiences with various service based models and having lived through the last few years of WS-* I can't but conclude that the end-to-end model cost more than it's worth and therefore recommend that implementers adopt the hop-by-hop model. Simplicity, it seems, has much to recommend it.
7 thoughts on “SOA and the End-To-End Morass”
Interesting! A few observations…
The terms “end-to-end” and “hop-by-hop” are, IME, most commonly used to refer to individual protocol features, not as a choice made by a message sender, as in general, I don’t think there’s many scenarios where a choice exists to use one or the other. It simply depends what needs to be accomplished. For example, if a message sender used a transfer(!) protocol with no end-to-end features, then it would have issues getting past many firewalls (that weren’t configured as transparent proxies). But what you call “hop-by-hop” is more commonly referred to as a “gateway configuration” where the (SOAP) intermediary terminates the message, while end-to-end is commonly referred to as a “proxy configuration” (or “surrogate”).
You didn’t cover the trust issue differences either. The end-to-end/proxy model isn’t suited to crossing trust boundaries, while hop-by-hop/gateway is, for the reasons (layering) very similar to why source routing is evil.
I agree with the point about the proxy configuration requiring the same transfer(!) protocol at each hop, but when that’s what’s required – as it often is – the world has shown little hesitation in adopting protocols such as HTTP pervasively. You call it a “mono-culture”, I call it standardization on the next layer of the stack. Perhaps you’d like to bring Banyan or SNA back, just to avoid the TCP/IP mono-culture? 8-)
In the specific case of machine-to-machine communication (which is my focus) there is indeed a fundamental decision that has to be made between configuring the communication chain with an expectation that it will be possible for services earlier in the chain to communicate to arbitrary services farther down the chain or hop-by-hop where communication is only possible to the next hop and any communication farther down the chain has to occur as a consequence of the application protocol design. It is this fundamental decision that I draw the reader’s attention to. Implementers must choose ahead of time which design they wish because it will control the architecture of all their protocols.
End-to-end requires all the complexity of the SOAP intermediary model and the complexity of XML DSIG/Encryption while Hop-by-hop works just fine with plain HTTP and HTTP Auth/SSL.
I though I had directly addressed the security/trust issues in the “security headaches” section where I call out the same point. That in hop-by-hop you just need to trust the next hop (and implicitly all the hops before you) but in end-to-end you have to provide authentication and possibly encryption for some or all of the hops ahead of you which requires some very sophisticated protocol formats.
As for going back to Banyan or SNA, actually it’s interesting because in fact we do not have a TCP/IP mono-culture. UDP is still very much alive and well because it serves a different purpose than TCP/IP. Similarly IPv4 did not, in fact, turn out to be the grand solution and so has necessitated the introduction of IPv6.
That’s the thing about the ‘one protocol to rule them all approach’ it always breaks. The world changes, needs change and any protocol that can do everything in the end turns out to do it all badly. Today our ‘monoculture’ transport stack already consists of at least four different combinations (IPv4/IPv6 & TCP/UDP) and that’s not even including different approaches to multicast, transport security (IPSec vs SSL), etc.
In the end there is no doubt in my mind that there does not exist and never will exist an uber protocol for all application protocol needs. One can already trivially see, for example, why one would want both HTTP and SIP (for similar reasons to why one would want both TCP and UDP).
It’s actually kind of funny to be having this argument about one application transport protocol because it was HTTP that taught me the importance of assuming you will get it wrong. That was the key behind HTTP’s extensibility model and part of the reason why I think it has been so successful. It assumes that its current design is wrong and leaves lots of room to change it in a backwards compatible way.
In the same way whatever application transport becomes most popular (and in my opinion today this is a no-brainer choice, HTTP is the best option) it will be shown to be inadequate for many key scenarios (e.g. SIP) and it will eventually be replaced.
So, yes, I am positive, there will be more than one.
Machine-to-machine is also my area of interest.
“That in hop-by-hop you just need to trust the next hop”
That wasn’t my point, because I disagree with that. It’s quite the opposite, in fact. You have to trust the next hop in end-to-end, while with hop-by-hop, you do not because the message is addressed directly at that node; all the sender cares about is its proper delivery, not what happens after. In end-to-end the sender has an interest in the whole chain of intermediaries up to the terminating node.
Anyhow, all I’m saying is that some problems lend themselves to end-to-end/proxied configurations, while others lend themselves to hop-by-hop/gatewayed configurations. I also agree that if I had to pick one, it would be hop-by-hop because it’s more flexible (IME). Luckily though, I don’t.
As for HTTP as uber protocol, I don’t believe that if “uber” means “good for everything”. I see it as good for most things you might want to do with documents. Certainly everything currently being done with Web services.
I’m also confident it will eventually be replaced. But it’s replacement will be a better designed (more general, more efficient) data transfer protocol, not SOAP, not BEEP, nor any other non-application protocol.
P.S. odd choice of counter-examples with SIP, seeing as it was basically a cut-and-paste of HTTP with some extensions 8-)
Sorry the ‘next hop’ was a typo.
But I realized that even my original sentence didn’t quite capture what I wanted to say. In a hop-by-hop system if a service is hop N then it can validate N-1 and N+1 but it will have to trust that N-1 properly validated N-2 and so on and in the same way it will have to trust N+1 that it will properly validate N+2 and so on.
This is different than end-to-end where it’s possible to directly validate all the forward hops.
But the key point I want to make in the article is that the infrastructure for end-to-end is significantly more complex and cumbersome than for hop-to-hop and therefore if people need end-to-end functionality they have to know that and provide for it up front.
If you need end-to-end then you either have to use WS-* (or some similar system that has all the machinery needed to make end-to-end work) or you have to re-invent those parts of the machinery you need yourself and make sure that all of your partners do the same.
My thesis then is that end-to-end rarely adds enough value to justify the clanking machinery it requires.
I actually don’t think HTTP is good enough for everything being done with Web Services. An area Web Services is getting more into is notifications and that is an area where SIP has a very definite advantage.
I also agree that when HTTP is replaced it won’t be with SOAP or BEEP. I don’t know what will replace it but thankfully the lesson from HTTP is that you can’t know the future so just make sure to leave the door open. :)
And the choice of SIP was quite intentional. It’s relationship to HTTP is in many ways similar to TCP’s relationship to UDP. Although, I think one can plausibly argue that in this metaphor HTTP is UDP and SIP is TCP since SIP’s asynchrony and routing capabilities make it more sophisticated than HTTP.
As an architect/program manager type a lot of my job is helping people to communicate with each other. More often than not this involves detecting when two intelligent people are disagreeing not because they have conflicting technical views but because they are using the exact same term to mean two different things and are therefore talking past each other.
Mr. Gall’s comments is, I believe, a classic example of this phenomena. Mr. Gall refers to the terms ‘end-to-end’ and ‘hop-by-hop’ in the sense used in the transport protocol world.
But this article is about SOA which comes from the application protocol world. It turns out that the terms ‘end-to-end’ and ‘hop-by-hop’ have different meaning and radically different architectural ramifications in the application protocol world than the transport protocol world.
Section 13.5.1 of RFC 2616 (the definition of HTTP/1.1), http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.5.1, provides the definition of end-to-end and hop-by-hop as it is commonly used in the application protocol world.
That the same terms used in two different contexts have two different meanings is unfortunate but not unexpected.
This situation reminds me of a quip attributed to everyone from George Bernard Shaw to Winston Churchill that America and England are “Two nations separated by a common language”.
Yaron, Sorry for the brusqueness of my original comment. You obviously know a lot about protocols, both application and transport. Nonetheless, I still think (a) you are misusing the terms E2E and HBH in a confusing way, and (b) wrong in your general criticism of E2E protocols.
As for (a), I don’t see how your citation to RFC2616 supports your position. First, it doesn’t explicitly say, as you do, that the meaning of E2E in the application layer is different from the meaning of E2E in the transport or network layer. I’ve never seen any such distinction made in any of the E2E discussions or readings I’ve done. Can you point me to ANY paper that explicitly makes this distinction?
Second, the use of E2E in RFC2616 is completely consistent with the original (or as you put it “transport”) use of the term. “End-to-end headers” are simply headers that must be sent intact from source to consumer, so that these two “endpoints” can properly process them. Here is the definition from RFC2616: “End-to-end headers, which are transmitted to the ultimate recipient of a request or response.” There is no requirement that intermediaries must “understand” them in any way. This use of e2e supports my position that e2e refers to functionality implemented solely at the endpoints at least as well as it supports your position that e2e refers to functionality that all intermediaries must understand (“a consequence of the end-to-end model is that the sending service often needs to provide explicit instructions to the intermediaries”).
Accordingly, unless you can point me to an authority that explicitly discusses the reason for inverting the meaning of E2E and H2H, I’d advise you to NOT invert their meanings between the transport level and the application level.
As for (b), while a protocol with an explicit, first class, intermediary architecture is more complex than one that simply assumes a direct (unmediated) connection between endpoints, it is definitely worth the complexity. For example, HTTP global success would not have been possible without the intermediary architecture specified in RFC2616. Your argument against protocols based on explicit intermediaries would appear to argue against the architecture of HTTP, arguably one of the most successful protocols in history. How do you explain this exception to your rule?
Furthermore, contrary to your argument, a protocol with an explicit intermediary architecture does not entail that “the sending service often needs to provide explicit instructions to the intermediaries.” Intermediary models may allow for the “transparent” addition of instructions (in the form of headers) by intermediaries, without the knowledge of the endpoints. For example, it is perfectly appropriate for a pair of SOAP intermediaries to encrypt/decrypt a SOAP envelop “in flight” using WS-Security without the two endpoints knowing anything about it.
To sum up, there are several widely successful examples of protocols with explicit intermediary architectures, e.g., HTTP, SIP, SMTP. Are there any widely successful examples of your proposed HBH or Hub and Spoke protocol? Some examples might shed some light on this debate.
Nick, I think you ask some good questions so I tried to give some good answers – http://www.goland.org/endtoend