Reactive Web Sockets with Spring 5
Something new and exciting has happened to the Spring Framework’s Web stack! Introduced in Spring 5, WebFlux enables us to compose Reactive HTTP request-response paths. The Spring WebSockets API also received this update and exposes WebSockets as a consumer and publisher in the Reactive domain. Because Reactive is a lot about building asynchronous data pipelines — functionally, and with back-pressure —Spring 5’s reactive WebSockets is a natural fit to expose event driven data and meet the demand of the real-time Web.
This article describes in particular the WebSocket technologies and the reasons for using them. To get to the code, check out my GitHub and you will find projects that make use of Spring 5, WebSocket, SSE and of course with the Reactive approach.
Classical event consumption over the Web
As always one may directly consume a service for event push/pull — e.g. directly via TCP/IP sockets. That is a portability, security and network nightmare that is probably not even appropriate where the client is a deployed package to a managed device[But would you really want clients to connect directly to your Kafka cluster???]. Luckily, many (or most) internet gateways wont forward inbound traffic — especially from non IANA ports — without organizational review or some kind of miracle. For the most part, even for thick-clients, Web Sockets are the best way to deliver real time events on the Internet. thus no new networking changes beyond proxy configurations need to take place. Lets take a look at the alternatives (and major differences) that have been adopted over the years.
Short-polling as it's called, the client repeats a request for new events in a stream, while the server vends a single or series of events that happened since the last request. This works when very little data is traveling in either direction, and where the interval can be kept sparse. For example, a news feed may update just once every half minute which is fine for consumers. However this will breakdown once new information must be delivered as soon as possible in which case the interval must be tightened, causing additional contention at the edge.
This gets us into long-polling (Informational RFC 6202), which has been the happy medium between near-real-time delivery and persistent sockets. A long-polling client initiates a request that can be satisfied by either a timeout, connection status change, or the reception of new event(s). The reason for the timeout exists as an exercise for this IETF recommendation as most intermediate HTTP proxies police HTTP connections, causing timeouts sooner than expected. Therefore, the IETF recommends somewhere between 30 and 120 second timeout tolerances.
The downside to long-polling is that the client may end up making many requests (like traditional polling) as events begin accumulating on the server for the client to request.
Server Sent Events(SSE)
SSE (W3C API Spec) is a unidirectional (half-duplex) transport that doesn’t have requirement for connection upgrading (out of HTTP) like WebSockets. This means you may find it easier to expose an SSE endpoint in environments where a policy for persistent non-HTTP connections have not been introduced. SSE is HTTP that handles media types for 'application/stream' and the variances for JSON, XML, text etc.. SSE is ideal for push-type applications that have few out-of-band operations.
A WebSocket is similar to a standard TCP connection, however beginning life as a HTTP request. The details of this connection negotiation are outlined in the [IETF RFC 6455] as well. WebSockets are bi-directional, in contrast to SSE.
WebSockets excel when you have application events that need to be delivered in high-frequency, as soon as possible. Real-time applications like stock tickers, chat apps, and even audio/video apps — WebSocket also handles binary content unlike SSE.
Common WebSocket Issues
Many currently deployed HTTP proxies and even network routers expected the bulk of web-traffic to be short-lived bursts of requests/responses. To the network admin, opening up for WebSockets means adding additional resources to keep networking infra from shutting connections that exceed typical HTTP response lifecycle duration. This common pitfall exists in proxies on client or server side that may not offer (or un-configured) support to the HTTP ‘CONNECT’ command, which thwarts WebSocket connection handshaking to occur.
NOTE: With WebSockets, you will have many long lived connections. Special configuration for intermediate proxies is warranted for this reason. Additionally, connection scalability at the edge is a concern. One will need to review for network changes that introducing a WebSocket application will require for example proxy handling, and load-balancing.
To the Demo!
I have used [start.spring.io] to help setup several simple WebSocket oriented modules. I will demonstrate some of the more interesting and (often overlooked) aspects when starting up a WS Service with Spring 5.
Code is here: github.com/marios-code-path/spring-web-sockets.
A really cool compendium of WEB networking technologies (WS, RTC included)
The IANA WebSocket (sub)Protocol Registry is where you will find specifications for STOMP, MQTT, XMPP and many more.
The Reactive Manifesto.
Reactive operators. Substantial reference.
This article does as fine job of explaining WebSocket technology underpinnings, and how to stand up a JEE 7 (Glassfish) Websocket Service (JSR-356).
The SockJS protocol is fairly portable/multiplatform. You can easily stand up a sockJS server with just a few lines of Python, Java, or JS(node.js) code
Security and WebSocket related readings (Don’t get Pwn’d)
Various other articles
- Push Technology WIKI