Websocket Scale Challenges and Best Practices

Author

Reads 809

People sitting at a conference casually checking smartphones, communicating and networking.
Credit: pexels.com, People sitting at a conference casually checking smartphones, communicating and networking.

Scaling WebSockets can be a challenge, but understanding the underlying issues can help. WebSockets can handle a large number of connections, but the number of concurrent connections is limited by the available system resources.

One key challenge is connection overhead, which can lead to a significant increase in memory usage. This can be mitigated by implementing a connection pooling strategy.

To ensure efficient resource utilization, it's essential to monitor system resources closely. This includes tracking metrics such as CPU usage, memory usage, and network traffic.

If this caught your attention, see: Websocket Create Connection

What Are WebSockets?

WebSockets are a bi-directional communication protocol built over TCP, which allows client and server to communicate in a message-oriented way with less overhead.

This connection established between client and server is long-lived, meaning it's kept open as long as it's needed, making it perfect for real-time communication needs.

A usual WebSocket connection has a specific lifecycle, which includes sending a connection upgrade request via HTTP, converting the underlying TCP connection to a WebSocket protocol, and exchanging messages between the client and server until one of them sends a close message.

Explore further: Sec Websocket Protocol

Credit: youtube.com, How to scale WebSockets to millions of connections

WebSockets are often the only solution for real-time communication needs within a browser context, thanks to their ability to provide low latency and delay.

Here's a brief overview of the WebSocket lifecycle:

  • The client sends a connection upgrade request via HTTP.
  • The server takes this request and converts the underlying TCP connection to a WebSocket protocol.
  • Messages are exchanged between the client and server over this connection until one of them sends a close message.

In a nutshell, WebSocket is a real-time web technology that enables bidirectional, full-duplex communication between client and server over a persistent connection.

This connection is kept alive for as long as needed, allowing the server and the client to send data at will, with minimal overhead.

Broaden your view: Client Websocket C#

Scaling WebSockets

Scaling WebSockets can be a challenging task, but there are some key strategies to keep in mind.

To scale WebSockets, you can use horizontal scaling, which involves adding more servers to your system to distribute the load. This approach is effective, but it can be complex to implement.

In a horizontally scaled WebSocket system, each server handles a portion of the WebSocket connections. This requires a load balancer layer that can handle traffic at scale. Load balancers detect the health of backend resources and redirect traffic to operational servers.

Curious to learn more? Check out: Load Balancer Websockets

Credit: youtube.com, How to scale WebSockets to millions of connections

The key steps to scale WebSockets horizontally include setting up multiple WebSocket servers in a cluster, distributing connections across multiple stateless nodes, and using a load balancer to efficiently route messages to the right connection.

To ensure horizontal scalability, you need to ensure the servers share the compute burden evenly. This can be achieved by using a load balancer that can handle traffic at scale.

Here are the key considerations for horizontal scaling:

  • Global load balancing
  • Shared or replicated state
  • Efficient routing of messages to the right connection across the network

By following these strategies, you can effectively scale your WebSocket application and handle a large number of concurrent users.

Approaches to Scaling

Scaling WebSockets requires a solid understanding of the challenges involved. There are two main architectural approaches to address these challenges: vertical scaling and horizontal scaling.

Vertical scaling involves scaling up individual machines, but this method can be complex and inflexible. On the other hand, horizontal scaling across a distributed network of machines offers more flexibility and resilience.

Credit: youtube.com, How to horizontally scale up websocket servers

Ably, a WebSocket platform, uses horizontal scaling to achieve reliable performance at any scale. Their globally-distributed network of datacenters and edge acceleration points-of-presence is a key factor in their ability to handle high traffic.

Horizontal scaling can be achieved through dynamic elasticity, which allows the system to quickly scale to handle any demand. Ably's platform can handle billions of WebSocket messages sent to millions of pub/sub channels and WebSocket connections.

Here are some key benefits of horizontal scaling:

  • Guaranteed message ordering and delivery
  • Global fault tolerance and a 99.999% uptime SLA
  • Less than 50ms round-trip latency (P99)

To achieve this level of scalability, a distributed signaling service must meet certain requirements. Two key constraints are distributedness and balance. Distributedness requires that messages be forwarded correctly across instances, even if the sender and recipient are not registered to the same instance. Balance requires that the load across instances remains balanced, even when instances are added or removed dynamically.

Managing Connections

Managing connections is a crucial aspect of scaling WebSockets. A well-tuned server with an event-driven architecture can handle tens of thousands of concurrent WebSocket connections.

Credit: youtube.com, WebSockets Aren’t as Reliable as You Think.. Here's Why

To manage connections effectively, you should consider implementing heartbeats, which are periodic "pings" between the client and server to confirm the connection is still alive. Heartbeats help detect dropped or dead connections that haven’t been properly closed.

Even if a connection hasn’t been closed, it may no longer be serving an active user. Idle timeouts allow servers to reclaim memory, file descriptors, and other resources by closing connections that have been inactive for a predefined period.

Backpressure is also essential to protect your infrastructure from being overwhelmed when clients slow down. The server can apply backpressure by buffering messages up to a safe limit, delaying delivery, or dropping non-critical messages.

Here are some strategies to help manage connections:

  • Use a load shedding strategy to detect congestion and fail gracefully when a server approaches overload.
  • Implement a backoff mechanism to prevent rejected clients from attempting to reconnect immediately.
  • Consider dropping existing connections to reduce the load on your system.
  • Aim to have a homogeneous server farm to balance load efficiently and evenly across machines.

By implementing these strategies, you can ensure that your WebSocket connections are managed effectively, even at scale.

Connection Lifecycle

Managing the lifecycle of WebSocket connections is crucial for a scalable system. You need to detect dead connections, reclaim resources from idle ones, and manage flow control to avoid overloading slow clients.

Credit: youtube.com, Albertas Gimbutas - Scaling Websockets

A key part of connection lifecycle management is detecting dead connections through heartbeats, which are periodic "pings" between the client and server to confirm the connection is still alive. Heartbeats should be sent at regular intervals, and systems should disconnect peers that don't respond within a defined timeout period.

Even if a connection hasn't been closed, it may no longer be serving an active user. Idle timeouts allow servers to reclaim memory, file descriptors, and other resources by closing connections that have been inactive for a predefined period.

To protect your infrastructure from being overwhelmed, you need to apply backpressure by buffering messages up to a safe limit. Beyond that, it may delay delivery or drop non-critical messages. This keeps your system responsive for everyone and avoids memory buildup that could take down entire servers.

Here are three key parts of connection lifecycle management:

  • Heartbeats: periodic "pings" between client and server to confirm connection is still alive
  • Idle Timeouts: closing connections that have been inactive for a predefined period
  • Backpressure: buffering messages up to a safe limit to avoid overwhelming the system

Best Practices

Scaling WebSockets requires careful planning and execution to ensure reliability and scalability. You've got your architecture in place, now it's time to apply lessons from the real world.

Credit: youtube.com, Scaling Websockets with Redis, HAProxy and Node JS - High-availability Group Chat Application

Use event-driven, non-blocking infrastructure to support high concurrency. This approach allows you to handle a large number of connections without compromising performance.

Externalize session and message state to avoid tight coupling to individual servers. This design pattern ensures that your system remains flexible and adaptable to changing traffic patterns.

Monitoring is crucial to identifying potential issues before they become major problems. Keep an eye on metrics like connection count, error rates, latency, and reconnect frequency.

Test your system at scale with production-like traffic patterns to ensure it can handle the demands of a live environment.

To ensure seamless reconnections, build client logic that supports reconnection, fallback, and session recovery. This will help minimize disruptions and maintain a smooth user experience.

Here are some key best practices to keep in mind when scaling WebSockets:

  • Use horizontal scaling rather than vertical scaling.
  • Use smaller machines (servers) rather than large ones.
  • Choose a load balancing algorithm that takes into account your specific use case and parameters.
  • Ensure your server layer is dynamically elastic and has capacity margin.
  • Support fallback transports, such as Comet long polling.
  • Run load and stress testing to understand your system's behavior under peak load.
  • Implement a robust real-time monitoring and alerting stack.
  • Use a random exponential backoff mechanism when handling reconnections.
  • Keep track of idle connections and close them.

Scalable Architecture

A scalable WebSocket architecture is crucial for handling a large number of connections and messages. This is achieved through a distributed system that can handle any demand, with billions of WebSocket messages sent to millions of pub/sub channels and WebSocket connections.

Credit: youtube.com, Short Polling vs Long Polling vs WebSockets - System Design

Ably's WebSocket platform is a great example of this, with a globally-distributed network of datacenters and edge acceleration points-of-presence. This ensures that messages are delivered quickly, with a round-trip latency of less than 50ms (P99).

To guarantee message ordering and delivery, a system must ensure that messages are correctly forwarded to their intended recipient, even if they are not registered to the same instance as the sender. This is a key requirement for a scalable distributed signaling service.

Here are some key design considerations for a scalable WebSocket architecture:

A good example of this is Dyte's WebSocket layer, which consists of three layers: edge, message broker, and hub. Each layer has a specific responsibility, such as maintaining WebSocket connections or processing messages.

To keep the edge layer light and scalable, it's essential to limit its responsibility to only handle WebSocket connections and relay messages. This allows for rapid scaling in response to increasing load.

Balancing and Fallbacks

Credit: youtube.com, NGINX+ and Highly Available WebSockets in an Auto-Scaling AWS Environment | SolvIT Inc.

To ensure WebSocket connections are distributed evenly across servers, implement a load balancer that uses algorithms like weighted round-robin or least-loaded to determine how to route incoming requests.

A load balancer acts as a traffic cop, ensuring each server receives a fair share of connections. This is crucial for maintaining high availability and reliability in your system.

For systems with many simultaneous users, consider the impact of fallbacks on availability. If a significant proportion of WebSocket connections fall back to long polling, your server will experience increased demand and resource usage.

To mitigate this, ensure your server layer is elastic and can scale to handle the increased load. You may also consider using different server farms for WebSocket and non-WebSocket traffic.

Some common load balancing algorithms include:

  • Round-robin: Each server gets an equal share of traffic.
  • Weighted round-robin: Each server gets a different share of traffic based on capacity.
  • Least-connected: Each server gets a share of traffic based on how many connections it currently has.
  • Least-loaded: Each server gets a share of traffic based on how much load it currently has.
  • Least response time: Traffic is routed to the server that takes the least time to respond to a health monitoring request.

Failing to implement a load balancing strategy can lead to performance degradation and decreased system availability.

Planning For Fallbacks

Planning for fallbacks is crucial to ensure a consistent experience for your users, even in the face of restrictive firewalls, proxies, or legacy environments. Clients should be able to establish a fallback transport mechanism like Server-Sent Events (SSE) or long polling.

Close-up of a hand adjusting network equipment in a data center.
Credit: pexels.com, Close-up of a hand adjusting network equipment in a data center.

Failing to plan for fallbacks can lead to a poor user experience and even system crashes. It's essential to consider the impact that fallbacks may have on the availability of your system. Suppose you have many simultaneous users connected to your system, and an incident causes a significant proportion of the WebSocket connections to fall back to long polling.

Your server will experience greater demand as long polling is more resource-intensive than WebSockets. To ensure your system's availability and uptime, your server layer needs to be elastic and have enough capacity to deal with the increased load.

Here are some key considerations for planning fallbacks:

  • Support fallback transport mechanisms like Server-Sent Events (SSE) or long polling.
  • Implement an exponential backoff strategy with jitter to avoid overwhelming the server with repeated reconnect attempts.
  • Consider the impact of fallbacks on system availability and plan accordingly.
  • Ensure your server layer is elastic and can handle increased load.
  • Use a random exponential backoff mechanism when handling reconnections to protect your server layer from being overwhelmed.

By planning for fallbacks, you can ensure a consistent user experience even in the face of system failures or restrictions.

Balancing

Balancing is a crucial aspect of load balancing, and it's essential to understand the different algorithms and strategies that can be used to distribute traffic evenly among servers.

Credit: youtube.com, TrueFoundry AI Gateway - Model / LLM Routing | Load Balancing, Fallback, Retries | Product Demo

Load balancing algorithms, such as round-robin, weighted round-robin, and least-connected, can help ensure that each server receives a fair share of connections.

A round-robin approach, for example, assigns an equal share of traffic to each server, while weighted round-robin takes into account the capacity of each server.

The least-connected algorithm, on the other hand, assigns a share of traffic based on the number of connections each server currently has.

Hashing methods can also be used to route traffic based on a hash of various data from the incoming connection, such as port number, domain name, and IP address.

It's also worth noting that the choice of algorithm will depend on the specific use case and the characteristics of the traffic.

Here are some common load balancing algorithms:

It's also worth noting that a homogeneous server farm is much easier to balance load efficiently and evenly across machines with different configurations.

Connection Management

Connection Management is a crucial aspect of WebSocket scaling. A well-designed connection management strategy can help you handle a large number of concurrent connections while maintaining system stability.

Credit: youtube.com, how to scale websockets to millions of connections

To detect dead connections, use heartbeats – periodic "pings" between the client and server to confirm the connection is still alive. This helps detect dropped or dead connections that haven’t been properly closed.

Heartbeats should be sent at regular intervals, and systems should disconnect peers that don’t respond within a defined timeout period. This is especially useful during traffic surges, when resource efficiency becomes critical.

Even if a connection hasn’t been closed, it may no longer be serving an active user. Idle timeouts allow servers to reclaim memory, file descriptors, and other resources by closing connections that have been inactive for a predefined period.

To manage flow control and avoid overloading slow clients, implement backpressure. This involves buffering messages up to a safe limit, delaying delivery, or dropping non-critical messages when a client slows down.

Here are some key considerations for designing effective backpressure policies:

  • Buffer thresholds
  • Priority-based message handling

A load shedding strategy is necessary to detect congestion and fail gracefully when a server approaches overload. This involves rejecting some or all of the incoming traffic and implementing a backoff mechanism to prevent rejected clients from attempting to reconnect immediately.

To shed connections, consider dropping existing idle connections to reduce the load on your system. This can be done by closing connections that have been inactive for a predefined period.

Performance Optimization

Credit: youtube.com, Serverless WebSockets at Scale | Simon Tabor | Code Mesh V 2020

To scale WebSockets, you need to optimize performance. Using protobuf to serialize and deserialize messages can be effective, resulting in a 40% smaller message payload compared to JSON.

This not only reduces the amount of data being transmitted but also provides an automated way to handle API contracts between client and server. Faster encoding and decoding times are also a bonus.

Batching messages by sending multiple messages over a single network call is another network optimisation that helps process large numbers of messages. This prevents excess system calls and reduces latency caused by repetitive network calls.

Here are some key performance optimization techniques to keep in mind:

  • Use protobuf for message serialization and deserialization.
  • Implement batching to reduce system calls and latency.

Use Cases and Examples

When you're dealing with a single instance of a signaling server, things are relatively straightforward. You can use a basic implementation found in online tutorials on creating a live chat WebSocket server.

A single instance of a signaling server makes it easier to reason about the task at hand. You can use any language and HTTP library you like to start a basic WebSocket server that listens for requests from clients who want to register with the signaling service.

Check this out: Websocket Use Cases

Credit: youtube.com, WebSockets in 100 Seconds & Beyond with Socket.io

To implement this, you'll want to retain a mapping of registered clients to their WebSockets in an in-memory associative structure, such as a hashmap or dictionary. This allows you to forward messages to the correct client.

Here's a basic outline of the process:

  • Start a basic WebSocket server that listens for requests from clients.
  • Retain a mapping of registered clients to their WebSockets in an in-memory associative structure.
  • Forward messages to the correct client based on the recipient's clientId.

A pseudo-code implementation could look like this:

In a single instance scenario, any basic implementation should work. It generally boils down to the following steps: starting a WebSocket server, retaining a mapping of registered clients, and forwarding messages to the correct client.

Platforms and Solutions

Ably is a reliable WebSocket platform that works at any scale, providing a globally-distributed network of datacenters and edge acceleration points-of-presence.

It offers pub/sub messaging over serverless WebSockets, with features like message delta compression, automatic reconnections with continuity, user presence, message history, and message interactions. Ably's APIs and SDKs help developers build and deliver real-time experiences without worrying about scaling messy WebSocket infrastructure.

Ably's managed infrastructure abstracts away operational complexity, providing horizontal scalability, resilience through automatic failover and load balancing, built-in support for fallback transports and message buffering, and more.

Here are some key features of managed WebSocket solutions like Ably:

  • Horizontal scalability out of the box
  • Resilience through automatic failover and load balancing
  • Built-in support for fallback transports and message buffering
  • Protocol interoperability, analytics, and QoS guarantees

With Managed Infrastructure

Credit: youtube.com, Zeeve Platform Overview - Blockchain Infrastructure Management Platform

With managed infrastructure, you can offload complexity and focus on product development. WebSockets are a powerful tool for bidirectional communication, but they come with substantial engineering overhead.

Managed services like Ably provide elastic, global infrastructure that abstracts away much of the operational complexity. They offer horizontal scalability, resilience, and built-in support for fallback transports and message buffering.

Using a managed provider can drastically reduce time-to-market and ongoing operational risk. This allows engineering teams to focus on product development rather than infrastructure maintenance.

For a scalable distributed signaling service, you'll need to consider the distributedness and balance constraints. The system must guarantee that messages are forwarded correctly, even if clients are not registered to the same instance.

The balance constraint requires load balancing across instances, including when instances are added or removed dynamically. This ensures that the system remains auto-scalable.

Here are the key benefits of managed infrastructure:

  • Horizontal scalability out of the box
  • Resilience through automatic failover and load balancing
  • Built-in support for fallback transports and message buffering
  • Protocol interoperability, analytics, and QoS guarantees

Ably, The Platform That Works Reliably At Any Scale

Credit: youtube.com, Ably 101 serverless websockets at scale

Ably is a platform that works reliably at any scale. It's a real-time experience infrastructure provider that helps developers build and deliver real-time experiences without worrying about maintaining and scaling messy WebSocket infrastructure.

Ably's APIs and SDKs offer pub/sub messaging over serverless WebSockets, with features like message delta compression and automatic reconnections with continuity. This ensures that messages are delivered efficiently and reliably, even in the presence of network failures or disconnections.

Ably's globally-distributed network of datacenters and edge acceleration points-of-presence ensures that data is processed quickly and efficiently, with a round-trip latency of less than 50ms (P99). This is crucial for real-time applications that require fast and reliable data delivery.

Ably's guaranteed message ordering and delivery, combined with its global fault tolerance and 99.999% uptime SLA, make it an ideal choice for mission-critical applications. With Ably, developers can focus on building their applications without worrying about the underlying infrastructure.

Here are some key features of Ably's platform:

  • Pub/sub messaging over serverless WebSockets
  • Message delta compression
  • Automatic reconnections with continuity
  • Globally-distributed network
  • Guaranteed message ordering and delivery
  • Global fault tolerance
  • 99.999% uptime SLA
  • Less than 50ms round-trip latency (P99)

Disadvantages and Challenges

Credit: youtube.com, How to scale WebSockets to millions of connections

Vertical scaling for WebSockets may seem attractive, but it has its limitations. You can only add so much to a single server before it becomes a bottleneck.

Vertical scaling can lead to a single point of failure, making it unsuitable for product systems. This means if your WebSocket server fails or needs maintenance, you're left with a big problem.

Some server technologies, like NodeJS, can't take advantage of extra CPU cores, making it harder to scale. Running multiple server processes can help, but you'll need another mechanism, like a reverse proxy, to balance traffic.

Horizontal scaling is the recommended approach for WebSockets, but it comes with its own set of challenges. Ensuring servers share the compute burden evenly requires a load balancer layer that can handle traffic at scale.

Load balancers detect the health of backend resources and redirect traffic if a server goes down. However, balancing load efficiently across machines with different configurations is a complex task, so aim for homogeneity.

Credit: youtube.com, Why WebSockets Are NOT Scalable | WebSockets Explained

Here are some limitations associated with WebSockets that make scaling challenging:

  • Per-connection memory overhead
  • File descriptors
  • CPU usage
  • Bandwidth
  • Message size

These limitations are per machine, so adding more machines won't necessarily solve the problem. In fact, scaling stateful systems like WebSockets requires a lot of engineering complexity and often involves adding an inter-communication layer to ensure resource consistency.

System Components

To scale a WebSocket application, understanding the system components is crucial.

A WebSocket server is the core component responsible for handling actual WebSocket connections and communication with clients.

Multiple WebSocket servers can be set up in a cluster to distribute the workload and improve performance.

This setup allows for efficient handling of a large number of WebSocket connections and ensures that no single server becomes a bottleneck.

Frequently Asked Questions

What are the metrics of WebSockets?

WebSocket metrics include connection establishment time, latency, message delivery time, throughput, and error rates, providing a comprehensive view of connection health. Understanding these metrics is essential for optimizing WebSocket performance and ensuring reliable communication.

Danny Orlandini

Writer

Danny Orlandini is a passionate writer, known for his engaging and thought-provoking blog posts. He has been writing for several years and has developed a unique voice that resonates with readers from all walks of life. Danny's love for words and storytelling is evident in every piece he creates.

Love What You Read? Stay Updated!

Join our community for insights, tips, and more.