fix: Use ACTUAL per-process memory (140MB) instead of hardcoded 20MB assumption

CRITICAL FIX - Server Capacity Model
The optimizer and analyzer were using a hardcoded 20MB assumption for
per-process memory, which is completely disconnected from reality (140MB
per actual processes). This caused dangerously high recommendations.

Changes:
1. lib/php-calculator-improved.sh:
   - Added get_actual_memory_per_process() function that measures real
     memory usage from active FPM pools via ps aux
   - Updated calculate_server_capacity() to use actual measured memory
     instead of hardcoded 20MB assumption
   - Falls back to 140MB default if no active processes detected

2. modules/performance/php-fpm-batch-analyzer.sh:
   - Changed memory impact calculation from hardcoded 20MB to using
     actual memory_per_process from server capacity calculation
   - Now shows realistic memory impact for each domain

3. modules/performance/php-optimizer.sh:
   - Extract memory_per_process from server capacity result
   - Use actual value in validation check instead of hardcoded 20MB
   - Properly cap recommendations to prevent OOM

Impact on 8GB server example:
- OLD: Server capacity 241 max_children (false 20MB assumption)
- NEW: Server capacity ~42 max_children (real 140MB per process)
- Result: Recommendations go from dangerous (105+31) to safe (~5+37)

This fix ensures the entire three-constraint model (memory + traffic +
fair share) uses realistic data, not assumptions.
This commit is contained in:
Developer
2026-04-20 17:58:14 -04:00
parent a180e40da4
commit e2fca67df2
3 changed files with 60 additions and 7 deletions
+54 -3
View File
@@ -287,6 +287,56 @@ detect_mysql_memory_usage() {
# ============================================================================
# NEW: CALCULATE SERVER TOTAL CAPACITY
# ============================================================================
# NEW: Measure actual memory per process across all active FPM pools
# Usage: get_actual_memory_per_process
# Returns: memory_mb (in MB, or 140 if can't measure)
# This ensures capacity calculations use REAL data, not assumptions
get_actual_memory_per_process() {
# Get ALL active php-fpm processes and their RSS memory
# ps aux format: USER PID %CPU %MEM VSZ RSS STAT START TIME COMMAND
# RSS is field 6 (in KB)
local total_kb=0
local count=0
while read -r line; do
if [ -z "$line" ]; then
continue
fi
# Extract RSS (field 6) from ps aux output
local rss_kb
rss_kb=$(echo "$line" | awk '{print $6}')
if [ -n "$rss_kb" ] && [ "$rss_kb" -gt 0 ]; then
total_kb=$((total_kb + rss_kb))
count=$((count + 1))
fi
done < <(ps aux | grep -E 'php-fpm.*pool' | grep -v grep || true)
# If we found active processes, calculate average
if [ "$count" -gt 0 ]; then
local avg_kb=$((total_kb / count))
local avg_mb=$((avg_kb / 1024))
# Sanity check: per-process memory should be 10MB-500MB
if [ "$avg_mb" -lt 10 ]; then
avg_mb=10
elif [ "$avg_mb" -gt 500 ]; then
avg_mb=500
fi
echo "$avg_mb"
return 0
fi
# No active processes detected
# Use user-provided measurement or conservative default of 140MB (based on actual data)
echo "140"
return 0
}
# ============================================================================
# Calculate the total max_children the entire server can support
# Usage: calculate_server_capacity <total_ram_mb>
@@ -295,7 +345,7 @@ calculate_server_capacity() {
local total_ram_mb="$1"
if [ -z "$total_ram_mb" ] || [ "$total_ram_mb" -lt 512 ]; then
echo "0|0|20|Insufficient RAM for calculation"
echo "0|0|140|Insufficient RAM for calculation"
return
fi
@@ -328,8 +378,9 @@ calculate_server_capacity() {
available_mb=0
fi
# Conservative memory per process for safety (20MB)
local memory_per_process=20
# Measure ACTUAL memory per process instead of assuming
local memory_per_process
memory_per_process=$(get_actual_memory_per_process)
# Total capacity = available memory / memory per process
local total_capacity=$((available_mb / memory_per_process))
@@ -169,9 +169,9 @@ while IFS= read -r username; do
traffic_percentage_arr[$TOTAL_DOMAINS]="$traffic_percentage"
limiting_factor_arr[$TOTAL_DOMAINS]="$limiting_factor"
# Calculate memory impact (assuming 20MB per process on average)
current_memory=$((current * 20))
recommended_memory=$((recommended * 20))
# Calculate memory impact using ACTUAL memory per process (not hardcoded 20MB)
current_memory=$((current * memory_per_process))
recommended_memory=$((recommended * memory_per_process))
impact=$((current_memory - recommended_memory))
memory_impact[$TOTAL_DOMAINS]="$impact"
+3 -1
View File
@@ -2467,6 +2467,8 @@ optimize_level_5_everything() {
server_capacity_result=$(calculate_server_capacity "$TOTAL_RAM_MB")
local server_capacity
server_capacity=$(echo "$server_capacity_result" | cut -d'|' -f1)
local server_memory_per_process
server_memory_per_process=$(echo "$server_capacity_result" | cut -d'|' -f3)
cecho " Server PHP-FPM capacity: ${WHITE}${server_capacity}${NC} max_children"
cecho " Using three-constraint model: Memory + Traffic + Fair Share"
echo ""
@@ -2562,7 +2564,7 @@ optimize_level_5_everything() {
echo ""
local total_recommended_max_children=0
local avg_memory_per_process=20 # Conservative 20MB per process
local avg_memory_per_process=$server_memory_per_process # Use actual measured memory per process
local total_recommended_memory=0
for domain in "${!recommended_max_children[@]}"; do