I have a HTTP-ZeroMQ gateway that accepts POST requests on one end and forwards them on Zmq, then routes the responses back.
The http server is done async with Boost.ASIO and Beast, and runs on a threadpool of 6 threads. Threadpooling is simply done by calling io_service.run()
from multiple threads. The zmq part is quite naive: for each http request it creates a new REQ(tcp) socket and synchronously waits for the response.
This clearly has a poor performance as it creates a new zmq/tcp link for each request and the processing thread is blocked until the response arrives (2-3sec). I would like to make the zmq part async as well, but I have some issues. There's a fairly easy way to make zmq sockets ASIO friendly (here and here), I'm more concerned with threading as zmq docs suggest using a the socket from the creating thread only.
I have 3 options in mind:
- Have a zmq socket in each threadpool thread with thread_local. In this case I didn't find any way to tell ASIO to run the zmq socket read completion handler on the right thread (which created the socket). If ran in a different thread the handler will see a different thread_local socket, not the one that's available for read.
- Similar to above: one socket/thread, but not with thread_local. In this case I don't see any guarantee that the socket is accessed from the right thread, or the socket migration requirement between threads is met
- Have a single socket that is protected by a mutex (AFAIK, that does a full memory barrier required for zmq socket migration between threads), but having a single shared resource for all threads doesn't scale well, I don't like it
The server does some data processing as well, so I don't want to make it single threaded.
So, any idea how to elegantly handle zmq sockets async in multi threaded ASIO app?
ps: I did see AZMQ, but I don't want to pull in another 3rd party lib right now.