« Camel Case | Main | Type Negotiation In Hessian »

Hessian Type Negotiation: Protocol Flow

In a previous installment I discussed the motivation behind an extension to the Hessian binary web services protocol. That article demonstrated the efficiency gain of adding explicit type negotiation to the protocol. The goal of this article is to have a deeper look into this extension from a protocol flow perspective.

Protocol Flow

The following diagram shows the general flow of the protocol:

In this scenario the following steps are taken:

  1. Peer 1 sends an instance of the type referenced by m not knowing whether Peer 2 has any knowledge of this type reference;
  2. Peer 2 does not have this reference so it requests Peer 1 to resend this type definition;
  3. Peer 1 resends the type definition;
  4. Peer 2 processes the encoded data it received in step (1) with the type information it received in step (3);
  5. Peer 1 continues to send subsequent instances of type m to Peer 2.

The important aspect of this negotiation is that it is effectively session-less, because the sender does not have to care whether or not the receiver is already in possession of the relevant type information. This simplifies the state the sender has to maintain. This can also be very useful if the sender broadcasts a message to multiple receivers (for example, in a publish-subscribe scenario) or if the sender is totally decoupled from the receiver (for example, in a broker-based messaging scenario).

It does, however, require the receiver to be able to query the sender. This may seem impossible at first glance in certain scenarios, for example, when using http as a transport mechanism or when using a messaging broker. However, there are practical solutions to both:

  • With http you can use the response to encode the query, just as you would if you were to encode a protocol fault in the reply;
  • Using a messaging broker, you can define an end point to send type queries to. This scenario makes it even easier for the client to selectively consume based on its knowledge of the type references.

Type Specification

The previous article coined the term "encoding scope" to describe the context within which a type reference can be made. Implicitly, the Hessian 2 protocol confines this to one leg of a request/response cycle. One approach to achieve type negotiation is to simply expand the scope transmission beyond each request/response cycle.

Because you can implement a simple counter to key your known types on, you can benefit from the compact integer encoding available in Hessian 2. Whilst this approach may be quite efficient in terms of the wire size, it does force the sender to maintain the coherency of the type references that is sends.

Another approach would be to compute a small hash value over each type and just send that hash value in place of the type definition that is currently being sent in Hessian 2. Then, within each cycle, you can reference that hash value in exactly the same way that you currently reference a preceding type definition in Hessian 2. The advantage of this approach is that the hash function is idempotent and so relieves the sender of having to maintain the coherency of its references over time and across multiples receivers.

The hash would not necessarily need to be cryptographically secure, it could just be a 32-bit hash such as a Jenkin's Hash.

This is a small trade-off to the variant where you just widen the transmission scope, because you would probably be resending a 4 - 5 byte hash per type per request/response cycle, whereas with the widened scope you could implement it so that it averages 1 - 2 bytes per type per cycle.

So you lose 3 - 4 bytes per type per cycle on average.

But you gain more simplicity overall, because the type keys will be idempotent thus making the protocol more robust.

This relative inefficiency could be mitigated in object graphs containing multiple types. In Hessian 2, every nested instance of a complex type contains a type reference. This is theoretically redundant because, if you had type information for the entire graph up front, you could potentially omit the type reference from every nested object instance, thus reducing the overall wire size but still retaining idempotency.

Conclusion

This protocol suggestion demonstrates a mechanism to avoid resending redundant type information whilst retaining idempotency of key generation. This represents a pragmatic trade-off between efficiency and robustness in the protocol definition.

Posted on Monday, March 3, 2008 at 08:09PM by Registered Commenter0x6e6562 in | CommentsPost a Comment | References1 Reference

References (1)

References allow you to track sources for this article, as well as articles that were written in response to this article.

Reader Comments

There are no comments for this journal entry. To create a new comment, use the form below.

PostPost a New Comment

Enter your information below to add a new comment.

My response is on my own website »
Author Email (optional):
Author URL (optional):
Post:
 
Some HTML allowed: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>