Configuring a low memory VPS for NGINX, PHP-FPM and MariaDB.

I recently moved this web site and a dozen others to a new VPS, in the process I went from an Apache HTTPD server to NGINX with PHP being handled by PHP-FPM. The base OS is just a minimal build CENTOS 7 which is very much end of life, normally I deploy Oracle Linux 8.8 VM’s but Linode didn’t have an ISO image of one and I was constrained by time to move.

PHP-FPM

The initial build of the VPS was 1G of memory with 1 CPU, once I deployed all the websites I watched the CPU performance and memory consumption using “atop” and “top” and used “free” periodically to see the memory usage in a more simplified form. During a busy period the server stalled at 35 php-fpm processes running, doing a quick calculation showed all memory consumed! I was planning to upgrade the memory to the next Plan which has 1x CPU and 2G of RAM, but first I needed to define some parameter for Mariadb and PHP-FPM.

First I needed to reduce the number of processes that php-fpm could spawn, the default pool is called “www” and is located in /etc/php-fpm.d/www.conf. I locked the service down to the following parameters:

pm = dynamic
pm.max_children = 11
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 10

To get an idea of the memory consumption of php-fpm I used the command shown below which I found while researching this article. This command is looking for the process name “php-fpm” so this may need to be adjusted to suit your environment.

ps --no-headers -o "rss,cmd" -C php-fpm | awk '{ sum+=$1 } END { printf ("%d%s\n", sum/NR/1024,"M") }'

I also used “atop” to view the memory usage (press “m” when running) and it yielded the following (abbreviated) output after I opened a few websites:

78.0M 0B 0B 0B 2.1M nginx nginx 4% php-fpm
77.0M 0B 0B 0B 2.2M nginx nginx 4% php-fpm
73.5M 0B 0B 0B 2.0M nginx nginx 4% php-fpm
67.2M 0B 0B 0B 2.1M nginx nginx 4% php-fpm
66.6M 0B 0B 0B 2.1M nginx nginx 4% php-fpm
64.5M 0B 0B 0B 2.0M nginx nginx 4% php-fpm
63.8M 0B 0B 0B 2.1M nginx nginx 3% php-fpm
62.7M 0B 0B 0B 2.1M nginx nginx 3% php-fpm
61.7M 0B 0B 0B 2.1M nginx nginx 3% php-fpm
58.1M 0B 0B 0B 2.2M nginx nginx 3% php-fpm

“atop” showed memory usage ranging between 58M and 78M. With 10 processes running (max_spare_servers), the average is approximately 58M to 66M so 10 processes would use upwards of 660M of the 1G total RAM.

MariaDB startup usage

On startup the mariadb version I was using appeared to suck in as much ram as it could, this appears to be used by the “performance_schema” so I added the command “performance_schema = off” to the “[mysqld] section of the file /etc/my.cnf.d/server.conf

This file also has the bind address which is set to bind-address = 127.0.0.1 which is a must on a public facing VPS where the DB is not remotely connected to.

Daily performance

I upgraded the VPS to the 2G plan after the initial performance tweaks (as originally planned) and I’ve been monitoring the memory usage over a 7 day period with visitors coming to each site, the memory barely goes above 75%

The “free -mh” command typically returns the following on average:

[root@vps# free -mh
      total  used  free  shared  buff/cache  available
Mem:   1.8G  849M  203M     22M        784M       805M
Swap:  511M  140M  371M

Ongoing Monitoring

I crafted a quick and dirty shell script to record memory usage and save it as a CSV file so I could graph the data when needed. Each file is 24 hours of memory with averages derived from SAR every 10 minutes. The SAR data is captured 4 times an hour via cron. The 10 minute capture is the system setup defaults.

The output is as follows:

12:00:01,AM,kbmemused,%memused,kbbuffers
12:10:01,AM,1128668,59.98,8344
12:20:01,AM,1135416,60.34,10808
...
12:30:01,PM,1673160,88.91,47824
12:40:01,PM,1727556,91.80,43328
12:50:01,PM,1625364,86.37,43832
01:00:01,PM,1608104,85.46,44436
Average:,464928,75.29,40133,438057

The script lives in /usr/local/bin

!/bin/bash
#
DATA_DIR=/data/sar
DAILY_FILE="sar-memory-date '+%Y%d%m'.csv"
mkdir -p ${DATA_DIR} > /dev/null 2>&1
OUT_FILE=${DATA_DIR}/${DAILY_FILE}
sar -r |awk '{if ($0 ~ /[0-9]/) { print $1","$2","$4","$5","$6; } }'|tail -n +2  > ${OUT_FILE}

To run it from CRON:

*/15 * * * * /usr/local/bin/sar-memory-csv.sh

Enjoy!

-oOo-

You may also like...

Popular Posts