1

I'm trying to write an application server in python. I have a master process and multiple worker processes created from the master using fork(). I have two approaches in mind about how the workers should handle request data.

  1. Using pipes pass data received by the master using accept() to an idle worker. The worker receives the data, processes it and sends data through another pipe back to the master which sends it back to the client.
  2. Since the workers inherit the listening socket file descriptor from the master, make each worker call accept(). In this case, I'm assuming the kernel will decide which worker the data should be given to.

What are the pros and cons to the above two approaches?

1

1 Answer 1

0

If all data is sent through the coordinator process, then that coordinator process becomes a bottleneck and a completely unnecessary level of buffering. So your first solution should be avoided.

There are a couple of alternatives to distribute the load over multiple worker processes:

  • Have one accept() loop in the coordinator process, then fork() off a worker process within that loop to handle the accepted socket. This is the classic daemon design and is easy to implement in C or Perl. But it can be difficult to implement correctly with Python because forking has surprising interactions with multithreading – and your Python program might be running more threads than you would expect.

  • Have one accept() loop in the coordinator process, then send the accepted socket's file descriptor to the worker process over an AF_UNIX socket with an SCM_RIGHTS message. This is similar to dup()ing the fd across a process boundary. This can be an elegant solution that allows the coordinator process to decide which worker process will handle the connection.

  • Have all worker processes run their own accept() loop, but let them listen on a shared port by using the SO_REUSEPORT flag. The kernel then decides which worker process receives an incoming connection. This is most appropriate for a load balancing scenario because the coordinator process does not interfere with the connection, but this does not work with all kinds of sockets.

    This is similar to your second solution where you start to listen on a port and then fork the worker processes, except that it is not necessary to start listening before forking and that either solution will only work with SO_REUSEPORT.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.