2009-04-15 15 views
7

Tengo una tarea programada que ejecuta un script de forma regular (cada hora). Esta secuencia de comandos tiene una fuerte interacción con la base de datos y el sistema de archivos, y regularmente demora varios minutos en ejecutarse. El problema es que los picos de uso de la CPU del servidor se están ejecutando y ralentiza las operaciones normales. ¿Hay alguna manera de acelerar este proceso para que tome más tiempo pero no consuma tantos recursos?Sugerencias/trucos para limitar un script PHP

He examinado diferentes opciones de configuración para PHP, pero no parece haber ninguna que se ajuste a mis necesidades.

Configurar memory_limit en php.ini a algo más bajo hace que mis objetos de datos se desborden con bastante facilidad.

He visto publicaciones similares donde las personas sugirieron usar sleep() en ciertos puntos del script, pero eso no impide que el script active el servidor.

La solución óptima sería de alguna manera indicarle a la pila de la lámpara (en este caso, Wamp) que use solo el 10% de la utilización máxima de la CPU. No me preocupa en absoluto el tiempo de ejecución y preferiría que llevara más tiempo si eso significara salvar ciclos de CPU por segundo. Mi solución alternativa sería configurar un servidor diferente con replicación de base de datos para que el cron pueda ir a la ciudad sin ralentizar todo lo demás.

Medio Ambiente: 2k3 Windows Server, Apache 2.2.11, PHP 5.2.9, MySQL 5.1

aprecio cualquier penetración a esta situación.

EDIT: Agradezco todas las respuestas, incluso las que son * nix-specific. Todavía es lo suficientemente temprano en mi situación para cambiar el entorno de alojamiento. Afortunadamente, esta pregunta ayudará a otros, independientemente del sistema operativo.

Respuesta

8

Este es un problema complicado. Si está ejecutando el script PHP a través de la línea de comando, puede establecer la prioridad de programación del proceso en bajo (start /low php.exe myscript.php Creo). Si su script PHP en realidad está haciendo la mayor parte del procesamiento que está consumiendo su CPU, esto podría funcionar.Sin embargo, dijiste que estás haciendo una gran base de datos y la interacción del sistema de archivos, que esta solución no ayudará. Parece que hay una sugerencia de MySQL "LOW_PRIORITY" para las consultas INSERT y UPDATE que pueden ayudarlo, pero no las he probado.

1

Esto podría ser un cambio difícil pero puede valer la pena refactorizar sus estructuras de datos en iteradores. Además, si tiene referencias circulares en su código, proporcione un método como clearReferences() que desactive estos objetos. Este es un problema que está resuelto en PHP 5.3 por cierto.

Así que si usted tiene:

class Row 
{ 
    protected $_table; 

    public function __construct($table) 
    { 
     $this->_table = $table; 
    } 
} 

class Table 
{ 
    protected $_row; 

    public function __construct() 
    { 
     $this->_row = new Row($this); 
    } 
} 

añadir un() para la clase Fila clearReferences:

class Row 
{ 
    public function clearReferences() 
    { 
     $this->_table = null; 
    } 
} 

Eso es todo lo que puedo llegar a por el momento.

0

Si lo tiene (Apache) ejecutándose como un servicio, puede cambiar la configuración de prioridad en el centro/servicios de control de Win. El uso de la CPU se disparará de todos modos, pero el planificador preferirá otros programas . También intente poner la base de datos/servidor en un hd diferente al de sus aplicaciones .

2

¿Puede modificar su entrada cron para iniciar su secuencia de comandos usando nice?

+0

Vaya, lo siento. Veo que estás ejecutando Windows. ¡Fui arrojado por las etiquetas 'lámpara' y 'cron'! – grossvogel

+0

Gracias por su respuesta de todos modos. Todavía es posible en mi situación cambiar el entorno, por lo que aún considero útil su solución. –

2

No es una buena idea utilizar un servidor para atender a clientes y analizar datos.

Así que si está buscando una solución final, realice un rediseño de su aplicación y descargue el análisis de datos de las interfaces y la base de datos activa a otro sistema dedicado a esta tarea.

Incluso si puede estrangular con éxito el analizador, utilizaría recursos valiosos que de lo contrario estarían disponibles para atender a los usuarios.

1

que tienen un montón de secuencias de comandos que corro desde cron de manera similar utilizando agradable:

0 * * * * agradable -n19 php myscript.php

Esto no ayuda a la utilización de la memoria RAM (solo cambiar la forma en que se escribe el script puede hacer eso), pero solo usa la CPU que de otro modo estaría inactiva.

EDIT: no vio que la cuestión involucrado un entorno Windows, lo siento ... dejando esto en para cualquier usuario en Unix que tienen el mismo problema ..

3

En UNIX (LAMP) Logré resolver el problema mediante la comprobación de la carga del servidor antes de continuar el bucle

function get_server_load($windows = 0) { 
    $os = strtolower(PHP_OS); 
    if(strpos($os, "win") === false) { 
     if(file_exists("/proc/loadavg")) { 
     $load = file_get_contents("/proc/loadavg"); 
     $load = explode(' ', $load); 
     return $load; 
     } 
     elseif(function_exists("shell_exec")) { 
     $load = explode(' ', `uptime`); 
     return $load; 
     } 
     else { 
     return ""; 
     } 
    } 
} 

for(... ... ...){ 
    $data = get_server_load(); 
    if($data[0] < 0.2){ 
    // continue 
    }else{ 
     sleep(1); 
    } 
} 

Esta función debería funcionar también en las ventanas, pero no puedo garantizarlo. En Linux, le devuelve una matriz con la carga de los últimos 1 minuto, 5 minutos y 15 minutos

Además, considere comenzar sus scripts (si es por CLI) con una prioridad más baja (en Linux, use "nice")

También puede usar otros valores antes de continuar el ciclo, como el número de procesos activos de Apache (puede analizar la página 127.0.0.1/server_status?auto si habilitó el mod_status en httpd.conf), o también el Situación de MySQL (¿conexiones activas?)

1

Tal vez lo que su secuencia de comandos simplemente está tratando de hacer demasiado a la vez. ¿Haría menos si corriera tres veces por hora?

Otra solución podría ser configurar un servidor adicional solo para ejecutar este tipo de procesamiento 'back-end'. Esto sería particularmente efectivo si no está cargando excesivamente en la base de datos, solo el servidor web.

Otro enfoque a considerar es si se puede dividir el trabajo en una dirección diferente. Este tipo de secuencias de comandos a menudo tienen algunas grandes instrucciones de SQL que generan resultados utilizados para generar una gran cantidad de pequeñas sentencias de SQL. Si este último se puede dejar de lado en alguna parte, se puede ejecutar contra la base de datos como un paso posterior. Tal enfoque también podría permitirle usar una consulta sin búfer para obtener los datos de preprocesamiento, lo que podría reducir significativamente el consumo de memoria por parte del código PHP.

Cuestiones relacionadas