websockets on the jvm: atmosphere to the rescue!

Post on 30-Jun-2015

949 Views

Category:

Documents

4 Downloads

Preview:

Click to see full reader

DESCRIPTION

WebSockets' State of the Union on the JVM with the help of the Atmosphere Framework. Status of atmosphere.js, socketio.js, socks.js client side library discussed as well.

TRANSCRIPT

@jfarcand@atmo_framework

WebSockets on the JVM: Atmosphere to the rescue!

@jfarcandAsync-IO.org, http://async-io.orgCTO

@asyncio@atmo_framework

WebSockets: Myth or Reality

WebSocket a standard? Really?

Tricks for Production Ready WebSocket Application

@asyncio@atmo_framework

is a web technology providing for bi-directional, full-duplex communications channels over a single TCP connection.

WebSockets

Browser Serverrequest

empty response

request

response

event

request

request

responseevent

request

response part

event

response part

event

Polling Long Polling StreamingBrowser

Server

Browser Server

request

responseevent

event

Browser Server

request

Response

event

response

event

WebSocket

@asyncio@atmo_framework

Agenda

• Who I am• Atmosphere• WebSockets: Serveur Side• WebSocket: Client Side• Socket.IO and Socks.js• Conclusion

@asyncio@atmo_framework

Who is this strange accent guy• Creator of Frameworks

• Grizzly (NIO Framework)

• AsyncHttpClient (HTTP/WebSocket)

• Atmosphere Framework

• Ex-GlassFish, Tomcat & Jetty « committer »

• Ex Sun Microsystem, France Telecom, Ning, Sonatype

@asyncio@atmo_framework

Currently• Founder anf CTO Async-

IO.org

• Since 2013• Atmosphere Support,

Atmosphere Pro & Elite

• Atmosphere is still licenced Apache 2

@asyncio@atmo_framework

Async-IO

blank slidefor your own

pictures

WebSockets: Server Side

@asyncio@atmo_framework

WebSockets: Server Side

• Tomcat 7+, Jetty 7+, GlassFish 3+, Resin 2+, JBoss 7.1.2+ native Websocket API

• Non Portable, Unstable API

• Missing Functionality

• What the point of Atmosphere then???????

blank slidefor your own

pictures

@asyncio@atmo_framework

WebSockets: Server Side

AtmosphereTo

The Rescue!

@asyncio@atmo_framework

Atmosphere: github.com/Atmosphere• Portable, Stable, EVERYWHERE

• Use Native API or JSR 356

• Javascript API(s) & Java (wAsync)

• 950+ mailing list

@asyncio@atmo_framework

JAX Awards 2014

Nominated for Most Innovative Java Technology

@asyncio@atmo_framework

Atmosphere: Well Established!!

http://www.parleys.com/

play/514892260364bc

17fc56bde7/chapter0/about

@asyncio@atmo_framework

Atmosphere: Run on top of

@asyncio@atmo_framework

atmosphere.js

• 100% Javascript Library

• Small, portable, mobile optimized

• Transparent Fallback

• One API to Rule them all: WebSockets/Server Sides Event/Long-Polling/HTML File/JSONP/Polling/Streaming etc.

@asyncio@atmo_framework

Atmosphere : Clients

@asyncio@atmo_framework

Atmosphere: Browsers

6+

3.5+

4+

3+

10+

@asyncio@atmo_framework

Atmosphere: Into the Cloud

• Your Atmosphere’s Application transparently work into the cloud

Proxy/Load balancer

@asyncio@atmo_framework

Atmosphere: Cloud

blank slidefor your own

pictures

Enterprise Ready?

@asyncio@atmo_framework

Atmosphere Pro! • atmosphere-satellite: replicate your data and code together In-

Memory for faster execution and seamless elastic scalability across your Atmosphere's Nodes/Servers.

• atmosphere-tower-control: Monitor your Atmosphere's Node/Server state via any JMX compliant tool like Java Mission Control. Get statistics on how many websocket or long-polling clients are currently connected, add/move connected clients from one node to another, for example in case of a node being restarted, etc.

• atmosphere-postman: Client/Server extension to Atmosphere to support message delivery guarantee.

http://async-io.org/AtmospherePro.html

blank slidefor your own

pictures

Fix broken browsers/servers for you!

`

Atmosphere

var socket = atmosphere; var subSocket; var request = { url: document.location.toString() + 'chat’, contentType : "application/json”, transport : "websocket" , trackMessageLength : true };

request.onOpen = function(response) { content.html($('<p>', { text: 'Atmosphere connected using ' + response.transport })); }; request.onMessage = function (response) {

var json = atmosphere.util.parseJSON(response.responseBody)…

};

request.onClose = function(response) {…};

request.onReopen = function(response) {….}

request.onTransportFailure = function(errorMsg, request) {…}

subSocket = socket.subscribe(request);

Atmosphere

@ManagedService(path = "/chat”)public class Chat { @Ready public void onReady(AtmosphereResource r) {..}

@Disconnect public void onDisconnect(AtmosphereResourceEvent e) {..}

@Message( encoders = {JacksonEncoder.class}, decoders = {JacksonDecoder.class})

public Reply onMessage(Message message){return handleAndReply(message);

}}

Atmosphere

@asyncio@atmo_framework

Problem #1 – Fallback

• Browser• Old version

• No support (IE 9)

• Proxys• Disconnect, block

• Load Balancer• Breaks Session Affinity

@asyncio@atmo_framework

Fallback with Atmosphere

public void onReady(AtmosphereResource r) { switch (r.transport()) {

case WEBSOCKET:case SSE:case LONG-POLLING:case STREAMING:case JSONP:case POLLING:

r.write(“Atmosphere is cool”);}

}

@asyncio@atmo_framework

Atmosphere I/O

• WebSocket uses « non blocking I/O »

• Fallback simulates « non blocking I/O>

Browsers behave the same way as packet are delivered uniformely.

@asyncio@atmo_framework

Problem #2 –Protocol

Tomcat 7.x/8.x => RFC 6455 (Version

13) !!<= Safari 5.0.x

Jetty9.1+ => Hixie 76 <= Safari 5.0.x

@asyncio@atmo_framework

Protocol Version

• Atmosphere => Transparent Fallback in case the protocol is not supported

@asyncio@atmo_framework

Problem #3 – Lost Lost Lost

• I/O error, websocket message will be lost.

• Message must be put inside a cache

• Message must be discarted if the connection never come back.

@asyncio@atmo_framework

Atmosphere – Messages Lost

@ManagedService(path = "/chat”)public class Chat {

@Message public void onMessage(AtmosphereResource r, String message){ // Transparently cache the message in case of a problem

// Transparently write it back once reconnected r.write(message); }}

@asyncio@atmo_framework

Problem #4 – Proxy

• Existing Proxy are cutting the connection.

• Must recover transparently from a disconnect.

• Heartbeat saves your day!

@asyncio@atmo_framework

Atmosphere – Proxy ? No Problem!

@asyncio@atmo_framework

Problem #5 – New Spec!

• Difference between Tomcat, Undertow and Jetty already!

• Spec is young, missing fondamental concepts.

• Tomcat 8.0.12 is stable. GlassFish 4 is dead, Jetty 9.1.3 stable, Undertow 1.1.Final is stable, WelLogic is broken.

@asyncio@atmo_framework

Problem #5 – JSR 356: Tomcat vs Jetty

@Message public void onMessage(String m, Session s) {

for (Session s: sessions.getOpenSessions()){ // Tomcat will throw an IllegalStateException

// if more than one thread call sendXXX.// Jetty won’t!

session.getAsyncRemote().sendText(m);}

}

@asyncio@atmo_framework

Problem #5 – JSR 356: Tomcat vs Jetty private final Semaphore semaphore = new Semaphore(1, true);

@Message public void onMessage(String m, Session s) {

for (Session s: sessions.getOpenSessions()){try{ semaphore.acquireUninterruptibly();

session.getAsyncRemote().sendText(m, …);}finally {

semaphore.release();}

}}

@asyncio@atmo_framework

Problem #5 – Tomcat vs Jetty

• I/O Event aren’t delivered the same way.

• CloseReason not the same depending on the server!!!!

// Hack if (closeCode == 1000 &&

getContainerName().contains("Tomcat")) { closeCode = 1005;

}

@asyncio@atmo_framework

Firefox is the new Internet Explorer 6!

// Reload a tab/window // Firefox => 1001 // Chrome => 1000

if (isFirefox && c.getCode() == CloseReason.GOING_AWAY

|| c.getCode() == CloseReason.NO_STATUS_CODE) {...

}

@asyncio@atmo_framework

Firefox is the new Internet Explorer 6!

Reload in Firefox produces phantom websockets connections!!!!!!!

@asyncio@atmo_framework

Problem #6 – Closing Code

• How to detect if a websocket was closed by a Proxy, a Load Balancer or the Browser!!

@asyncio@atmo_framework

Hell exists!!

@asyncio@atmo_framework

Atmosphere

@Disconnect public void onClose(AtmosphereResourceEvent e) {

if (e.isClosedByClient()){

} else if (e.isClosedByApplication()) {

} else if (e.isUnexpectlyClosed()) {

}

@asyncio@atmo_framework

blank slidefor your own

pictures

WebSockets: Client Side

@asyncio@atmo_framework

WebSockets: Javascript API

• W3C SpecificationWebSocket ws = new WebSocket(“ws://127.0.0.1:8080”);

ws.onopen = function (message) {};

ws.onclose = function (message) {};

ws.onmessage = function (message) {}

@asyncio@atmo_framework

WebSocket: Supported Browsers

10+

10+

6+

5+

10+

?

2+

@asyncio@atmo_framework

W3C API

Ohhhhhhhhh• Pong/Ping: No exposed

• Headers: Can’t add/read

• Query String: No API, append them to the url

• Cookie: Impossible to read them

@asyncio@atmo_framework

Atmosphere: First request

• W3C SpecificationT 127.0.0.1:52212 -> 127.0.0.1:8080 [AP]GET /chat?X-Atmosphere-tracking-id=0&X-Atmosphere-Framework=2.2.0-javascript&X-Atmosphere-Transport=websocket&X-Atmosphere-TrackMessageSize=true&X-Cache-Date=0&Content-Type=application/json&X-atmo-protocol=true HTTP/1.1.Upgrade: websocket.Connection: Upgrade.Host: 127.0.0.1:8080.Origin: http://127.0.0.1:8080.Sec-WebSocket-Key: TCBKrAyFFwW8HUXqLpj2wg==.Sec-WebSocket-Version: 13.Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits, x-webkit-deflate-frame.

@asyncio@atmo_framework

Atmosphere: First request

• W3C Specification

T 127.0.0.1:8080 -> 127.0.0.1:52212 [AP]HTTP/1.1 101 Switching Protocols.X-Atmosphere-first-request: true.X-Atmosphere-tracking-id: bb7aeeb7-9e44-4aa9-848d-14bba6532de9.Connection: Upgrade.Sec-WebSocket-Accept: 5mHABDQFkWBtjoinv3lj+6dVwHg=.Upgrade: WebSocket.

@asyncio@atmo_framework

Problem #1 – onclose

• Firefox will execute the ws.onclose function on F5 (reload)

• Chrome/Safari ….. NOT!

@asyncio@atmo_framework

Problem #1: onclose

• W3C Specificationws.onclose = function(closeReason) {

switch(closeReason.code) {case 1000:

….}

// Firefox will execute this logic on every reload// closeReason.wasClean unreliableif (dirtyClose) {

reconnectTo(…); }}

@asyncio@atmo_framework

Atmosphere: onclose

• W3C Specification

// Hahahaha go to hell Firefox!!atmosphere.onClose = function

(callback) {

};

@asyncio@atmo_framework

Problem #2 – Messages’ length

• Messages can be truncated when the server write them

• The Browser received them in two chunks or I/O operation

@asyncio@atmo_framework

Problem #2: Messages’ length

• W3C Specification

// Craaaaaaashhhhhhhhhhhhhws.onmessage = function (callback) {

window.JSON.parse(callback.data);};

@asyncio@atmo_framework

Problem #2: What’s Up, Doctor!

• W3C Specification

// atmosphere.js transparently // handles it

atmosphere.onMessage = function (callback) {window.JSON.parse(callback.responseBody);

};

@asyncio@atmo_framework

Problem #3 – UUID and Cookie

• No Cookie to identify the client

@asyncio@atmo_framework

Problem #3 – UUID and Cookie

• Solutions:

• Normal request => set-cookie

• Next WebSockets

• Useful if you deploy on Amazon

(1) HTTP

(2) websockets

@asyncio@atmo_framework

Atmosphere: Handshake Protocol

• W3C Specification

T 127.0.0.1:8080 -> 127.0.0.1:52212 [AP].651|bb7aeeb7-9e44-4aa9-848d-14bba6532de9|1397426374301|

T 127.0.0.1:8080 -> 127.0.0.1:52212 [AP]..

T 127.0.0.1:8080 -> 127.0.0.1:52212 [AP]..

@asyncio@atmo_framework

Problem #4 – Proxy

• Proxy can close the websocket or completely ignore the websocket handshake, completely fooling the server…and the browser!

• ws.open never called!!!!

@asyncio@atmo_framework

Problem #4 – Proxy

• W3C Specification

websocket.onopen = function (message) { alert(“Ha ha ha good luck!!!”);}

websocket.onmessage = function(message) { // Never called

alert(“Sleep on it!!!”);}

@asyncio@atmo_framework

Problem #4 – Proxy

• W3C Specification

atmosphere.onReopen = function (callback) { // Yeahhhh!!!

};

atmosphere.onTransportFailure = function (callback) { // Apache Proxy, I hate you!!!

};

@asyncio@atmo_framework

Hazelcast

@asyncio@atmo_framework

blank slidefor your own

pictures

SockJs et Socket.ioSocket.IO and Socks.js

@asyncio@atmo_framework

Socket.IO• For Node.js

• Streaming, Long-Polling and now Websocket

• Extremely popular, lot of  »issues »

602 => https://github.com/LearnBoost/socket.io/issues

• Supported by Atmosphere, both client and server side. Replace node.js

@asyncio@atmo_framework

Socket.IO - Atmosphere

• W3C Specification@ManagedService(path = "/chat”)public class Chat { @Ready public void onReady(AtmosphereResource r) {..}

@Disconnect public void onDisconnect(AtmosphereResourceEvent e) {..}

@Message( encoders = {JacksonEncoder.class}, decoders = {JacksonDecoder.class})

public Reply onMessage(Message message){return handleAndReply(message);

}}

@asyncio@atmo_framework

Socket.IO - Atmosphere

• W3C Specificationvar socket = io.connect('', {'resource’:document.location.toString() + 'chat'});

socket.on('connect', function () { content.html($('<p>',

{ text:'Atmosphere connected using this.socket.transport.name}));});

socket.on('chat message', function() { var json = jQuery.parseJSON(msg);

… });

socket.on(‘error’, function (e) {…});

@asyncio@atmo_framework

Socks.js

• For Node.js

• Emulate WebSocket, with « fallback »

• Socks.js popularity increase, due to Spring 4, Vert.x and Atmosphere support

@asyncio@atmo_framework

Socks.js - Atmosphere

• W3C Specification@ManagedService(path = "/clavarder”)public class Chat { @Ready public void onReady(AtmosphereResource r) {..}

@Disconnect public void onDisconnect(AtmosphereResourceEvent e) {..}

@Message( encoders = {JacksonEncoder.class}, decoders = {JacksonDecoder.class})

public Reply onMessage(Message message){return handleAndReply(message);

}}

@asyncio@atmo_framework

Socks.js- Atmosphere

• W3C Specificationvar socket = new SockJS('http://' + window.location.host + '/chat', null, { 'protocols_whitelist': ['websocket', 'xhr-streaming', 'iframe-eventsource', 'iframe-htmlfile', 'xhr-polling', 'jsonp-polling'] });

socket.onopen = function() { content.html($('<p>', { text: 'Atmosphere connected using SockJs client'}));}

socket.onmessage = function (response) { var message = response.data;

var json = JSON.parse(message);}

socket.onclose = function() {}

@asyncio@atmo_framework

Conclusion

• WebSockets in Prod without fallback? You’re Crazy!!

• Atmosphere is production ready, and fixes all the issues listed here!

• What are you waiting for?

@asyncio@atmo_framework

@All images copyright JeanFrancois Arcand

https://www.linkedin.com/in/jfarcand

http://async-io.org

http://github.com/Atmosphere/atmosphere

http://github.com/jfarcand

Credits

top related