Using WebSockets for Real-Time Updates in a Serverless Web Application
Are you looking for a solution to get instantaneous, real-time updates within your application? WebSockets can do just that. WebSockets are bidirectional communication channels between a client and a server that enables data to flow freely and asynchronously. This type of protocol is used in cases where the client needs to be aware of changes on the server side in a timely manner, ensuring that all information presented is as current as possible.
Here’s a quick look at how this works: First, the client sends out a typical request to the server to establish a WebSocket connection with the server. Then, the server responds with a handshake, agreeing to use the socket as a connection link between the two. Pretty straightforward.
Why use WebSockets?
The main advantage of WebSockets is that a server can immediately send out data to clients whenever it needs to. This can be the case for receiving an incoming message or getting a notification that your pizza is ready for pickup. The server simply gets the connections of clients it wants to send the data to, then pushes the data through the channel.
These advantages are meant to alleviate the resource strain that a similar implementation in REST may incur. Typically, if a client using REST wants “real-time-updates” for a specific resource they will have to poll the server every 1 second. This can be quite taxing on the server as the number of clients for your application grows. The client-server diagram below shows the difference between getting data with polling vs WebSockets.
Polling every second can be mitigated with a technique called long-polling where the client opens a request to the server, and the server holds onto that request until an update happens. When an update occurs the server then fulfills the long-polled request. However, long-polling is still more resource-intensive than maintaining a WebSocket connection and has an added layer of complexity. Also, there are only a handful of libraries that support long-polling across the popular programming languages.
Challenges with WebSockets in a Serverless World
WebSockets sound great on paper – a continuous bidirectional communication between a server and a client is powerful for getting data from a server without the need to ask for it. But there are challenges when trying to incorporate this technology with REST API. First, REST APIs are stateless, meaning every API request happens in isolation from one another. In contrast, WebSocket connections are stateful, meaning every connection establishes a TCP connection which can send/receive data if that connection is maintained. This means that while the REST API can communicate to those connected, anything the client sends over the WebSocket needs to be handled in some other stateful environment (typically a database) so that the REST API can use the data the client sends.
Another issue with WebSockets is scalability. The amount of resource overhead to establish a connection, send data, wait for a response, and close the connection typically uses more resources than a REST API would to do the same task. Scaling the WebSockets with the number of clients is also a non-trivial task. Vertically scaling the server to communicate with more WebSocket clients is straightforward. The more power you give the server, the better it performs. However, this type of scaling is limited by obtainable physical hardware. There is only so much CPU/GPU/RAM/STORAGE power you can give a server before price and hardware limitations become an issue. Unfortunately, horizontal scaling (i.e., adding more servers to handle more connections) requires implementing connection strategies like load balancing and publish-subscribe. Thankfully, there are many solutions that exist today that implement these strategies, one of them being AWS (Amazon Web Services) WebSockets API implemented in API Gateway.
The Solution: API Gateway WebSockets
AWS’s API Gateway implementation of WebSockets allows the invoking of HTTP endpoints, Lambdas, or any other AWS service. Each WebSocket deployment needs to have a default route as well as routes for connecting and disconnecting. This is a powerful integration with API Gateway’s REST API as the entire process of connecting, disconnecting, and sending any custom message can be reduced to a lambda function call, HTTP endpoint call, or any other AWS service trigger. This coupling enables effortless storing of connection IDs in databases like RDS or DynamoDB, as well as an easy means to query open connections and users for pushing data through – all without needing to worry about load balancing. On the other hand, synchronization of these resources is the key to overcoming WebSockets in a stateless REST world.
There are other solutions to scaling WebSockets. For example, Google’s cloud infrastructure, Cloud Run, has WebSockets. The main difference between WebSockets on Cloud Run and API Gateway is that some of the container managements (scaling mechanisms) on Cloud Run are configured by the developer. AWS, in contrast, completely manages the connections and their scaling. Another solution recently released is Microsoft Azure’s PubSub. PubSub enabes WebSockets to scale according to the publisher-subscriber connection strategy without worrying about the details of how connections are stored. This differs from API Gateway in terms of customizability. Where AWS allows you to implement different connection strategies and notification patterns, Azure limits the developer to a publisher-subscriber method. Also worth noting, depending on where your other resources lie (AWS vs Azure vs Google Cloud, etc.), integrating across clouds may increase development time.
WebSockets play a significant role when real-time data needs to be sent and received from both ends of an application. We discussed the challenges with scalability and noted situations where REST APIs may be a better choice, like grabbing data that does not change frequently or only needing to grab data when the user needs it. With Serverless being a big part of modern application infrastructures, scaling WebSockets can present challenges, but it’s not as hard as it may seem on the surface when considering modern cloud services by AWS, Microsoft and Google. Simply pick the one that both contains the features you need and integrates most seamlessly into your project.