I am managing a PHP 8.2 and Symfony 7-based school management platform hosted on a VPS with 16GB RAM from Hostinger, running Ubuntu and Nginx. My app is a traditional, server-rendered site without a dynamic frontend framework.
The Issue:
issue arises when a user initiates an action that processes a large volume of data in the database, such as generating report cards for an entire class or generating class statistics.
Specifically:
When initiates an action that processes a large volume of data, such as generating report cards for an entire class of 60 students for example, the page displays a “This site can’t be reached
“ error after approximately 30 seconds.
Observations:
- When mass data are handled in the background using Symfony Messenger, the process works flawlessly, even for 1000+ .
- If I segment the data processing such as report card generation (e.g., 10 students at a time), the process completes quickly without errors.
- On my local development environment (Windows 10 with Apache, 8GB RAM), the same tasks complete successfully, regardless of the data size. Even if the process takes 1 to 10 minutes or more, it ultimately generates the expected results.
Actions Taken So Far:
I have explored potential solutions:
-debugging with the command htop when i generate the report cards:
- Upgrade php limit on php.ini from /etc/php/8.2/fpm/php.ini
- -memory_limit=-1
- maximum_time_execution = 3600
- post_max_size = 100M
- upload_max_filesize = 100M
- Upgrade nginx configuration on /etc/nginx/nginx.conf
user www-data;
worker_processes auto;
pid /run/nginx.pid;
error_log /var/log/nginx/error.log;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 1024;
# multi_accept on;
}
http {
# Configurations de timeout globales
proxy_read_timeout 300s; # Temps d'attente pour les proxys
fastcgi_read_timeout 300s; # Temps d'attente pour FastCGI
client_max_body_size 100M;
client_body_timeout 300s;
client_header_timeout 300s;
keepalive_timeout 300s;
send_timeout 300s;
##
# Basic Settings
##
sendfile on;
tcp_nopush on;
types_hash_max_size 2048;
# server_tokens off;
# server_names_hash_bucket_size 64;
# server_name_in_redirect off;
include /etc/nginx/mime.types;
default_type application/octet-stream;
# server_names_hash_bucket_size 64;
# server_name_in_redirect off;
include /etc/nginx/mime.types;
default_type application/octet-stream;
##
# SSL Settings
##
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
ssl_prefer_server_ciphers on;
##
# Logging Settings
##
access_log /var/log/nginx/access.log;
##
# Gzip Settings
##
gzip on;
# gzip_vary on;
# gzip_proxied any;
# gzip_comp_level 6;
# gzip_buffers 16 8k;
# gzip_http_version 1.1;
# Virtual Host Configs
##
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
#mail {
# # See sample authentication script at:
# # http://wiki.nginx.org/ImapAuthenticateWithApachePhpScript
#
# # auth_http localhost/auth.php;
# # pop3_capabilities "TOP" "USER";
# # imap_capabilities "IMAP4rev1" "UIDPLUS";
#
# server {
# listen localhost:110;
# protocol pop3;
# proxy on;
# }
#
# server {
# listen localhost:143;
# protocol imap;
# proxy on;
# }
#}
- here is my mysql configuration
#
# The MySQL database server configuration file.
#
# One can use all long options that the program supports.
# Run program with --help to get a list of available options and with
# --print-defaults to see which it would actually understand and use.
#
# For explanations see
# http://dev.mysql.com/doc/mysql/en/server-system-variables.html
# Here is entries for some specific programs
# The following values assume you have at least 32M RAM
[mysqld]
#
# * Basic Settings
#
user = mysql
# pid-file = /var/run/mysqld/mysqld.pid
# socket = /var/run/mysqld/mysqld.sock
# port = 3306
# datadir = /var/lib/mysql
# If MySQL is running as a replication slave, this should be
# changed. Ref https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_tmpdir
# tmpdir = /tmp
#
# Instead of skip-networking the default is now to listen only on
# localhost which is more compatible and is not less secure.
bind-address = 127.0.0.1
mysqlx-bind-address = 127.0.0.1
#
# * Fine Tuning
#
#
innodb_buffer_pool_size = 6G
#innodb_log_file_size = 512M
innodb_redo_log_capacity = 1G
innodb_flush_log_at_trx_commit = 2
innodb_io_capacity = 1000
# Memory and performance tuning
key_buffer_size = 64M
max_allowed_packet = 128M
thread_stack = 256K
thread_cache_size = 8
# Table cache
table_open_cache = 2000
# Connections
max_connections = 500
#wait_timeout = 3600
#innodb_lock_wait_timeout = 3600
# Temp tables
tmp_table_size = 64M
max_heap_table_size = 64M
# Temp tables
tmp_table_size = 64M
max_heap_table_size = 64M
# MyISAM recover options
myisam-recover-options = BACKUP
#
# * Logging and Replication
#
# Both location gets rotated by the cronjob.
#
# Log all queries
# Be aware that this log type is a performance killer.
# general_log_file = /var/log/mysql/query.log
# general_log = 1
# Error log - should be very few entries.
log_error = /var/log/mysql/error.log
# Here you can see queries with especially long duration
# slow_query_log = 1
# slow_query_log_file = /var/log/mysql/mysql-slow.log
# long_query_time = 2
# log-queries-not-using-indexes
# The following can be used as easy to replay backup logs or for replication.
# note: if you are setting up a replication slave, see README.Debian about
# other settings you may need to change.
# server-id = 1
# binlog_expire_logs_seconds = 2592000
max_binlog_size = 100M
# binlog_do_db = include_database_name
# binlog_ignore_db = include_database_name
- I have also try this to my PHP-FPM Wokers on /etc/php/8.2/fpm/pool.d/www.conf
pm = dynamic
pm.max_children = 20
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 10
Here are the log :