diff --git a/modules/performance/php-optimizer.sh b/modules/performance/php-optimizer.sh index 13cd099..7ce4a23 100755 --- a/modules/performance/php-optimizer.sh +++ b/modules/performance/php-optimizer.sh @@ -1563,6 +1563,17 @@ optimize_level_1_max_children() { echo "" fi + # Calculate server capacity for intelligent three-constraint model + local server_capacity_result + 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 intelligent three-constraint model: Memory + Traffic + Fair Share" + echo "" + # Get recommendations cecho "${CYAN}Step 2: Calculating optimal settings...${NC}" echo "" @@ -1575,6 +1586,18 @@ optimize_level_1_max_children() { local users users=$(list_all_users) + # CRITICAL FIX: Build list of ALL domains on server FIRST + # This is needed for accurate traffic percentage calculation + all_domains_string="" + while IFS= read -r u; do + [ -z "$u" ] && continue + u_domains=$(get_user_domains "$u") + while IFS= read -r d; do + [ -z "$d" ] && continue + all_domains_string="$all_domains_string$d"$'\n' + done <<< "$u_domains" + done <<< "$users" + while IFS= read -r username; do [ -z "$username" ] && continue local user_domains @@ -1594,16 +1617,21 @@ optimize_level_1_max_children() { current_max="?" fi - # Get recommendations - use profile if available, otherwise use traffic-based + # Get recommendations - use profile if available, otherwise use intelligent three-constraint model local recommended_max if [ "$profiles_exist" = "1" ] && [ -f "/tmp/php-domain-profiles/$domain.profile" ]; then recommended_max=$(get_max_children_recommendation "$domain" "$username") else - # Fallback to traffic-based (old method) - local traffic_rpm - traffic_rpm=$(get_domain_peak_concurrent "$domain" 2>/dev/null || echo "0") - [ "$traffic_rpm" = "?" ] && traffic_rpm="0" - recommended_max=$((traffic_rpm > 5 ? traffic_rpm + 10 : 5)) + # Use intelligent three-constraint model (same as Level 5) + local traffic_pct + traffic_pct=$(get_domain_traffic_percentage "$username" "$domain" "$all_domains_string" 2>/dev/null | cut -d'|' -f1) + traffic_pct=${traffic_pct:-50} + + # Call intelligent three-constraint function + local intel_result + intel_result=$(calculate_optimal_php_settings_intelligent "$username" "$total_ram_mb" "$server_capacity" "$traffic_pct" 2>/dev/null || echo "20|dynamic|1|5|ERROR|Failed") + + recommended_max=$(echo "$intel_result" | cut -d'|' -f1) fi recommended_values["$domain"]="$recommended_max" @@ -1621,6 +1649,46 @@ optimize_level_1_max_children() { done <<< "$user_domains" done <<< "$users" + # CRITICAL VALIDATION: Check if combined recommendations exceed safe limits + cecho "${CYAN}Step 2b: Validating capacity...${NC}" + echo "" + + local total_recommended_max_children=0 + local avg_memory_per_process=$server_memory_per_process + local total_recommended_memory=0 + + for domain in "${!recommended_values[@]}"; do + local rec_max="${recommended_values[$domain]}" + [ -z "$rec_max" ] && continue + total_recommended_max_children=$((total_recommended_max_children + rec_max)) + total_recommended_memory=$((total_recommended_memory + (rec_max * avg_memory_per_process))) + done + + # Determine if recommendations are safe + local max_safe_php_fpm=$((total_ram_mb * 60 / 100)) + + if [ "$total_recommended_memory" -gt "$max_safe_php_fpm" ]; then + cecho "${RED}${BOLD}⚠ WARNING: Combined recommendations exceed safe limits!${NC}" + cecho "${RED}Recommended total: ${total_recommended_memory}MB (${total_recommended_max_children} max_children combined)${NC}" + cecho "${RED}Safe maximum: ${max_safe_php_fpm}MB${NC}" + cecho "${YELLOW}Applying safety caps to prevent OOM crashes...${NC}" + echo "" + + # Scale down all recommendations proportionally + local scale_factor + scale_factor=$((max_safe_php_fpm * 100 / total_recommended_memory)) + + for domain in "${!recommended_values[@]}"; do + local rec_max="${recommended_values[$domain]}" + [ -z "$rec_max" ] && continue + rec_max=$((rec_max * scale_factor / 100)) + [ "$rec_max" -lt 5 ] && rec_max=5 + recommended_values["$domain"]="$rec_max" + done + cecho "${CYAN}Applied proportional scaling (${scale_factor}%)${NC}" + echo "" + fi + echo "" if [ "$changes_needed" -eq 0 ]; then cecho "${GREEN}${BOLD}✓ All domains already optimized - no changes needed${NC}" @@ -1752,6 +1820,17 @@ optimize_level_2_memory() { cecho " Status: ${WHITE}${status}${NC}" echo "" + # Calculate server capacity for intelligent three-constraint model + local server_capacity_result + 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 intelligent three-constraint model: Memory + Traffic + Fair Share" + echo "" + # Check if profiles exist local profiles_exist=0 if [ -d "/tmp/php-domain-profiles" ] && [ "$(ls -1 /tmp/php-domain-profiles/*.profile 2>/dev/null | wc -l)" -gt 0 ]; then @@ -1762,7 +1841,7 @@ optimize_level_2_memory() { else cecho "${YELLOW}${BOLD}⚠ No domain profiles found${NC}" cecho "${CYAN}For more accurate optimization, run pre-analysis first:${NC}" - cecho " ${WHITE}php-optimizer.sh${NC} → Option 3 (Pre-analyze domains)" + cecho " ${WHITE}php-optimizer.sh${NC} → Option 0 (Pre-analyze domains)" echo "" fi @@ -1779,6 +1858,18 @@ optimize_level_2_memory() { local users users=$(list_all_users) + # CRITICAL FIX: Build list of ALL domains on server FIRST + # This is needed for accurate traffic percentage calculation + all_domains_string="" + while IFS= read -r u; do + [ -z "$u" ] && continue + u_domains=$(get_user_domains "$u") + while IFS= read -r d; do + [ -z "$d" ] && continue + all_domains_string="$all_domains_string$d"$'\n' + done <<< "$u_domains" + done <<< "$users" + while IFS= read -r username; do [ -z "$username" ] && continue local user_domains @@ -1798,27 +1889,24 @@ optimize_level_2_memory() { current_max="?" fi - # Get recommendations - use profile if available, otherwise use traffic-based + # Get recommendations - use profile if available, otherwise use intelligent three-constraint model local recommended_max - if [ "$profiles_exist" = "1" ] && [ -f "/tmp/php-domain-profiles/$domain.profile" ]; then - recommended_max=$(get_max_children_recommendation "$domain" "$username") - else - # Fallback to traffic-based (old method) - local traffic_rpm - traffic_rpm=$(get_domain_peak_concurrent "$domain" 2>/dev/null || echo "0") - [ "$traffic_rpm" = "?" ] && traffic_rpm="0" - recommended_max=$((traffic_rpm > 5 ? traffic_rpm + 10 : 5)) - fi - local recommended_memory if [ "$profiles_exist" = "1" ] && [ -f "/tmp/php-domain-profiles/$domain.profile" ]; then + recommended_max=$(get_max_children_recommendation "$domain" "$username") recommended_memory=$(get_memory_limit_recommendation "$domain" "$username") else - # Fallback to traffic-based (old method) - local traffic_rpm - traffic_rpm=$(get_domain_peak_concurrent "$domain" 2>/dev/null || echo "0") - [ "$traffic_rpm" = "?" ] && traffic_rpm="0" - recommended_memory=$(calculate_optimal_memory_limit "$username" "$domain" "$traffic_rpm") + # Use intelligent three-constraint model (same as Level 5) + local traffic_pct + traffic_pct=$(get_domain_traffic_percentage "$username" "$domain" "$all_domains_string" 2>/dev/null | cut -d'|' -f1) + traffic_pct=${traffic_pct:-50} + + # Call intelligent three-constraint function + local intel_result + intel_result=$(calculate_optimal_php_settings_intelligent "$username" "$total_ram_mb" "$server_capacity" "$traffic_pct" 2>/dev/null || echo "20|dynamic|1|5|ERROR|Failed") + + recommended_max=$(echo "$intel_result" | cut -d'|' -f1) + recommended_memory=$(calculate_optimal_memory_limit "$username" "$domain" "$recommended_max" 2>/dev/null || echo "128M") fi recommended_max_children["$domain"]="$recommended_max" @@ -1839,6 +1927,46 @@ optimize_level_2_memory() { done <<< "$user_domains" done <<< "$users" + # CRITICAL VALIDATION: Check if combined recommendations exceed safe limits + cecho "${CYAN}Step 2b: Validating capacity...${NC}" + echo "" + + local total_recommended_max_children=0 + local avg_memory_per_process=$server_memory_per_process + local total_recommended_memory=0 + + for domain in "${!recommended_max_children[@]}"; do + local rec_max="${recommended_max_children[$domain]}" + [ -z "$rec_max" ] && continue + total_recommended_max_children=$((total_recommended_max_children + rec_max)) + total_recommended_memory=$((total_recommended_memory + (rec_max * avg_memory_per_process))) + done + + # Determine if recommendations are safe + local max_safe_php_fpm=$((total_ram_mb * 60 / 100)) + + if [ "$total_recommended_memory" -gt "$max_safe_php_fpm" ]; then + cecho "${RED}${BOLD}⚠ WARNING: Combined recommendations exceed safe limits!${NC}" + cecho "${RED}Recommended total: ${total_recommended_memory}MB (${total_recommended_max_children} max_children combined)${NC}" + cecho "${RED}Safe maximum: ${max_safe_php_fpm}MB${NC}" + cecho "${YELLOW}Applying safety caps to prevent OOM crashes...${NC}" + echo "" + + # Scale down all recommendations proportionally + local scale_factor + scale_factor=$((max_safe_php_fpm * 100 / total_recommended_memory)) + + for domain in "${!recommended_max_children[@]}"; do + local rec_max="${recommended_max_children[$domain]}" + [ -z "$rec_max" ] && continue + rec_max=$((rec_max * scale_factor / 100)) + [ "$rec_max" -lt 5 ] && rec_max=5 + recommended_max_children["$domain"]="$rec_max" + done + cecho "${CYAN}Applied proportional scaling (${scale_factor}%)${NC}" + echo "" + fi + echo "" if [ "$changes_needed" -eq 0 ]; then cecho "${GREEN}${BOLD}✓ All domains already optimized${NC}" @@ -2006,6 +2134,17 @@ optimize_level_3_advanced() { cecho " Status: ${WHITE}${status}${NC}" echo "" + # Calculate server capacity for intelligent three-constraint model + local server_capacity_result + 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 intelligent three-constraint model: Memory + Traffic + Fair Share" + echo "" + # Check if profiles exist local profiles_exist=0 if [ -d "/tmp/php-domain-profiles" ] && [ "$(ls -1 /tmp/php-domain-profiles/*.profile 2>/dev/null | wc -l)" -gt 0 ]; then @@ -2029,6 +2168,18 @@ optimize_level_3_advanced() { local users users=$(list_all_users) + # CRITICAL FIX: Build list of ALL domains on server FIRST + # This is needed for accurate traffic percentage calculation + all_domains_string="" + while IFS= read -r u; do + [ -z "$u" ] && continue + u_domains=$(get_user_domains "$u") + while IFS= read -r d; do + [ -z "$d" ] && continue + all_domains_string="$all_domains_string$d"$'\n' + done <<< "$u_domains" + done <<< "$users" + while IFS= read -r username; do [ -z "$username" ] && continue local user_domains @@ -2048,14 +2199,18 @@ optimize_level_3_advanced() { recommended_memory_limit["$domain"]=$(get_memory_limit_recommendation "$domain" "$username") recommended_max_requests["$domain"]=$(get_max_requests_recommendation "$domain") else - # Fallback to traffic-based (old method) - local traffic_rpm - traffic_rpm=$(get_domain_peak_concurrent "$domain" 2>/dev/null || echo "0") - [ "$traffic_rpm" = "?" ] && traffic_rpm="0" + # Use intelligent three-constraint model (same as Level 5) + local traffic_pct + traffic_pct=$(get_domain_traffic_percentage "$username" "$domain" "$all_domains_string" 2>/dev/null | cut -d'|' -f1) + traffic_pct=${traffic_pct:-50} - recommended_max_children["$domain"]=$((traffic_rpm > 5 ? traffic_rpm + 10 : 5)) - recommended_memory_limit["$domain"]=$(calculate_optimal_memory_limit "$username" "$domain" "$traffic_rpm") - recommended_max_requests["$domain"]=$(calculate_optimal_max_requests "$traffic_rpm") + # Call intelligent three-constraint function + local intel_result + intel_result=$(calculate_optimal_php_settings_intelligent "$username" "$total_ram_mb" "$server_capacity" "$traffic_pct" 2>/dev/null || echo "20|dynamic|1|5|ERROR|Failed") + + recommended_max_children["$domain"]=$(echo "$intel_result" | cut -d'|' -f1) + recommended_memory_limit["$domain"]=$(calculate_optimal_memory_limit "$username" "$domain" "$recommended_max_children[$domain]" 2>/dev/null || echo "128M") + recommended_max_requests["$domain"]=$(calculate_optimal_max_requests "$recommended_max_children[$domain]" 2>/dev/null || echo "0") fi local current_max @@ -2088,6 +2243,46 @@ optimize_level_3_advanced() { done <<< "$user_domains" done <<< "$users" + # CRITICAL VALIDATION: Check if combined recommendations exceed safe limits + cecho "${CYAN}Step 2b: Validating capacity...${NC}" + echo "" + + local total_recommended_max_children=0 + local avg_memory_per_process=$server_memory_per_process + local total_recommended_memory=0 + + for domain in "${!recommended_max_children[@]}"; do + local rec_max="${recommended_max_children[$domain]}" + [ -z "$rec_max" ] && continue + total_recommended_max_children=$((total_recommended_max_children + rec_max)) + total_recommended_memory=$((total_recommended_memory + (rec_max * avg_memory_per_process))) + done + + # Determine if recommendations are safe + local max_safe_php_fpm=$((total_ram_mb * 60 / 100)) + + if [ "$total_recommended_memory" -gt "$max_safe_php_fpm" ]; then + cecho "${RED}${BOLD}⚠ WARNING: Combined recommendations exceed safe limits!${NC}" + cecho "${RED}Recommended total: ${total_recommended_memory}MB (${total_recommended_max_children} max_children combined)${NC}" + cecho "${RED}Safe maximum: ${max_safe_php_fpm}MB${NC}" + cecho "${YELLOW}Applying safety caps to prevent OOM crashes...${NC}" + echo "" + + # Scale down all recommendations proportionally + local scale_factor + scale_factor=$((max_safe_php_fpm * 100 / total_recommended_memory)) + + for domain in "${!recommended_max_children[@]}"; do + local rec_max="${recommended_max_children[$domain]}" + [ -z "$rec_max" ] && continue + rec_max=$((rec_max * scale_factor / 100)) + [ "$rec_max" -lt 5 ] && rec_max=5 + recommended_max_children["$domain"]="$rec_max" + done + cecho "${CYAN}Applied proportional scaling (${scale_factor}%)${NC}" + echo "" + fi + echo "" if [ "$changes_needed" -eq 0 ]; then cecho "${GREEN}${BOLD}✓ All domains already optimized${NC}"