Add server-wide memory capacity check (Option 9) - Critical OOM prevention

NEW FEATURES:
- Menu Option 9: Check Server Memory Capacity (OOM Risk)
- Calculates total memory if ALL PHP-FPM pools hit max_children
- Identifies servers at risk of Out-Of-Memory (OOM) kills
- Provides balanced memory allocation recommendations

TWO NEW ANALYZER FUNCTIONS:

1. calculate_server_memory_capacity()
   - Iterates through all users/PHP-FPM pools
   - Calculates: max_children × avg_memory_per_process
   - Sums total across all pools
   - Compares to total RAM
   - Returns: total_required|total_ram|percentage|status

   Status Levels:
   - HEALTHY:  <60% RAM (safe)
   - CAUTION:  60-75% RAM (watch)
   - WARNING:  75-90% RAM (risky)
   - CRITICAL: >90% RAM (OOM likely!)

2. calculate_balanced_memory_allocation()
   - Analyzes traffic for each user (requests/minute)
   - Calculates proportional memory allocation
   - Reserves 20% of RAM for system (min 2GB)
   - Distributes remaining RAM based on traffic
   - Returns recommendations: REDUCE / INCREASE / OPTIMAL

   Example output:
   USER     CURRENT_MAX  AVG_MB  TRAFFIC_RPM  RECOMMENDED_MAX  REASON
   user1    50          45MB     120          75              INCREASE (traffic demands)
   user2    100         60MB     10           15              REDUCE (prevent OOM)

MENU OPTION 9 FEATURES:
- Shows total RAM vs required memory
- Displays percentage and color-coded status
- Optional per-user breakdown table
- Optional balanced recommendations
- Interactive: ask user what details to show

USE CASE:
Server has 16GB RAM. 10 users each with max_children=50, avg 50MB/process.
Total required: 10 × 50 × 50MB = 25GB
Percentage: 156% of RAM → CRITICAL!
Result: Server WILL run out of memory and kill processes!

This feature addresses user's request:
"calculating max children and memory allocation and then combining all the
 accounts to see if the memory will hit over the memory cap if at capacity"

CRITICAL for preventing OOM kills on shared hosting servers!
This commit is contained in:
cschantz
2025-12-02 20:39:20 -05:00
parent 52379f0ee6
commit 257e846685
2 changed files with 354 additions and 0 deletions
+143
View File
@@ -50,6 +50,7 @@ show_main_menu() {
cecho " ${GREEN}6${NC}) View OPcache Statistics"
cecho " ${GREEN}7${NC}) View PHP-FPM Process Stats"
cecho " ${GREEN}8${NC}) Check for Configuration Issues"
cecho " ${GREEN}9${NC}) Check Server Memory Capacity (OOM Risk)"
echo ""
cecho " ${YELLOW}b${NC}) Backup Current Configurations"
cecho " ${YELLOW}r${NC}) Restore from Backup"
@@ -722,6 +723,145 @@ check_config_issues() {
read -p "Press Enter to continue..."
}
# ============================================================================
# OPTION 9: CHECK SERVER MEMORY CAPACITY
# ============================================================================
check_server_memory_capacity() {
show_banner
cecho "${WHITE}${BOLD}SERVER MEMORY CAPACITY CHECK${NC}"
echo ""
cecho "${YELLOW}This checks if all PHP-FPM pools hitting max_children would cause OOM...${NC}"
echo ""
# Run capacity analysis
cecho "${CYAN}Analyzing PHP-FPM memory requirements...${NC}"
echo ""
local result
result=$(calculate_server_memory_capacity 2>&1)
# Parse result (main output is last line)
local main_result
main_result=$(echo "$result" | tail -1)
local total_required total_ram percentage status details
total_required=$(echo "$main_result" | cut -d'|' -f1)
total_ram=$(echo "$main_result" | cut -d'|' -f2)
percentage=$(echo "$main_result" | cut -d'|' -f3)
status=$(echo "$main_result" | cut -d'|' -f4)
# Display summary
cecho "${CYAN}═══════════════════════════════════════════════════════════════════${NC}"
cecho "${WHITE}${BOLD}MEMORY CAPACITY ANALYSIS${NC}"
cecho "${CYAN}═══════════════════════════════════════════════════════════════════${NC}"
echo ""
cecho " Total Server RAM: ${WHITE}${total_ram}MB${NC}"
cecho " Required if ALL pools at max_children: ${WHITE}${total_required}MB${NC}"
cecho " Percentage of RAM: ${WHITE}${percentage}%${NC}"
echo ""
# Display status with color
case "$status" in
CRITICAL)
cecho " Status: ${RED}${BOLD}CRITICAL - HIGH OOM RISK!${NC}"
cecho ""
cecho " ${RED}WARNING: If all PHP-FPM pools hit their max_children limit,${NC}"
cecho " ${RED}the server will likely run out of memory and kill processes!${NC}"
;;
WARNING)
cecho " Status: ${YELLOW}${BOLD}WARNING - MODERATE OOM RISK${NC}"
cecho ""
cecho " ${YELLOW}CAUTION: Memory usage is high. Some pools may need reduction.${NC}"
;;
CAUTION)
cecho " Status: ${YELLOW}${BOLD}CAUTION - WATCH MEMORY USAGE${NC}"
cecho ""
cecho " ${YELLOW}Memory usage is elevated but manageable.${NC}"
;;
HEALTHY)
cecho " Status: ${GREEN}${BOLD}HEALTHY - LOW OOM RISK${NC}"
cecho ""
cecho " ${GREEN}Memory allocation appears safe.${NC}"
;;
esac
echo ""
cecho "${CYAN}═══════════════════════════════════════════════════════════════════${NC}"
echo ""
# Ask if user wants detailed breakdown
read -p "Show detailed per-user breakdown? (y/n): " show_details
if [[ "$show_details" =~ ^[Yy]$ ]]; then
echo ""
cecho "${WHITE}${BOLD}PER-USER BREAKDOWN${NC}"
cecho "${CYAN}─────────────────────────────────────────────────────────────────────${NC}"
echo ""
# Get details from stderr of previous call
local details_output
details_output=$(echo "$result" | head -n -1)
printf "%-20s %12s %12s %12s\n" "USER" "MAX_CHILDREN" "AVG/PROCESS" "MAX_MEMORY"
printf "%-20s %12s %12s %12s\n" "--------------------" "------------" "------------" "------------"
while IFS='|' read -r username max_children avg_mb pool_max_mb; do
[ -z "$username" ] && continue
printf "%-20s %12s %12s %12s\n" "$username" "$max_children" "$avg_mb" "$pool_max_mb"
done <<< "$details_output"
echo ""
fi
# Ask if user wants balanced recommendations
echo ""
read -p "Calculate balanced memory allocation recommendations? (y/n): " show_recommendations
if [[ "$show_recommendations" =~ ^[Yy]$ ]]; then
echo ""
cecho "${WHITE}${BOLD}BALANCED MEMORY ALLOCATION RECOMMENDATIONS${NC}"
cecho "${CYAN}─────────────────────────────────────────────────────────────────────${NC}"
echo ""
cecho "${YELLOW}Calculating optimal max_children based on traffic...${NC}"
echo ""
local recommendations
recommendations=$(calculate_balanced_memory_allocation 2>/dev/null)
# Display header
local header
header=$(echo "$recommendations" | head -1)
echo "$header" | awk -F'|' '{printf "%-15s %8s %10s %12s %12s %15s %20s\n", $1, $2, $3, $4, $5, $6, $7}'
echo "--------------------------------------------------------------------------------------------------------"
# Display recommendations
echo "$recommendations" | tail -n +2 | while IFS='|' read -r user current_max avg_mb traffic_rpm recommended_max allocated_mb reason; do
[ -z "$user" ] && continue
# Color code reason
if [[ "$reason" == *"REDUCE"* ]]; then
color="${RED}"
elif [[ "$reason" == *"INCREASE"* ]]; then
color="${GREEN}"
else
color="${WHITE}"
fi
printf "%-15s %8s %10s %12s ${color}%12s${NC} %15s %20s\n" "$user" "$current_max" "$avg_mb" "$traffic_rpm" "$recommended_max" "$allocated_mb" "$reason"
done
echo ""
cecho "${YELLOW}NOTE: These are recommendations based on proportional traffic.${NC}"
cecho "${YELLOW}Actual needs may vary. Always test changes carefully.${NC}"
echo ""
fi
echo ""
cecho "${CYAN}═══════════════════════════════════════════════════════════════════${NC}"
read -p "Press Enter to continue..."
}
# ============================================================================
# MAIN LOOP
# ============================================================================
@@ -775,6 +915,9 @@ main() {
8)
check_config_issues
;;
9)
check_server_memory_capacity
;;
b)
cecho "${YELLOW}Backup feature not yet implemented${NC}"
sleep 2