Threads and Connections in Backend Applications

by Rahul sain on

Listener

When a program wants to communicate over the internet, it opens a "socket", which is like a door that others can knock to talk to the program.

Accepter

When someone knocks on the door (socket), the program needs to decide whether to let them in or not.

Reader

Once the connection is established, data starts flowing through it. This data isn't neatly packaged like email; it's more like a continuous stream of bytes. The reader's job is to make sense of this stream by organizing it into meaningful pieces, understanding where one message ends and another starts.

TCP (Transmission Control Protocol)

TCP is the underlying protocol that ensures data gets from one place to another reliably. It doesn't care about the structure of the data itself. It's like a delivery truck that transports packages. The reader's job is to unpack the packages and make sense of them, like understanding the individual requests being sent on the internet.

Architecture Patterns

Single Threaded Architecture

In this architecture, the backend application handles all aspects of connection management, including listening for incoming connections, accepting them, and processing the data streams. This approach is simple and straightforward but may struggle to handle high loads efficiently due to its single-threaded nature.

Example: Node.js operates a single-threaded event loop model where a single thread manages all incoming requests and responses.

Multiple Threads Single Acceptor Architecture

The Multiple Threads Single Acceptor Architecture is a design pattern used in building performant backend applications that leverage multi-threading to take advantage of all CPU cores. In this architecture, a single listener thread is responsible for accepting connections, but each accepted connection is handed over to a separate worker thread for processing.

How this architecture works

  1. Single Listener Thread: There is only one listener thread responsible for accepting incoming connection requests. This thread binds to a specific IP address and port, waiting for clients to establish connections.
  2. Connection Acceptance: When a client initiates a connection request, the listener thread accepts it. However, instead of processing the data itself, the listener thread delegates the connection to another worker thread.
  3. Worker Threads: Each accepted connection is handed over to a separate worker thread for processing. These worker threads are responsible for reading data from the connection, performing any necessary computations or operations, and generating responses.
  4. Maximizing CPU Utilization: The number of worker threads can be configured based on the number of CPU cores available. A common rule-of-thumb is to have one thread per CPU core. This ensures that each CPU core is fully utilized, maximizing overall performance.
  5. Shared Connections: To prevent excessive thread creation and memory consumption, multiple connections may be shared among worker threads. This means that each thread is responsible for processing multiple connections concurrently.

Overall: The Multiple Threads Single Acceptor Architecture offers a balance between performance and complexity, allowing backend applications to efficiently utilize multi-core CPUs while managing incoming connections effectively.

Multiple Threads Multiple Acceptors Architecture

In the Multiple Threads Multiple Acceptors Architecture, a single listener thread is responsible for creating the socket and placing it in shared memory accessible to other threads. Multiple worker threads are then created, each of which calls accept on the shared socket object to accept incoming connections. In this model, each worker thread takes on the dual role of acceptor and reader, handling both the acceptance of connections and the processing of data.

How this architecture works

  1. Shared Socket Object: This listener thread creates a socket and places it in shared memory where other threads can access it. This allows multiple threads to accept connections from the same socket.
  2. Worker Threads: Each worker is responsible for calling accept on the shared socket object to accept incoming connections. Once a connection is accepted, the thread takes ownership of that connection and becomes responsible for processing data from it.
  3. Dispersed Connection Management: By dispersing the responsibility of connection management to local threads, this architecture aims to improve concurrency and performance. Each thread handles its own set of connections independently.

Example: NGINX, a widely used web server and reverse proxy server, used this architecture by default prior to version 1.9.1. In NGINX, multiple worker processes are created, each of which handles its own set of connections independently, improving concurrency and performance.

Multiple Threads with Message-based Load Balancing Architecture

In this special architecture used by systems like RAMCloud, connections and work are handled differently. Instead of just passing connections to different workers, there's a special "listener" who not only listens for connections but also reads and sorts the messages that come through. Once the messages are sorted out, they're given to different worker threads to handle.

This setup ensures that no worker gets too overloaded with work while others sit idle. However, the listener, which reads and sorts messages, can sometimes become overwhelmed, slowing things down. Techniques like optimized message handling can mitigate these issues.

Peer-to-Peer (P2P) Architecture

Peer-to-Peer (P2P) architecture allows computers to communicate and share resources directly with each other without relying on a central server. Each computer, or peer, can act as both a client and a server, enabling them to exchange data and services directly.

How this architecture works

  1. Decentralization: There's no central server controlling everything. Peers communicate directly with each other.
  2. Autonomy: Each peer can join or leave the network without needing permission from a central authority.
  3. Resource Sharing: Peers can share files, computing power, and other resources with each other.
  4. Scalability: P2P networks can easily grow by adding more peers without relying on a single server.

Example: File Sharing & Streaming Media

Serverless Architecture

Serverless architecture is a cloud computing model where cloud providers manage the infrastructure, allowing developers to focus on writing code without worrying about server management. In this architecture, applications are broken down into smaller functions that run in response to events, autoscaling and managed by the cloud provider. This model offers benefits such as reduced operational costs, improved scalability, and faster time to market.

How this architecture works

  1. Event-driven: Functions are triggered by events such as HTTP requests, database changes, or file uploads.
  2. Scalability: Functions can scale automatically based on demand, ensuring optimal performance without provisioning or managing servers.
  3. Pay-as-you-go: Developers only pay for the compute resources used, rather than provisioning and paying for fixed server instances.
  4. Microservices: Applications are composed of independent functions that can be developed, deployed, and scaled individually, promoting agility and modularity.

Example: AWS Lambda, Azure Functions, Google Cloud Functions

Microservices Architecture

Microservices architecture is an approach to building applications as a set of loosely coupled, independently deployable services. Each service is responsible for a specific business function and communicates with other services through APIs. This architecture promotes scalability, flexibility, and continuous delivery, enabling teams to independently develop, deploy, and scale services.

How this architecture works

  1. Decentralization: Each microservice is self-contained and independently deployable, allowing teams to develop, deploy, and scale services without affecting other parts of the application.
  2. Service Communication: Services communicate through lightweight protocols such as HTTP/HTTPS or messaging queues, enabling seamless integration and decoupling.
  3. Scalability: Individual services can be scaled independently based on demand, optimizing resource utilization and improving performance.
  4. Resilience: Failure in one service does not impact the entire application, as other services can continue to function independently.

Example: Netflix, Amazon, Uber, Spotify