There are multiple tips and suggestions which must be acknowledged while running RoadRuner on production.
State and memory
State and memory are not shared between different worker instances but are shared for a single worker instance. Since a single worker typically process more than a single request, you should be careful about it:
- Make sure to close all descriptors (especially in case of fatal exceptions).
- [optional] consider calling
gc_collect_cyclesafter each execution if you want to keep the memory low (this will slow down your application a bit).
- Watch memory leaks - you have to be more picky about what components you use. Workers will be restarted in case of a memory leak but it should not be hard to completely avoid this issue by properly designing your application.
- Avoid state pollution (i.e. globals or user data cache in memory).
- Database connections and any pipe/socket is the potential point of failure. Simple way of dealing with it is to close all connections after each iteration. Note that it is not the most performant solution.
- Make sure NOT to listen 0.0.0.0 in RPC service (unless in Docker).
- Connect to a worker using pipes for higher performance (Unix sockets just a bit slower).
- Tweak your pool timings to the values you like.
- A number of workers = number of CPU threads in your system, unless your application is IO bound, then pick the number heuristically.
- Consider using
maxJobsfor your workers if you experience any issues with application stability over time.
- RoadRunner is +40% performant using Keep-Alive connections.
- Set memory limit to least 10-20% below
- Since RoadRunner workers run from cli you need to enable OPcache in CLI via
- Make sure to use health check endpoint when running rr in a cloud environment.
useroption in the config to start workers processes from the particular user on Linux based systems.