Non-blocking MongoDB Interaction in Swoole
While researching on how to setup a containerized auto-discovering microservice environment using Docker I came across this invaluable article by Graham Jenson. Although I strongly recommend reading it to everyone, the solution provided there is not the subject of this article. At the first step Graham – in his word – builds a very simple service with Docker using python official image; however - the stubborn PHP developer I am - I decided against him and wanted my simple service to be implemented in PHP. That was when it hit me that in PHP – at least in main stream PHP – it is not as straight forward as python. If I want to use php-fpm I need a web server (e.g. Nginx or Apache) as well and I need to either create a container with two running services or two different containers that are aware of each other existence and copy my code to both of them. PHP built-in server (i.e. the infamous php -S) is a single threaded blocking server that is designed to be used in development environment rather than production. Implementing my own non-blocking HTTP server using PHP streams – although tempting – defied the word “simple”. My previous experiments with Ratchet showed that in certain cases a request can hang the entire server making other requests stall for this operation to finish. ReactPHP was another option which I had no experience with, however Ratchet was developed upon it so the end result could not be that different. So I checked Swoole and it was everything I was expecting from a non-blocking HTTP server.
Developing in Swoole requires a good understanding of long running processes and I/O. In contrast to our typical PHP applications that are short-lived (i.e. from the moment a request is received until the response is sent) which allow the garbage collector to easily release the allocated memory at the end of the process, a Swoole application is a long-running process that we should be wary of the way we allocate and release memory (specially resources). Also we should revise the way we implement sessions and work with I/O. If we use any PHP command or library that interacts with I/O in a blocking manner it can gravely affect the throughput of our application. That is why you can see Swoole has a dedicated list of database clients, file-system manipulation functions, shell execution function, or even its dedicated sleep function. Swoole 4.1.0 has come with a feature that - if gets activated - decorates most of this blocking calls with their non-blocking counterparts behind the scenes. The only problem is that there is no mongodb client at the moment and PHP mongodb extension is one of those nefarious blocking ones. Since most of the services that I am recently working on are using MongoDB as their persistence layer, I was motivated to examine the issue more in depth and find a workaround for the problem for the time being. Here I share the result with you using this github repository – non-blocking mongodb interaction in Swoole.