Complete profile-based PHP-FPM optimization system with real usage data

Implement data-driven optimization using actual server metrics instead of thresholds:

NEW FEATURES:
- lib/php-analytics.sh: Analytics engine for domain profiling
  • analyze_memory_errors_from_logs: Parse error logs for memory exhaustion
  • analyze_process_memory_usage: Measure actual PHP process memory via ps
  • get_peak_concurrent_detailed: Extract peak concurrent requests from access logs
  • detect_memory_leak_pattern: Identify domains with memory leak issues
  • build_domain_profile: Complete profile with all real usage data
  • Intelligent recommendations based on ACTUAL peak memory, traffic, and leak patterns

- modules/performance/php-domain-analyzer.sh: Pre-analysis script
  • Scans all domains and builds comprehensive profiles
  • Stores profiles in /tmp/php-domain-profiles/ for use by optimizer
  • Shows summary with top memory users, traffic patterns, and potential leaks
  • Displays analysis in real-time with progress indicators

- php-optimizer.sh: Profile-based optimization levels
  • Option 0: Run pre-analysis to collect real usage data
  • Levels 1-5: Now use profile-based recommendations (fallback to traffic-based if no profiles)
  • Shows real usage data from profiles when optimizations applied
  • Memory recommendations: peak_memory_seen + 20% buffer
  • Max children: peak_concurrent_requests + 30% safety margin
  • Max requests: 250 for leak-prone domains, 500 for normal domains

ARCHITECTURE:
- Profile format (pipe-delimited): domain|username|peak_concurrent|avg_concurrent|
  total_hits|min_mem|max_mem|avg_mem|proc_count|mem_exhausted|peak_mem_seen|
  leak_type|current_memory_limit|current_max_children
- Profiles cached in /tmp/php-domain-profiles/ (24 hour TTL)
- All 5 optimization levels now profile-aware
- Seamless fallback to traffic-based method if no profiles exist

CONVERSION COMPLETED:
- Level 1: Optimizes pm.max_children only (profile-aware)
- Level 2: pm.max_children + memory_limit (profile-aware)
- Level 3: All of above + pm.max_requests for leak prevention (profile-aware)
- Level 4: OPcache optimization (unchanged)
- Level 5: Complete optimization with all settings (NOW PROFILE-AWARE - FIXED)

All levels now enumeraate users/domains directly and use profile recommendations
when available, with intelligent fallback to the original traffic-based method.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
cschantz
2026-02-18 19:40:01 -05:00
parent 7a68086bf1
commit 4d745f203e
3 changed files with 944 additions and 89 deletions
+146
View File
@@ -0,0 +1,146 @@
#!/bin/bash
# PHP Domain Analyzer - Collect real usage data for true optimization
# Run this before optimization to build accurate domain profiles
# Uses actual logs and process data instead of thresholds
# Source required libraries
PHP_TOOLKIT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && cd ../.. && pwd)"
source "$PHP_TOOLKIT_DIR/lib/common-functions.sh" 2>/dev/null || { echo "ERROR: common-functions.sh not found"; exit 1; }
source "$PHP_TOOLKIT_DIR/lib/system-detect.sh" 2>/dev/null || { echo "ERROR: system-detect.sh not found"; exit 1; }
source "$PHP_TOOLKIT_DIR/lib/user-manager.sh" 2>/dev/null || { echo "ERROR: user-manager.sh not found"; exit 1; }
source "$PHP_TOOLKIT_DIR/lib/php-detector.sh" 2>/dev/null || { echo "ERROR: php-detector.sh not found"; exit 1; }
source "$PHP_TOOLKIT_DIR/lib/php-analytics.sh" 2>/dev/null || { echo "ERROR: php-analytics.sh not found"; exit 1; }
source "$PHP_TOOLKIT_DIR/lib/php-scanner.sh" 2>/dev/null || { echo "ERROR: php-scanner.sh not found"; exit 1; }
# Color codes
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
WHITE='\033[1;37m'
BOLD='\033[1m'
NC='\033[0m'
cecho() {
echo -e "$@"
}
# ============================================================================
# MAIN ANALYSIS
# ============================================================================
initialize_system_detection
if [ "$EUID" -ne 0 ]; then
cecho "${RED}ERROR: This script must be run as root${NC}"
exit 1
fi
cecho "${CYAN}╔════════════════════════════════════════════════════════════════════════╗${NC}"
cecho "${CYAN}${WHITE} PHP DOMAIN ANALYZER - REAL USAGE DATA COLLECTION ${CYAN}${NC}"
cecho "${CYAN}╚════════════════════════════════════════════════════════════════════════╝${NC}"
echo ""
cecho "${WHITE}${BOLD}Starting Analysis...${NC}"
cecho "${CYAN}This may take a few minutes. Analyzing logs, processes, and traffic patterns.${NC}"
echo ""
# Get all users and domains
users=$(list_all_users)
declare -a all_profiles
total_domains=0
analyzed=0
cecho "${YELLOW}Analyzing domains...${NC}"
echo ""
while IFS= read -r username; do
[ -z "$username" ] && continue
user_domains=$(get_user_domains "$username")
while IFS= read -r domain; do
[ -z "$domain" ] && continue
total_domains=$((total_domains + 1))
cecho -n " [$total_domains] Analyzing $domain..."
# Build profile with actual data
profile=$(build_domain_profile "$username" "$domain")
if [ -n "$profile" ]; then
all_profiles+=("$profile")
store_domain_profile "$profile"
analyzed=$((analyzed + 1))
# Extract key metrics
peak_concurrent=$(echo "$profile" | cut -d'|' -f3)
peak_mem=$(echo "$profile" | cut -d'|' -f11)
leak_status=$(echo "$profile" | cut -d'|' -f12)
cecho "${GREEN}${NC}"
cecho " Peak: $peak_concurrent concurrent | Memory: ${peak_mem}MB | Leak: $leak_status"
else
cecho "${YELLOW}${NC} (could not collect data)"
fi
done <<< "$user_domains"
done <<< "$users"
echo ""
cecho "${CYAN}═══════════════════════════════════════════════════════════════════════════${NC}"
cecho "${WHITE}${BOLD}ANALYSIS COMPLETE${NC}"
cecho "${CYAN}═══════════════════════════════════════════════════════════════════════════${NC}"
echo ""
cecho " Total domains analyzed: ${WHITE}${analyzed}${NC} / ${total_domains}"
cecho " Profiles stored in: ${WHITE}/tmp/php-domain-profiles/${NC}"
echo ""
# Display summary
if [ "${#all_profiles[@]}" -gt 0 ]; then
cecho "${CYAN}ANALYSIS SUMMARY:${NC}"
echo ""
# Find domains with highest memory usage
cecho "${WHITE}${BOLD}Top Memory Usage:${NC}"
printf '%s\n' "${all_profiles[@]}" | sort -t'|' -k11 -rn | head -5 | while IFS='|' read -r domain username peak_concurrent avg_concurrent total_hits min_mem max_mem avg_mem proc_count mem_exhausted peak_mem leak rest; do
cecho "$domain: ${peak_mem}MB peak memory"
done
echo ""
# Find domains with highest traffic
cecho "${WHITE}${BOLD}Top Traffic:${NC}"
printf '%s\n' "${all_profiles[@]}" | sort -t'|' -k3 -rn | head -5 | while IFS='|' read -r domain username peak_concurrent avg_concurrent total_hits rest; do
cecho "$domain: $peak_concurrent concurrent requests"
done
echo ""
# Find domains with potential leaks
leak_count=$(printf '%s\n' "${all_profiles[@]}" | \grep -c "LIKELY_LEAK")
if [ "$leak_count" -gt 0 ]; then
cecho "${RED}${BOLD}⚠ Domains with potential memory leaks:${NC} $leak_count"
printf '%s\n' "${all_profiles[@]}" | \grep "LIKELY_LEAK" | while IFS='|' read -r domain username rest; do
cecho "$domain"
done
echo ""
fi
# Show high memory usage domains
high_mem=$(printf '%s\n' "${all_profiles[@]}" | awk -F'|' '$11 > 200 {print}' | wc -l)
if [ "$high_mem" -gt 0 ]; then
cecho "${YELLOW}${BOLD}Domains using >200MB:${NC} $high_mem"
fi
fi
echo ""
cecho "${CYAN}═══════════════════════════════════════════════════════════════════════════${NC}"
echo ""
cecho "${GREEN}${BOLD}✓ Domain profiles ready for optimization!${NC}"
echo ""
cecho "Next step: Run php-optimizer.sh → Option 5 → Select optimization level"
cecho "The optimizer will now use REAL usage data for accurate recommendations."
echo ""