A tale of friendly competition and Server-Sent Events
Me
Background
is a broadcaster
Traditionally, journalists ➜ users
"Push" makes more sense than "poll"
More and more "realtime" services
is a broadcaster
Use case is usually very similar:
Broadcast some arbitrary data
The tale begins...
Websockets is starting to sound like a good idea
Spend 10% of time
on a prototype
"Websockets are awesome, but does it scale?"
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
http.listen(3000, function() {
console.log('listening on *:3000');
});
setInterval(function() {
io.emit('ping', { timestamp: Date.now() });
}, 5000);
Server
// On VG.no:
var chance = 50;
if ((Math.random() * 100) < chance) {
var script = d.createElement('script');
script.type = 'text/javascript';
script.async = true;
script.src = '<url-to-client-script>.js';
}
Client
Result? Not encouraging
- Latency spikes
- High CPU usage
- Hard to debug
- Server "crashed"
- Monster server,
~60k connection cap?
Some time later...
Let's investigate
WSS: Not HTTP
handshake resembles HTTP
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Origin: http://example.com
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat
Full-duplex
On top of TCP
Port 80/443
6 different protocols
RFC since
Dec 2011
Proxies and firewalls still cause issues
Server-Sent Events?
One-way -
Server ➜ Client
Extremely simple,
HTTP-based
GET /chat HTTP/1.1
Host: server.example.com
Accept: text/event-stream
HTTP/1.1 200 OK
Connection: Keep-Alive
Content-Type: text/event-stream
Cache-Control: no-cache
id: 123
data: some arbitrary data
id: 124
data: {"we could also":"push json"}
Additional features
- "Events since ID" (dropped clients)
- Named events
- Configurable reconnect timeout
Time passes
Confidence grows
"I can do this"
Node.js
SSE
Simple!
Result?
Go
would
scale
better
Erlang was
built for
this task
Did you
try this in
Python?
Do you even
Nimrod,
bro?
C++,
aight?
Fine.
Do your worst!
(I'll go heal my wounded pride)
Results!
Node.js
- Spiky response times
- Bit of GC every now and then
- High CPU usage
Go
- Consumed less CPU than node
- Hit the roof at about ~30% more clients than node
Ruby (EventMachine)
- Similar to node, but with less CPU usage
- Very quick connects
- Fairly high memory usage
Erlang
- Very unfamiliar
- Response times very varying
- "Cheated" the system slightly
Clojure (http-kit)
- Nice, predictable performance
- Fairly stable response times
- Delivery time a bit varied
- High memory consumption
Python (Twisted)
- Comparable to Node.js and Ruby
- CPU usage a bit higher than the others
BUT THEN
C
- Epoll, pthread, ~350 LOC
- Could not give it enough work
- Peaked at ~200k
- Mostly rock solid response times
- Very low memory usage
Written by...
a sysop
My hero:
Ole Fredrik Skudsvik
Since then:
-
C++
-
Nim
-
php-react
Scalability vs maintainability
-
C
-
C++
-
Clojure
Microservice!
Lessons learned
“If you only have a hammer, you tend to see every problem as a nail.”
- Abraham Maslow
You can learn a lot during two weeks of intense hacking
Benchmarking stuff is not easy
Friendly competition can be helpful, educational and
a lot of fun
We want to share
SSE Hub is open-source
RabbitMQ
C/C++
+ ecosystem
Thx.
Credits
Lego man by Okan Benn
Cowboy hat by Paul Stevens
Horse by Gilad Fried
Salesman by John Salzarulo
Lazy by Aaron Tregent
Whining + sick day by Clara Joy
Muscle by Jurjen Versteeg
Hourglass by Sma-rtez
Hammer by John Caserta
Graphics licensed under CC BY 3.0 US:
Mortar Board by Ian Graham
Snake tornado kindly borrowed from Natalie Dee
A tale of friendly competition and Server-Sent Events
By Espen Hovlandsdal
A tale of friendly competition and Server-Sent Events
- 1,586