main website home
  • About this blog

    This blog features updates, opinions, and technical notes from Caucho engineers about Caucho products, the enterprise Java industry, and PHP. Caucho Technology is the creator of the Resin Application Server and the Quercus PHP in Java engine. A leader in Java performance since 1998, Caucho is a Sun JavaEE licensee with over 9000 customers worldwide.
  • Tags

    ajaxworld bam candi cdi cloud cluster comet configuration deploy devoxx eclipse ejb embedded flash flex google app engine hessian hmtp ioc java ee 6 javaone javazone jms messaging newsletter nyjug osgi php pomegranate quercus resin resin 4.0 REST servlet sfjug silicon valley code camp spring testing training tssjs watchdog webbeans web profile websockets wordpress
  • Meta

    • Register
    • Log in
    • Entries RSS
    • Comments RSS
    • WordPress.org
« Resin 4.0 Security
Friday Meeting Summary, Jan 16 »

HMTP - Hessian Message Transport Protocol

Resin triad cloud

I’ve put together a brief description of HMTP, including a definition of the low-level wire protocol (skip to the end). This post includes the core messages, and tomorrow I’ll add the pub/sub presence and subscription messages.

Resin 4.0 uses HMTP for all of its internal clustering and deployment communication. We’ve organized Resin 4.0 clustering capabilities as services which communicate using HMTP/BAM. Because HMTP/BAM provides routing and addressing for the services, and supports unidirectional messaging as well as RPC, our services have the flexibility they need.

Because HMTP is based on Hessian, it keeps Hessian’s advantages:

  • Object oriented - serializes and deserializes Java objects
  • Language independent - e.g. Flash, Objective-C, etc.
  • Binary - supports binary data efficiently like sending files (very important for our caching and deployment)
  • Compact and fast

HMTP/BAM adds routing/addressing to Hessian, simplifying our services by providing a layer on top of TCP/HTTP routing. Our services don’t need to worry about connecting to other services, because HMTP/BAM handles the links itself.

All Resin services in a cluster have a unique name like “cache@baa.app-tier.admin.resin”. The “cache@” is the service name. “admin.resin” is a virtual host suffix for the current Resin domain. “app-tier” is the cluster, and “baa” is the server within the cluster. So “baa.app-tier.admin.resin” is the 2nd server in the app-tier cluster.

jids: addressing

HMTP uses a jid for addressing and routing. Because the jid looks like a mail address, it’s familiar (”cache@aaa.app-tier.resin”), and because it includes the virtual host, service name, and resource, it’s flexible enough to handle all our addressing needs. The resource id identifies a specific connection, like an iPhone login “ferg@hmtp.caucho.com/my-iPhone-1″.

Hessian payloads: object-oriented messaging

Because all HMTP payloads are objects serialized by Hessian 2.0, they inherit the Hessian 2.0 advantages: type-safe, language-independent, compact, fast and binary.

The type-safety of the Hessian payload is critical for HMTP/BAM since service methods are dispatched based on the Java class of the payload.

@Message
void startup(String to, String from, StartupMessage msg)
{
  ...
}

Core Packets: Messaging and RPC

Six packets form the core of HMTP, covering both unidirectional messaging and RPC-style method calls:

  • message - unidirectional message
  • messageError - unidirectional error message
  • queryGet - RPC query for information (no side effects)
  • querySet - RPC action (produces side effects)
  • queryResult - RPC result for queryGet and querySet
  • queryError - RPC error for queryGet and querySet

Message: unidirectional message

message ::=
            int      # type: code = 0
            string  # to: jid, e.g. "cluster@aaa.app-tier.resin"
            string  # from: jid, e.g. "cluster@baa.app-tier.resin"
            object  # value: Serializable payload, e.g. StartMessage()

MessageError: unidirectional message error

Services may optionally use MessageError to return error information for a failed message. Unlike QueryError, MessageError is optional, defined by the service protocol layered on HMTP. A service protocol might never send a MessageError, e.g. for a high-performance pub/sub service where dropped message might be expected for heavy loads.

messageError ::=
            int      # type: code = 1
            string  # to: jid, e.g. "cluster@aaa.app-tier.resin"
            string  # from: jid, e.g. "cluster@baa.app-tier.resin"
            object  # value: Serializable payload, e.g. StartMessage()
            object  # error: com.caucho.bam.BamError

QueryGet: query RPC

QueryGet is an RPC query for information, similar to a HTTP GET. Like HTTP GET, it may not perform any action or change persistent state, it is used for information only.

A service MUST reply to a QueryGet packet with either a QueryResult or QueryError. It must never ignore a QueryGet packet, because the caller might be blocking waiting for a result. If the server doesn’t recognize the jid address or if the service doesn’t recognize the payload, it much send a QueryError back.

The RPC packets are coordinated with a correlation id, a 64-bit integer which must be unique for any outstanding requests. The service must send the QueryResult or QueryError with the same id and swap the to and from arguments.

queryGet ::=
            int      # type: code = 2
            string  # to: jid, e.g. "cache@aaa.app-tier.resin"
            string  # from: jid, e.g. "cache@baa.app-tier.resin"
            int      # id: RPC correlation id to match queryResult
            object  # value: Hessian payload, e.g. GetCacheEntry()

QuerySet: action RPC

QuerySet is an RPC action, similar to a HTTP POST. Like HTTP POST, it may perform an action or change persistent state.

A service MUST reply to a QuerySet packet with either a QueryResult or QueryError. Like QueryGet, each call must have a matching reply. And like QueryGet, tThe RPC packets are coordinated with a correlation id, a 64-bit integer which must be unique for any outstanding requests. The service must send the QueryResult or QueryError with the same id and swap the to and from arguments.

querySet ::=
            int      # type: code = 3
            string  # to: jid, e.g. "cache@aaa.app-tier.resin"
            string  # from: jid, e.g. "cache@baa.app-tier.resin"
            int      # id: RPC correlation id to match queryResult
            object  # value: Hessian payload, e.g. PutCacheEntry()

QueryResult: RPC result

QueryResult is a reply to a QueryGet or QuerySet call, using the same correlation id as the call, and swapping the to and from addresses. The QueryResult (or a QueryError) MUST be sent as a response, even if the payload is null.

queryResult ::=
            int      # type: code = 4
            string  # to: jid, e.g. "cache@baa.app-tier.resin"
            string  # from: jid, e.g. "cache@aaa.app-tier.resin"
            int      # id: RPC correlation id to match queryGet
            object  # value: Hessian payload, e.g. CacheEntryResult()

QueryError: RPC error

QueryError is an error reply to a QueryGet or QuerySet call, using the same correlation id as the call, and swapping the to and from addresses. The QueryError or a QueryResult MUST be sent as a response, even if the payload is null.

The BamError contains information about the error. For example, the jid to might not exist, or the service might not understand the payload type, or it may reject processing, or it may simply fail.

queryError ::=
            int      # type: code = 5
            string  # to: jid, e.g. "cache@baa.app-tier.resin"
            string  # from: jid, e.g. "cache@aaa.app-tier.resin"
            int      # id: RPC correlation id to match queryGet
            object  # value: the Get or Set payload, e.g. GetCacheEntry
            object  # error: the BamError with error information

Conclusions

The key concepts underlying HMTP/BAM are the following:

  • symmetrical: all peer agents serve as services, including logged in clients. So clients are services which may receive and process messages and RPC calls. With the exception of connection establishment and login, there are no true “clients” in HMTP, all are peer services.
  • jid (mail) style addressing: HMTP/BAM is responsible for routing
  • typed payloads: services dispatch methods based on the payload types, not method names like traditional RPC
  • unidirectional and RPC style packets are core to the protocol

Although messaging and RPC calls are the core packets, HMTP includes packet types for managing publish/subscribe lists and handling instant messaging presence announcements. Tomorrow, I’ll describe the pub/sub and presence packets.

This entry was posted on Monday, January 19th, 2009 at 12:12 pm and is filed under Engineering. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

Leave a Reply

You must be logged in to post a comment.


Caucho Technology is proudly powered by WordPress and Quercus®
Entries (RSS) and Comments (RSS).

  • HOME |
  • CONTACT US |
  • DOCUMENTATION |
  • BLOG |
  • WIKI 4 |
  • WIKI 3 |
  • Resin: Java Application Server
Copyright (c) 1998-2012 Caucho Technology, Inc. All rights reserved.
caucho® , resin® and quercus® are registered trademarks of Caucho Technology, Inc.
resin® is a cloud optimized, java® application server that supports the java ee webprofile ®