Re: [hybi] Multiplexing in WebSocket (Was: HyBi Design Space)

Jamie Lokier <jamie@shareable.org> Wed, 14 October 2009 00:15 UTC

Return-Path: <jamie@shareable.org>
X-Original-To: hybi@core3.amsl.com
Delivered-To: hybi@core3.amsl.com
Received: from localhost (localhost [127.0.0.1]) by core3.amsl.com (Postfix) with ESMTP id 7D46828C12B for <hybi@core3.amsl.com>; Tue, 13 Oct 2009 17:15:33 -0700 (PDT)
X-Virus-Scanned: amavisd-new at amsl.com
X-Spam-Flag: NO
X-Spam-Score: -1.999
X-Spam-Level:
X-Spam-Status: No, score=-1.999 tagged_above=-999 required=5 tests=[BAYES_00=-2.599, J_CHICKENPOX_31=0.6]
Received: from mail.ietf.org ([64.170.98.32]) by localhost (core3.amsl.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id ZQRwNcNTvVk8 for <hybi@core3.amsl.com>; Tue, 13 Oct 2009 17:15:32 -0700 (PDT)
Received: from mail2.shareable.org (mail2.shareable.org [80.68.89.115]) by core3.amsl.com (Postfix) with ESMTP id 5723E28C129 for <hybi@ietf.org>; Tue, 13 Oct 2009 17:15:32 -0700 (PDT)
Received: from jamie by mail2.shareable.org with local (Exim 4.63) (envelope-from <jamie@shareable.org>) id 1MxrWc-0007OP-J6; Wed, 14 Oct 2009 01:15:30 +0100
Date: Wed, 14 Oct 2009 01:15:30 +0100
From: Jamie Lokier <jamie@shareable.org>
To: Graham Klyne <gk-ietf-hybi@ninebynine.org>
Message-ID: <20091014001530.GB22806@shareable.org>
References: <4ACE50A2.5070404@ericsson.com> <3a880e2c0910081600v3607665dp193f6df499706810@mail.gmail.com> <4ACF4055.6080302@ericsson.com> <Pine.LNX.4.62.0910092116010.21884@hixie.dreamhostps.com> <4AD2E353.8070609@webtide.com> <4AD2F43D.6030202@ninebynine.org> <4AD39A64.4080405@webtide.com> <4AD4482B.3030705@ninebynine.org>
MIME-Version: 1.0
Content-Type: text/plain; charset="us-ascii"
Content-Disposition: inline
In-Reply-To: <4AD4482B.3030705@ninebynine.org>
User-Agent: Mutt/1.5.13 (2006-08-11)
Cc: "hybi@ietf.org" <hybi@ietf.org>
Subject: Re: [hybi] Multiplexing in WebSocket (Was: HyBi Design Space)
X-BeenThere: hybi@ietf.org
X-Mailman-Version: 2.1.9
Precedence: list
List-Id: Server-Initiated HTTP <hybi.ietf.org>
List-Unsubscribe: <https://www.ietf.org/mailman/listinfo/hybi>, <mailto:hybi-request@ietf.org?subject=unsubscribe>
List-Archive: <http://www.ietf.org/mail-archive/web/hybi>
List-Post: <mailto:hybi@ietf.org>
List-Help: <mailto:hybi-request@ietf.org?subject=help>
List-Subscribe: <https://www.ietf.org/mailman/listinfo/hybi>, <mailto:hybi-request@ietf.org?subject=subscribe>
X-List-Received-Date: Wed, 14 Oct 2009 00:15:33 -0000

Graham Klyne wrote:
> These applications are essentially channel-free, being more 
> datagram/message/event oriented than session oriented, using some kind of 
> global identifier space (e.g. URIs) for disambiguation where needed.

That *is* multiplexing.

There is some confusion about what multiplexing is about.  It
has nothing much to do with sessions.

I think this is what multiplexing (in BWTP etc.) is about:

  - Multiplexing is about delivering messages to addressable targets.

  - Messages that cannot be received or processed immediately should
    not block reception of other messages which _can_ be received
    immediately.

  - Large messages should be usable, without blocking small messages
    for a long time.

  - So that multiple message sources and targets can share TCP/IP
    connections efficiently and easily.  (And eventually, to do the
    same over SCTP/IP which is theoretically a better fit).

Multiplexing is *not* about:

  - Establishing lots of byte sessions or channels (whatever you want
    to call them), although that could be an optional additional feature.

The reason multiplexing protocols talk about channels is:

  - So that messages can be transmitted without blocking all
    other messages.  The protocol creates a channel for *every*
    (unordered) message, so they can be transmitted in parallel
    according to optimal transport strategies.

The reasons for parallelism are:

  - To allow large messages alongside smaller messages without blocking
    everything.

  - To allow message sinks (receivers) to continue receiving messages
    while other sinks are not in a state ready to receive or process
    more messages.

I think that's confusing matters, because channels of a kind are
involved in the protocol, but they are used primarily to allow
independent messages to flow efficiently, and don't need to be visible
above the protocol layer.

There are uses for channels visible to applications too, but
multiplexing is not especially about that.

> No, I'm not, but I'm also prepared to consider using multiple TCP 
> connections in such circumstances.  Typically, I've seen requirements to 
> put up to about 5 different semi-independent widgets on a page.

I've seen 3000. :-) Of course it's always possible to rewrite code so
it works differently.  But that seems opposite to one of the design
goals: to make it easy for independent application implementor tbo
send messages between their components.

> I could imagine server-to-server BEEP being used to tunnel multiple
> WebSocket sessions over a single connection - and here, the
> complexity of BEEP might be justified.

BEEP is a poor fit for this.  We've looked at the details.

It appears to be faster to multiplex messages over HTTP long-polling
than over BEEP under some circumstances.

BEEP is connection-oriented, and has expensive connection setup, which
makes it quite unsuitable for sending independent messages to
independent targets without blocking.

> >But multiplexing can be much much simpler.  At it simplest,
> >it just needs a channel id in each frame and the channel creation
> >can be automatic.   In the BWTP protocol proposal, I've added
> >a little bit of channel creation exchange, so as to well match
> >the explicit life cycle events of the websocket API.
> 
> I guess that I'm not convinced that you can make multiplexing much simpler 
> than BEEP and not end up being broken.  When I reviewed BEEP a few years 
> back, I thought about trying to avoid the complexities of per-channel flow 
> control, but in the end I couldn't see any way of doing that without 
> running the risk that one channel could starve all the others.  But with 
> per-channel flow control comes the need for some quite complex buffering 
> arrangements.

You do need flow control, and yes buffering can be tricky.

I would say per-message flow control, rather than using pre-assigned
channels, if you have no need of channels.  I regard BWTP's channel
creation exchange as a weakness if you must use it.

But here's the mistake: If there isn't flow control in the protocol,
you _must_ implement flow control and buffering in another layer
instead - or get the problems you'd expect.

In WebSockets discussions, flow control tends to be *hidden* in things
like unspecified DOM event queue behaviour's relationship with the
TCP/IP socket.

For example, if a web browser receives hundreds of WebSocket frames of
different sizes before the Javascript can process the corresponding
DOM events, at what point does the browser stop reading from the
TCP/IP socket?  Does it ever stop reading, or does it lead to
out-of-memory conditions on some clients if the server is transmitting
faster than the client script is reading?

If a browser implementation of WebSockets _does_ make use of TCP/IP
flow control by stopping reading from a socket when it has too many
queued DOM events, what happens when a Javascript target is ready for
events to most targets, but cannot process events to one addressable
target right away because that target is busy?  Does it freeze the
whole web page until that single target can process the messages
queued to it, or does it use unbounded memory reading messages for
that single target so that other targets can receive messages?

That is more pertinent now that events can be sent to background
threads in web pages in modern browsers, but it's always been an issue
when some events cause large, slow page updates, while others are
small and should be processed at speed.  The current situation does
not handle that very well.

Generally, at the present time as far as I can tell, typically every
message must be fully processed as soon as it's available, before
moving to the next message.  The concept of targets which aren't ready
to receive a message hardly exists in current web applications, but
it's common in other applications.

In other words - _someone_ implements flow control, or there is no
flow control and memory usage is unbounded in clients, or flow control
is very coarse: every message must be processed fully before the next
message, even to independent targets.

There is no escape from that.

> Hmmm... in principle, I understand that HTTP can be run over any 
> full-duplex connection.  I see nothing in WebSockets that prevents similar 
> behaviour.

WebSockets cannot carry binary frames in any current or anticipated
implementation, so implementing HTTP over it isn't possible at
present, without first encoding the content into UTF-8 (plus escaping
NUL bytes).

> While I can agree that the XHR interface is too low-level, and that there 
> are better abstractions, and I could agree that the API makes it harder to 
> multiplex on a connection, I don;t see anything in the API that actually 
> makes such multiplexing impossible.

Not impossible, but somewhat tricky to do well.  See above - flow
control has to go somewhere, although it's easy to ignore the need and
just get unreliable or tighly-coupled behaviour.

-- Jamie