Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Finished Explanation for Leader/Followers #2239 #2733

Merged
merged 6 commits into from
Mar 17, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 84 additions & 9 deletions leader-followers/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,103 @@ title: Leader/Followers
category: Concurrency
language: en
tag:
- Performance
- Performance
---

## Intent
The Leader/Followers pattern provides a concurrency model where multiple
threads can efficiently de-multiplex events and dispatch event handlers
that process I/O handles shared by the threads.
The Leader/Followers design pattern is a pattern used to coordinate a selection of 'workers'. It allows tasks to execute concurrently
with the Leader delegating tasks to the Follower threads for execution. It is a very common design pattern used in multithreaded
situations such as servers, and works to help prevent ambiguity around delegation of tasks.

## Explanation
Real-world Example
> The best real world example of Leader/Followers is a web server. Web servers have to be able to handle a multitude of incoming
> connections all at once. In a web server, the Leader/Followers pattern works by using the Leader to listen to incoming requests
> and accept connections. Once a connection is made to a client the Leader can then find a Follower thread to delegate the task
> to for execution and return to the client. This means that the Leader does not have to wait to finish execution before it can
> accept another incoming connection, and can focus on delegating tasks. This pattern is created to aid in concurrency of applicaitons,
> allowing for many connections to work simultaneously.

In plain words
> You can picture the Leader as a traffic controller that has to direct traffic from one lane into 25 lanes. As a car comes in,
> the Leader sends it down a road that isn't full or busy. This car can then have its request filled, or reach its destination.
> If the Leader had to drive each car down the lane itself, the line would pile up and progress would be slow. But as the Leader
> has Followers that can also drive the cars, the Leader can focus on making the line move quickly and ensuring traffic doesn't
> back up.

Wikipedia says
> A concurrency pattern are those types of design patterns that deal with the multi-threaded programming paradigm.

## Programmatic Example
This example shows Java code that sets up a Leader that listens for client requests on port 8080. Once a request is sent,
the leader will accept it and delegate it to a new Follower to execute. This means that the Leader can keep delegating,
and ensure requests are fulfilled timely. This is only pseudocode and the working code would require a more concrete implementation
of Leader and Followers.
```java
public class LeaderFollowerWebServer {

public static void main(String[] args) throws IOException {
int port = 8080; // the port that clients can reach the leader on
int numFollowers = 5; // the amount of followers we can delegate tasks to

ServerSocket serverSocket = new ServerSocket(port); // pseudocode for creating a socket to the server
ExecutorService executorService = Executors.newFixedThreadPool(numFollowers); // pseudocode to start execution for Followers

System.out.println("Web server started. Listening on port " + port);

while (true) {
Socket clientSocket = serverSocket.accept();
// Accept a new connection and assign it to a follower thread for processing
executorService.execute(new Follower(clientSocket));
}
}
}

class Follower implements Runnable {
private final Socket clientSocket;

public Follower(Socket clientSocket) {
this.clientSocket = clientSocket;
}

@Override
public void run() {
try {
// handle the client request, e.g., read and write data
// this is where you would implement your request processing logic.
// we will just close the socket
clientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
```
## Class diagram
![Leader/Followers class diagram](./etc/leader-followers.png)

## Applicability
Use Leader-Followers pattern when

* multiple threads take turns sharing a set of event sources in order to detect, de-multiplex, dispatch and process service requests that occur on the event sources.
* You want to establish a concurrent application
* You want faster response times on heavy load
* You want an easily scalable program
* You want to load balance a program

## Consequences
Consequences involved with using the Leader/Followers pattern

* Implementing this pattern will increase complexity of the code
* If the leader is too slow at delegating processes, some Followers may not get to execute tasks leading to a waste of resources
* There is overhead with organising and maintaining a thread pool
* Debugging is more complex

## Real world examples

* [ACE Thread Pool Reactor framework](https://www.dre.vanderbilt.edu/~schmidt/PDF/HPL.pdf)
* [JAWS](http://www.dre.vanderbilt.edu/~schmidt/PDF/PDCP.pdf)
* [Real-time CORBA](http://www.dre.vanderbilt.edu/~schmidt/PDF/RTS.pdf)
* ACE Thread Pool Reactor framework
* JAWS
* Real-time CORBA

## Credits

* [Douglas C. Schmidt and Carlos O’Ryan - Leader/Followers](http://www.kircher-schwanninger.de/michael/publications/lf.pdf)
* Douglas C. Schmidt and Carlos O’Ryan - Leader/Followers
Loading