Nginx+HTTPS event stream issues

Hey guys,

first of all, the stats: running Ubuntu 11.10, nginx 1.0.5 (package
installed) and PHP 5.3.6 (package php-fpm).

So I have this HTML5 event stream that every 0,5 seconds does some
database operation and sends events to the browser (which the javascript
then handles). Everything was working alright, but then I noticed the
events were getting bundled (3 or 4 of them together) and sent all at
the same time. Basically, I’d see an event coming, then after waiting 2
or 3 seconds, I’d see 4 or 5 arrive at the same time. As the idea here
is a real-time stream, this is definitely not good - the events should
be sent to the browser as soon as they are created (ie. every 0,5
seconds - plus some processing time for DB access etc).

So I started playing around with the buffer size. I noticed that my
events are always roughly 800 bytes, so I used the following parameters:

[php.ini]
output_buffering = Off

[nginx site file]
fastcgi_buffer_size 500;
fastcgi_buffers 2 900;
fastcgi_busy_buffers_size 900;
fastcgi_max_temp_file_size 0;
proxy_buffering off;

With these settings, everything works great, I see the events arriving
in order, all of them individually, and it looks great.
But then, of course, everything got wrong again when I started using
HTTPS. After a lot of nginx debugging (including looking at its source
code), I realized that nginx buffers the data sent to OpenSSL, and that
this buffer is 16k bytes. Since I couldn’t find any config options to
change/disable this SSL buffer, I decided to pad my events with
whitespaces, in order for them to be roughly 16k long, and set the
buffers to:

fastcgi_buffer_size 17000;
fastcgi_buffers 2 17000;
fastcgi_busy_buffers_size 17000;

Unfortunately, that doesn’t work either: looking at the nginx debug log,
I see that the events arrive at nginx fine, the buffer is just big
enough for them, and for every event, nginx writes it immediately to
SSL:

SSL buf copy: 6
SSL buf copy: 15974
SSL to write: 16384
SSL_write: 16384

Yet the javascript only sees the first event (confirmed with
console.log)

Basically, I’d love to have some help from you guys to solve my problem.
All I need is a real-time event stream in HTTPS. I already tried dozens
of buffer size combinations, either really small (so that’s nothing is
buffered) or values around 800bytes (+headers), or values around 16000
with padding. I also tried compiling nginx from source with
NGX_SSL_BUFFERED (source/core/ngx_connection.h) set to 0x00 , but that
didn’t help… Is there any way to just disable SSSL buffering all
together?!

I am attaching the nginx debug log, hopefully it will make sense to
someone! (Tip: in the php script, I error_log “Sending event with
<num_bytes> bytes” before echo’ing the event output and error_log
“SENT!” after - these show up in the log after the “FastCGI sent in
stderr” messages)

Thanks in advance,

Thanks mate, your module does seem pretty handy! I’m not sure it’s what
I need though,let me explain:

Basically, what I have now (without using the push stream module) is a
PHP function that, when called, pretty much echos the contents of a
certain DB table (chosen via POST paramters) every 0,5 seconds. On the
client-side, there is javascript code that sets up an event source (with
HTML5’s EventSource class) to this PHP script URL and shows the
information to the user, when the events arrive. Like I said in my
initial message, this works fine for HTTP, but the SSL buffering means
the events get bundled together and instead of waiting 0,5secs for an
event, I only see events after like 10 seconds (and then only the last
event’s info is seen by the user).

From what I can understand from your module, the publisher is something
that is always running, ie. always posting new stuff to all clients.
What I need, on the other hand, is an individual channel that is
different for each different client and each different DB-information
to obtain
(ie. info from what table to post, the fields to return,
etc). Ignoring how setting up individual channels would be
time-consuming, what I think is the main problem here is that I would
have to (client-side) somehow call a PHP function (via XHR, I guess) to
initiate the proper channel with some parameters (DB table, etc) and
then go subscribe to it (on a different address). Now, this doesn’t look
like a good set-up, does it? :confused:

In the mean time, I figured out how to disable SSL buffering (or change
its size), so I might just go with that*… Would still like to hear
your opinion, tho, since using a proper publisher-subscriber module
seems like a better idea!

*: for anyone with the same problem, its all in
src/event/ngx_event_openssl.h . The buffer size is in NGX_SSL_BUFSIZE
and if you want to disable it completely, change NGX_SSL_BUFFER to 0.

Cheers,