unicorn Ruby/Rack server user+dev discussion/patches/pulls/bugs/help
 help / color / mirror / code / Atom feed
* Please join the Rack Specification discussion for `env['upgrade.websocket']`
@ 2016-08-05 23:49 Bo
  2016-08-06  1:01 ` Eric Wong
  0 siblings, 1 reply; 9+ messages in thread
From: Bo @ 2016-08-05 23:49 UTC (permalink / raw)
  To: unicorn-public

Please join the Rack Specification discussion for `env['upgrade.websocket']`

I represent an effort to extend Rack so that it allows server-side websocket upgrade implementation support and pure Rack websocket applications.

This new Rack feature proposal is gaining support, with over 42 support votes in the [original Rack discussion thread](https://github.com/rack/rack/issues/1093).

You may have read [my blog post about this](https://bowild.wordpress.com/2016/07/31/the-dark-side-of-the-rack/) or [the reddit discussion](https://www.reddit.com/r/ruby/comments/4vgdlc/the_dark_side_of_the_rack_and_websockets_dreams/).

This proposal simplifies Websocket applications by leaving all the network complexity were it is (with the application's web server), allowing application programmers to focus on their application logic.

Using [the proposed specification](https://github.com/boazsegev/iodine/issues/6), a pure Rack Websocket echo server could be written as simply as:

```ruby
# this is a toy example.
class MyEcho
   def initialize(env = nil)
      # optional initialization
   end
   def on_message(data)
     write "Echo: #{data}"
   end
end

app = Proc.new do |env|
   if env['upgrade.websocket?'] && env['HTTP_UPGRADE'] =~ /websocket/i
      env['upgrade.websocket'] = MyEcho.new(env) # or simply `MyEcho`
      [ 0, {'X-Header': 'data'}, [] ]
   else
      [200, { 'Content-Length' => '12' }, ['He11o World!']]
   end
end

run app
```

There's [a working Gist chatroom example](https://gist.github.com/boazsegev/1466442c913a8dd4271178cab9d98a27).

I invite you to join [the discussion](https://github.com/rack/rack/issues/1093) and help shape the [proposed specification](https://github.com/boazsegev/iodine/issues/6).


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Please join the Rack Specification discussion for `env['upgrade.websocket']`
  2016-08-05 23:49 Please join the Rack Specification discussion for `env['upgrade.websocket']` Bo
@ 2016-08-06  1:01 ` Eric Wong
  2016-08-06  3:09   ` Boaz Segev
  0 siblings, 1 reply; 9+ messages in thread
From: Eric Wong @ 2016-08-06  1:01 UTC (permalink / raw)
  To: Bo; +Cc: unicorn-public

Bo <boaz@2be.co.il> wrote:
> Please join the Rack Specification discussion for `env['upgrade.websocket']`

Fwiw, I have not existed outside of plain-text email for years;
so I'll respond inline here and you can link others to this
thread on:

https://bogomips.org/unicorn-public/58D32D89-4523-436E-8C0E-FA8F4E7AFFB2@plezi.io/T/
(which anybody may reply-all to after disabling HTML in their mailer)

> I represent an effort to extend Rack so that it allows server-side
> websocket upgrade implementation support and pure Rack websocket
> applications.
> 
> This new Rack feature proposal is gaining support, with over 42
> support votes in the [original Rack discussion
> thread](https://github.com/rack/rack/issues/1093).

You mention performance several times, but I am not sure what
you mean.  unicorn completely stops caring for a socket after
it's hijacked by the app.  In other words:

  Your Rack app could take the socket and inject it into an
  event loop running in a separate thread.  That event loop
  could be 100% C code running without GVL for all unicorn
  cares.

  unicorn would only parse the first HTTP request (with the
  Upgrade header) before the Rack app hijacks it.


Also, Ruby IO.select also supports arbitrary number of
descriptors in some cases (Linux for sure, and probably most
server-oriented *BSDs).  Of course, the malloc usage + O(n)
behavior still suck, but no, select(2) is not always limited to
<=1024 FDs.


In any case, I'd be glad to help with lower-level issues over
plain-text email, but I'm not going to attempt to run a
mainstream browser capable of WebSockets or JS.
I suppose curl can deal with WebSockets nowadays?

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Please join the Rack Specification discussion for `env['upgrade.websocket']`
  2016-08-06  1:01 ` Eric Wong
@ 2016-08-06  3:09   ` Boaz Segev
  2016-08-06  4:10     ` Michael Fischer
  2016-08-06  4:59     ` Eric Wong
  0 siblings, 2 replies; 9+ messages in thread
From: Boaz Segev @ 2016-08-06  3:09 UTC (permalink / raw)
  To: Eric Wong; +Cc: unicorn-public

Eric, thank you for your review and thoughts on the matter.

You raised a few questions, please allow me to both answer and clarify the intention behind the proposed extension.

>> I represent an effort to extend Rack so that it allows server-side
>> websocket upgrade implementation support and pure Rack websocket
>> applications.
>> 
>> This new Rack feature proposal is gaining support, with over 42
>> support votes in the [original Rack discussion
>> thread](https://github.com/rack/rack/issues/1093).
> 
> You mention performance several times, but I am not sure what
> you mean.  unicorn completely stops caring for a socket after
> it's hijacked by the app.  In other words:
> 
>  Your Rack app could take the socket and inject it into an
>  event loop running in a separate thread.  That event loop
>  could be 100% C code running without GVL for all unicorn
>  cares.


Running two (or more) event loops, each with it's own resources, is wasteful and promotes needless context switches.

There is no reason to hijack a socket when the server can easily provide callbacks for IO related events using it's existing established event loop.

This alone should provide a performance boost. There are other considerations as well, but I think they all derive from this core principle of having the web server retain control over all network IO concerns.

> Also, Ruby IO.select also supports arbitrary number of
> descriptors in some cases (Linux for sure, and probably most
> server-oriented *BSDs).  Of course, the malloc usage + O(n)
> behavior still suck, but no, select(2) is not always limited to
> <=1024 FDs.


Although this isn't as relevant to the proposed specification, it is a good example for how intricate network programming details are unknown by most Ruby programmers and shows why it would be better for the web server to retain control over all network IO concerns.

For example, the Linux man page expressly states that "To monitor file descriptors greater than 1023, use poll(2) instead"

This is true even when using select for a single FD that has a value of more then 1023, since `select` is often implemented using a bit vector map of 1024 bits that are controlled using the FD_(*) macros.

See, for example: http://linux-tips.org/t/is-it-possible-to-listen-file-descriptor-greater-than-1024-with-select/45/2

Ruby's IO.select uses this same system call and suffers the same issues that are present in the OS - each OS with it's own quirks.

I don't think application developers should worry about these details when these issues were already resolved during the server's designed.

By having the server provide callbacks - instead of hijacking - we eliminate a hoard of potential bugs and considerations.

>  unicorn would only parse the first HTTP request (with the
>  Upgrade header) before the Rack app hijacks it.


Of course, not every server has to offer this feature - just like hijacking, it's optional.

Unicorn was design for very specific use cases, so I definitely understand if this might not be as interesting for you. 

However, I do think your experience as developers could help enrich us all. If you have any comments or anything to add regarding the proposed `websocket.upgrade` specification, your voice is welcome:

https://github.com/boazsegev/iodine/issues/6



^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Please join the Rack Specification discussion for `env['upgrade.websocket']`
  2016-08-06  3:09   ` Boaz Segev
@ 2016-08-06  4:10     ` Michael Fischer
  2016-08-06  7:37       ` Boaz Segev
  2016-08-06  4:59     ` Eric Wong
  1 sibling, 1 reply; 9+ messages in thread
From: Michael Fischer @ 2016-08-06  4:10 UTC (permalink / raw)
  To: Boaz Segev; +Cc: Eric Wong, unicorn-public

On Fri, Aug 5, 2016 at 8:09 PM, Boaz Segev <boaz@2be.co.il> wrote:

> > Your Rack app could take the socket and inject it into an
> > event loop running in a separate thread. That event loop
> > could be 100% C code running without GVL for all unicorn
> > cares.
>
>
> Running two (or more) event loops, each with it's own resources, is wasteful and promotes needless context switches.
>
> There is no reason to hijack a socket when the server can easily provide callbacks for IO related events using it's existing established event loop.

I suspect we're missing the forest for the trees here :)

Unicorn is a forking webserver, not an event-driven or threaded
webserver.  Whether Unicorn ever supports the proposed standard or
not, I wouldn't recommend it be used for typical applications that use
WebSockets, as they usually involve persistent connections.  Unicorn
would quickly run out of worker processes capable of serving such
connections anyway, so I question whether it's worth delving into the
dirty details of IO syscalls.

Best regards,

--Michael


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Please join the Rack Specification discussion for `env['upgrade.websocket']`
  2016-08-06  3:09   ` Boaz Segev
  2016-08-06  4:10     ` Michael Fischer
@ 2016-08-06  4:59     ` Eric Wong
  1 sibling, 0 replies; 9+ messages in thread
From: Eric Wong @ 2016-08-06  4:59 UTC (permalink / raw)
  To: Boaz Segev; +Cc: unicorn-public

Boaz Segev <boaz@2be.co.il> wrote:
> Running two (or more) event loops, each with it's own
> resources, is wasteful and promotes needless context switches.
> 
> There is no reason to hijack a socket when the server can
> easily provide callbacks for IO related events using it's
> existing established event loop.

As Michael said, WS is a really bad fit for unicorn :)

> This alone should provide a performance boost. There are other
> considerations as well, but I think they all derive from this
> core principle of having the web server retain control over
> all network IO concerns.

For anybody else writing an epoll-based server with multiple
epoll-based event loops in different threads, the following is
good ordering; relatively cheap and scalable:

	epoll_ctl(original_epfd, EPOLL_CTL_DEL, client_fd, NULL);
	epoll_ctl(websocket_epfd, EPOLL_CTL_ADD, client_fd, &ev);

Change the order, and it's slower and less scalable:

	/* in other words, don't do this in this order */
	epoll_ctl(websocket_epfd, EPOLL_CTL_ADD, client_fd, &ev);
	epoll_ctl(original_epfd, EPOLL_CTL_DEL, client_fd, NULL);

The former ensures a simple topology where the file behind
client_fd only exists in one eventpoll rbtree at a time.  The
latter creates a complex topology which needs to do additional
locking and scanning to prevent infinite loops.

This is true since Linux 3.13, commit 67347fe4e632633
("epoll: do not take global 'epmutex' for simple topologies")
 https://bogomips.org/mirrors/linux.git/commit?id=67347fe4e632633

> like hijacking, it's optional.
> 
> Unicorn was design for very specific use cases, so I
> definitely understand if this might not be as interesting for
> you. 

Yes, unicorn itself will never have a multi-client-aware event
loop.  It is out-of-scope for its design, it seems WebSockets
usually have idle times which would cause any server with the
design of unicorn to fall over.  unicorn cannot even handle
HTTP/1.1 persistent connections.

> However, I do think your experience as developers could help
> enrich us all. If you have any comments or anything to add
> regarding the proposed `websocket.upgrade` specification, your
> voice is welcome:

Sorry, not interested, and definitely not touching centralized
message boards :>

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Please join the Rack Specification discussion for `env['upgrade.websocket']`
  2016-08-06  4:10     ` Michael Fischer
@ 2016-08-06  7:37       ` Boaz Segev
  2016-08-09  1:08         ` Sam Saffron
  0 siblings, 1 reply; 9+ messages in thread
From: Boaz Segev @ 2016-08-06  7:37 UTC (permalink / raw)
  To: Michael Fischer; +Cc: Eric Wong, unicorn-public

>> Michael said
> Unicorn is a forking webserver, not an event-driven or threaded
> webserver.  Whether Unicorn ever supports the proposed standard or
> not, I wouldn't recommend it be used for typical applications that use
> WebSockets, as they usually involve persistent connections.  Unicorn
> would quickly run out of worker processes capable of serving such
> connections anyway, so I question whether it's worth delving into the
> dirty details of IO syscalls.


>> Eric said
> Sorry, not interested, and definitely not touching centralized
> message boards :>


I totally understand and I thank you both for your time.

-- Bo.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Please join the Rack Specification discussion for `env['upgrade.websocket']`
  2016-08-06  7:37       ` Boaz Segev
@ 2016-08-09  1:08         ` Sam Saffron
  2016-08-09  2:42           ` Eric Wong
  2016-08-09  3:17           ` Boaz Segev
  0 siblings, 2 replies; 9+ messages in thread
From: Sam Saffron @ 2016-08-09  1:08 UTC (permalink / raw)
  To: Boaz Segev; +Cc: Michael Fischer, Eric Wong, unicorn-public

For the record Eric,

We use unicorn at Discourse to serve concurrent long polls across 100s
of hosted forums using hijack with zero issues using
https://github.com/SamSaffron/message_bus

I am not particularly enthused WebSockets and have blogged about my
reservations, in an HTTP/2 world I am less clear about how they fit in
except for some very niche uses.

If this becomes a core Rack specification and now forces all Rack
implementation to carry around websocket framing protocol and
epoll/kqueue I would also be less excited.

On Sat, Aug 6, 2016 at 5:37 PM, Boaz Segev <boaz@2be.co.il> wrote:
>>> Michael said
>> Unicorn is a forking webserver, not an event-driven or threaded
>> webserver.  Whether Unicorn ever supports the proposed standard or
>> not, I wouldn't recommend it be used for typical applications that use
>> WebSockets, as they usually involve persistent connections.  Unicorn
>> would quickly run out of worker processes capable of serving such
>> connections anyway, so I question whether it's worth delving into the
>> dirty details of IO syscalls.
>
>
>>> Eric said
>> Sorry, not interested, and definitely not touching centralized
>> message boards :>
>
>
> I totally understand and I thank you both for your time.
>
> -- Bo.
>

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Please join the Rack Specification discussion for `env['upgrade.websocket']`
  2016-08-09  1:08         ` Sam Saffron
@ 2016-08-09  2:42           ` Eric Wong
  2016-08-09  3:17           ` Boaz Segev
  1 sibling, 0 replies; 9+ messages in thread
From: Eric Wong @ 2016-08-09  2:42 UTC (permalink / raw)
  To: Sam Saffron; +Cc: Boaz Segev, Michael Fischer, unicorn-public

Sam Saffron <sam.saffron@gmail.com> wrote:
> For the record Eric,
> 
> We use unicorn at Discourse to serve concurrent long polls across 100s
> of hosted forums using hijack with zero issues using
> https://github.com/SamSaffron/message_bus

Thanks.  That's exactly the usage I had in mind when I learned
about rack.hijack.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Please join the Rack Specification discussion for `env['upgrade.websocket']`
  2016-08-09  1:08         ` Sam Saffron
  2016-08-09  2:42           ` Eric Wong
@ 2016-08-09  3:17           ` Boaz Segev
  1 sibling, 0 replies; 9+ messages in thread
From: Boaz Segev @ 2016-08-09  3:17 UTC (permalink / raw)
  To: Sam Saffron; +Cc: Michael Fischer, Eric Wong, unicorn-public

Hi Sam,

I just wanted to point out that the specification was meant to be optional and this is why it includes the `env['upgrade.websocket?']` flag to indicate support. 

I don't think every server has to support Websockets - different server architectures favor different tasks and performance isn't a one size fit all.

However, it's high time (if not a bit late) Ruby had better support for applications that decide to use Websockets - which is, obviously, not all of them (I doubt that many applications need them).

I think it's wrong that Websockets are so complicated to implement in Ruby and Rack. The technology might be dangerous, but it does have it's uses (such as large file uploads, inter-app micro-services, game servers... to name just a few use-cases that survive HTTP/2).

- Bo.

> On Aug 8, 2016, at 21:08, Sam Saffron <sam.saffron@gmail.com> wrote:
> 
> For the record Eric,
> 
> We use unicorn at Discourse to serve concurrent long polls across 100s
> of hosted forums using hijack with zero issues using
> https://github.com/SamSaffron/message_bus
> 
> I am not particularly enthused WebSockets and have blogged about my
> reservations, in an HTTP/2 world I am less clear about how they fit in
> except for some very niche uses.
> 
> If this becomes a core Rack specification and now forces all Rack
> implementation to carry around websocket framing protocol and
> epoll/kqueue I would also be less excited.
> 
> On Sat, Aug 6, 2016 at 5:37 PM, Boaz Segev <boaz@2be.co.il> wrote:
>>>> Michael said
>>> Unicorn is a forking webserver, not an event-driven or threaded
>>> webserver.  Whether Unicorn ever supports the proposed standard or
>>> not, I wouldn't recommend it be used for typical applications that use
>>> WebSockets, as they usually involve persistent connections.  Unicorn
>>> would quickly run out of worker processes capable of serving such
>>> connections anyway, so I question whether it's worth delving into the
>>> dirty details of IO syscalls.
>> 
>> 
>>>> Eric said
>>> Sorry, not interested, and definitely not touching centralized
>>> message boards :>
>> 
>> 
>> I totally understand and I thank you both for your time.
>> 
>> -- Bo.
>> 


^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2016-08-09  3:17 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-08-05 23:49 Please join the Rack Specification discussion for `env['upgrade.websocket']` Bo
2016-08-06  1:01 ` Eric Wong
2016-08-06  3:09   ` Boaz Segev
2016-08-06  4:10     ` Michael Fischer
2016-08-06  7:37       ` Boaz Segev
2016-08-09  1:08         ` Sam Saffron
2016-08-09  2:42           ` Eric Wong
2016-08-09  3:17           ` Boaz Segev
2016-08-06  4:59     ` Eric Wong

Code repositories for project(s) associated with this public inbox

	https://yhbt.net/unicorn.git/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).