PHP factor 30 diferencia de rendimiento de Linux a Windows


Nuestro equipo está trabajando está desarrollando plugins de WordPress y proporciona instancias alojadas en un par de servidores independientes. Nuestra instalación de WordPress es administrada por Git, todos los servidores tienen la misma fuente y configuración de WordPress implementada, solo los dominios y los datos reales en la base de datos varían. Para cada instalación, MySQL se ejecuta en el mismo host. WordPress se ejecuta exclusivamente en cada servidor.

Sin embargo, después de haber implementado esta configuración en un Windows Server 2008 RC2, notamos una drástica diferencia de rendimiento en comparación con nuestros otros servidores: el tiempo de generación de páginas aumenta desde el promedio. 400ms a 4000-5000ms para páginas generadas con PHP. Para los recursos estáticos entregados solo por Apache, la velocidad es aproximadamente la misma que en Linux.

Así que tomamos algunas medidas para reducir el problema:{[17]]}

  1. Asegúrese de que no haya software antivir en ejecución u otros elementos del dominio de Windows que interfieran
  2. Recopilar datos de perfiles para identificar los temporizadores durante el script ejecución
  3. Pruebe diferentes configuraciones de servidor y hardware
  4. Revise la configuración de Apache y PHP para ver si hay errores obvios de configuración

Después de algunos perfiles rápidamente notamos que la evaluación de expresiones regulares es terriblemente lenta en nuestras máquinas windows. Evaluar 10.000 expresiones regulares (preg_match) toma alrededor de 90ms en Linux y 3000ms en Windows.

Los perfiles, las pruebas del sistema y los detalles de configuración se proporcionan a continuación. no queremos para optimizar este script(que sí sabemos hacer). Queremos que el script se ejecute aproximadamente a la misma velocidad en Windows que en Linux (dada la misma configuración con respecto a opcache/...). No hay necesidad de optimizar la huella de memoria del script también.

Actualización: Después de algún tiempo, los sistemas parecen quedarse sin memoria, lo que desencadena excepciones de memoria y asignaciones aleatorias. Ver abajo para más detalles. Reiniciar Apache / PHP solucionó el problema por ahora.

Traza a _get_browser is:

File (called from)
require wp-blog-header.php (index.php:17)
wp (wp-blog-header.php:14)
WP->main (functions.php:808)
php::do_action_ref_array (class-wp.php:616)
php::call_user_func_array (wp-includes/plugin:507)
wp_slimstat::slimtrack  (php::internal (507))
wp_slimstat::_get_browser (wp-slimstat.php:385)

Actualización 2 : Alguna razón por la que no recuerdo que volvimos a activar PHP como un módulo Apache en nuestros servidores (el mismo que ofrece un mal rendimiento). Pero hoy corren increíblemente rápido (~1seg / request). Agregar Opcache reduce esto a ~400ms / req. Apache / PHP / Windows se mantuvo igual.

1) Perfiles de resultados

El perfilado se realizó con XDebug en todas las máquinas. Por lo general, solo recogimos unas pocas carreras, esas fueron suficientes para revelar la ubicación donde se pasó la mayor parte del tiempo (50%+): el método [get_browser][1] del plugin de WordPress wp-slimstats:

protected static function _get_browser(){
    // Load cache
    @include_once(plugin_dir_path( __FILE__ ).'databases/browscap.php');
    // browscap.php contains $slimstat_patterns and $slimstat_browsers

    $browser = array('browser' => 'Default Browser', 'version' => '1', 'platform' => 'unknown', 'css_version' => 1, 'type' => 1);
    if (empty($slimstat_patterns) || !is_array($slimstat_patterns)) return $browser;

    $user_agent = isset($_SERVER['HTTP_USER_AGENT'])?$_SERVER['HTTP_USER_AGENT']:'';
    $search = array();
    foreach ($slimstat_patterns as $key => $pattern){
        if (preg_match($pattern . 'i', $user_agent)){
            $search = $value = $search + $slimstat_browsers[$key];
            while (array_key_exists(3, $value) && $value[3]) {
                $value = $slimstat_browsers[$value[3]];
                $search += $value;
            }
            break;
        }
    }

    // Lots of other lines to relevant to the profiling results
  }

Esta función similar a la de PHP get_browser detecta las capacidades del navegador y el sistema operativo. La mayor parte del tiempo de ejecución del script se gasta en este bucle foreach, evaluando todos esos preg_match (~aproximadamente 8000 - 10000 por solicitud de página). Esto toma alrededor de 90ms en Linux y 3000ms en Windows. Los resultados fueron los mismos en todas las configuraciones probadas (la imagen muestra datos de dos executions):

wp_slimstat::_get_browser resultados de perfiles en IIS8

Claro, cargar dos matrices enormes lleva algún tiempo. Evaluación de expresiones regulares también. Pero esperaríamos que tomaran aproximadamente el mismo tiempo en Linux y Windows. Este es el resultado de la generación de perfiles en una máquina virtual linux (solo una solicitud de página). La diferencia es bastante obvia:

introduzca la descripción de la imagen aquí

Otro asesino del tiempo fue en realidad el Objeto-Caché WordPress utiliza:

function get( $key, $group = 'default', $force = false, &$found = null ) {
    if ( empty( $group ) )
        $group = 'default';

    if ( $this->multisite && ! isset( $this->global_groups[ $group ] ) )
        $key = $this->blog_prefix . $key;

    if ( $this->_exists( $key, $group ) ) {
        $found = true;
        $this->cache_hits += 1;
        if ( is_object($this->cache[$group][$key]) )
            return clone $this->cache[$group][$key];
        else
            return $this->cache[$group][$key];
    }

    $found = false;
    $this->cache_misses += 1;
    return false;
}

El tiempo se pasa dentro de esta función en sí (3 script executions):

introduzca la descripción de la imagen aquí

En linux:

introduzca la descripción de la imagen aquí

El último verdadero gran asesino fueron las traducciones. Cada traducción, cargada desde la memoria, toma cualquier cosa de 0.2 ms a 4ms en WordPress: introduzca la descripción de la imagen aquí

En linux:

introduzca la descripción de la imagen aquí

2) sistemas Probados

Para asegurarnos de que la virtualización o Apache afectan esto, lo probamos en varias configuraciones. Antivir fue desactivado en todas las configuraciones:

  • Linux Debian, Apache 2 y PHP en versiones estables actualizadas. Esto es lo mismo para los desarrolladores que se ejecutan en sus máquinas virtuales que para los servidores staging/live. Actuar como un sistema de referencia de rendimiento deseado. Ya sea en nuestra oficina o en algún alojamiento proporciona (espacio compartido). Los sistemas Windows tenían entre 4GB y 8GB de RAM, en todo momento el uso de memoria era inferior al 50%. Las virtualizaciones nunca ejecutan Windows y Apache al mismo tiempo.
  • Servidores de vida, que se ejecutan en T-Systems (servidores virtualizados administrados), en Reproductor de VMware
    • Win 2008 R2. Apache 2.2.25 + PHP 5.4.26 NTS, VC9 como módulo fastcgi
    • Win 2008 R2. Apache 2.2.25 + PHP 5.5.1 NTS, VC11 como módulo fastcgi
    • Win 2008 R2. Apache 2.2.25 + PHP 5.5.1 NTS, VC11 como módulo apache
    • Win 2008 R2, Apache 2.2.25 + PHP 5.5.11 TS, VC11 como módulo apache (ese es el rápido que mencioné en la actualización 2)
  • En una máquina local, Host: openSUSE, Virtualización: VMware player, igual que @T-Systems. A evitar que su infraestructura nos influya:
    • Win 2008 R2. Apache 2.2.25 + PHP 5.4.26 NTS, VC9 como módulo fastcgi
    • Win 2008 R2. IIS7 + PHP 5.4.26 NTS, VC9 como módulo fastcgi (con y sin wincache)
    • Win 2012. IIS * + PHP 5.5.10 NTS, VC11 como módulo fastcgi (con y sin wincache)
  • En una máquina local sin virtualización
    • Win 2008 R2. Apache 2.2.25 + PHP 5.4.26 NTS, VC9 como fastcgi módulo

Los resultados de los perfiles mencionados anteriormente fueron los mismos en los diferentes sistemas (~10% de derivación). Windows siempre fue un factor significativo más lento que Linux.

El uso de una nueva instalación de WordPress y Slimstats resultó en aprox. los mismos resultados. Reescribir el código no es una opción aquí.

Update: Mientras tanto, encontramos otros dos sistemas Windows (ambos Windows 2008 R2, VM y Phys) donde esta pila completa se ejecuta bastante rápido. Mismo configuración sin embargo.

Actualización 2 : Ejecutar PHP como módulo apache en los Servidores Life fue un poco más rápido que el método fastcgi: hasta ~2 segundos, 50% menos.

Se está quedando sin memoria

Después de algún tiempo, nuestro Servidor en vivo deja de funcionar, activando estas excepciones de memoria:

PHP Fatal error:  Out of memory (allocated 4456448) (tried to allocate 136 bytes)
PHP Fatal error:  Out of memory (allocated 8650752) (tried to allocate 45 bytes) 
PHP Fatal error:  Out of memory (allocated 6815744) (tried to allocate 24 bytes) 

Esto sucede en ubicaciones de script aleatorias. Obviamente, el Administrador de memoria Zend no es capaz de asignar más memoria, aunque los scripts serían se le permite hacerlo. En el momento del incidente, el servidor tenía aproximadamente el 50% de RAM libre (2 GB+). Así que el servidor no se queda sin ram. Reiniciar Apache / PHP solucionó este problema por ahora.

No estoy seguro de si este problema está relacionado con los problemas de rendimiento aquí. Sin embargo, como ambos temas parecen estar relacionados con la memoria, se incluye aquí. Especialmente trataremos de reproducir la configuración de las pruebas de Windows que proporcionaron un rendimiento decente.

3) Configuración de Apache y PHP

... probablemente no tienen ninguna trampa común. Output-Buffering está habilitado( por defecto), multibye override deshabilitado, ... Si alguna opción(s) son de interés, estaremos encantados de proporcionarlas.

Salida de httpd.exe -V

Server version: Apache/2.4.7 (Win32)
Apache Lounge VC10 Server built:   Nov 26 2013 15:46:56
Server's Module Magic Number: 20120211:27
Server loaded:  APR 1.5.0, APR-UTIL 1.5.3
Compiled using: APR 1.5.0, APR-UTIL 1.5.3
Architecture:   32-bit
Server MPM:     WinNT
  threaded:     yes (fixed thread count)
    forked:     no
Server compiled with....
 -D APR_HAS_SENDFILE
 -D APR_HAS_MMAP
 -D APR_HAVE_IPV6 (IPv4-mapped addresses disabled)
 -D APR_HAS_OTHER_CHILD
 -D AP_HAVE_RELIABLE_PIPED_LOGS
 -D DYNAMIC_MODULE_LIMIT=256
 -D HTTPD_ROOT="/apache"
 -D SUEXEC_BIN="/apache/bin/suexec"
 -D DEFAULT_PIDLOG="logs/httpd.pid"
 -D DEFAULT_SCOREBOARD="logs/apache_runtime_status"
 -D DEFAULT_ERRORLOG="logs/error.log"
 -D AP_TYPES_CONFIG_FILE="conf/mime.types"
 -D SERVER_CONFIG_FILE="conf/httpd.conf"

mpm_winnt_module configuración:

<IfModule mpm_winnt_module>
    ThreadsPerChild 150
    ThreadStackSize 8388608 
    MaxConnectionsPerChild 0
</IfModule>

Extracto de php.ini:

realpath_cache_size = 12M
pcre.recursion_limit = 100000

4) Razón actual sospechada

Antigua suposición:

Los tres ejemplos dependen en gran medida de grandes matrices y operaciones de cadena. Que algunos kind parece ser la fábrica común. Como la implementación funciona bien en Linux, sospechamos que esto es un problema de memoria en Windows. Dado que no hay interacción con la base de datos en las ubicaciones puntiagudas, no sospechamos que la base de datos o la integración de PHP del Servidor sea el problema. De alguna manera la interacción de memoria de PHP parece ser lenta. Tal vez hay alguien interfiriendo con la memoria en Windows haciendo el acceso dramáticamente más lento?

Antigua suposición 2:

Como la misma pila funciona bien en otras máquinas Windows, asumimos que el problema está en algún lugar de la configuración de Windows.

Nueva suposición 3: {[17]]}

En realidad estoy fuera de suposiciones. ¿Por qué ejecutaría PHP mucho más lento como fastcgi que como módulo apache>

¿Alguna idea sobre cómo verificar esto o encontrar el verdadero problema aquí? Cualquier ayuda o dirección para solucionar este problema es muy bienvenida.

Author: Fge, 2014-04-03

5 answers

Windows tiene muchos servicios/políticas que restringen, previenen, protegen, controlan y etc. el uso de la computadora en cada situación.

Un buen especialista certificado de Microsoft será capaz de resolver su pregunta en cuestión de minutos, ya que tendrá la experiencia para decir exactamente qué configuración/servicios/políticas para comprobar y desactivar/activar/cambiar la configuración, de modo que los scripts PHP se ejecutan más rápido.

Fuera de mi memoria, solo puedo sugerirle que revise todo lo que se ocupa con RAM, Acceso al disco duro, Variables ambientales, Límites y Seguridad (como Firewall). Todo lo que puede afectar a la ejecución del script php, comenzando con algunas políticas de Llamada a Procedimientos remotos y terminando con la memoria de la pila operativa.

La lógica es que es php.exe llama a algunos externos .archivo dll para ejecutar alguna operación, puede haber comprobaciones en el camino realizado por el sistema operativo, que ralentizará tanto el envío de solicitudes a través de tales .dll, y recibir la respuesta de ella. Si el .dll utiliza el disco duro para acceder a algo, las directivas de acceso al disco duro entran en escena. Además, cómo todo está situado en la memoria-en RAM o caché de disco duro de RAM. Políticas de aplicación. Políticas de hilos. Límites en el porcentaje máximo disponible para su uso en aplicaciones.

No estoy diciendo que los hosts basados en Windows sean malos, solo que son mucho más difíciles de configurar correctamente para un administrador general. Si tiene un especialista de Microsoft en las manos, puede ajustar su servidor para que sea tan rápido como el servidor basado en Linux.

 8
Author: Toly,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-14 11:34:22
  • Habilitar APC, cuando se utiliza PHP5. 4

    • Si no nota una ganancia de velocidad, cuando APC está encendido, algo está mal configurado

      [APC] extension=php_apc.dll apc.enabled=1 apc.shm_segments=1 apc.shm_size=128M apc.num_files_hint=7000 apc.user_entries_hint=4096 apc.ttl=7200 apc.user_ttl=7200

  • Habilite el Opcode de Zend cuando esté en PHP 5.5

    [Zend] zend_extension=ext/php_zend.dll zend_optimizerplus.enable=1 zend_optimizerplus.use_cwd=1 zend_optimizerplus.validate_timestamp=0 zend_optimizerplus.revalidate_freq=2
    zend_optimizerplus.revalidate_path=0 zend_optimizerplus.dups_fix=0 zend_optimizerplus.log_verbosity_level=1 zend_optimizerplus.memory_consumption=128 zend_optimizerplus.interned_strings_buffer=16 zend_optimizerplus.max_accelerated_files=2000 zend_optimizerplus.max_wasted_percentage=25 zend_optimizerplus.consistency_checks=0 zend_optimizerplus.force_restart_timeout=60 zend_optimizerplus.blacklist_filename= zend_optimizerplus.fast_shutdown=0 zend_optimizerplus.optimization_level=0xfffffbbf zend_optimizerplus.enable_slow_optimizations=1 opcache.memory_consumption=128 opcache.interned_strings_buffer=8 opcache.max_accelerated_files=10000 opcache.revalidate_freq=60 opcache.fast_shutdown=1 opcache.enable_cli=1

  • Deshabilitar las extensiones de Wordpress paso a paso, para encontrar el monstruo de uso de memoria

  • establecer Wordpress: define('WP_MEMORY_LIMIT', '128M');, a menos que utilice plugins de conversión de imágenes que deberían ser suficientes
  • establecer memoria ilimitada en php.ini ini_set('memory_limit', -1);
  • perfil sin ejecutar Xdebug, esto suena loco, pero el propio depurador tiene un alto impacto
  • use memory_get_usage y difunda llamadas por todo el sistema para encontrar la posición del código, donde la memoria se filtra
  • pruebe zend.enable_gc=1, los scripts serán más lentos, pero usarán menos memoria
  • tal vez solo deshabilite la comprobación del navegador del usuario en la configuración de SlimStats..
  • si eso no es posible, intente anular la función SlimStats getBrowser (), con un getBrowser más rápido() substitute
  • para una comparación de velocidad de los fetchers user-agent, ver https://github.com/quentin389/ua-speed-tests
  • https://github.com/garetjax/phpbrowscap
 4
Author: Jens A. Koch,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-04 15:24:27

Eché un vistazo a ese plugin en Github:

Https://github.com/wp-plugins/wp-slimstat

Y el archivo ofensivo que se incluye es un archivo que ha sido minificado en cierta medida y realmente es datos (no código), hay 5 variaciones cada uno de que es de aproximadamente 400KB

También está ese maxmind.archivo dat que es 400KB, aunque no se si usa ambos.

Está utilizando una versión anterior del plugin, versión 3.2.3 y hay uno mucho más nuevo que puede resolver tu problema.

Comparar las diferencias es difícil porque el autor o quien no ha mantenido el historial de git en orden, así que tuve que diff manualmente el archivo. La mayoría de los cambios relacionado con _get_browser parece estar agregando una caché.

Es posible que cargar ese archivo sea lento para analizar, pero Yo esperaría que PHP se cargue ambos archivos en similar las tarifas en ambas plataformas otorgaron que el almacenamiento en caché de E / s es trabajo.

EDITAR Mirando un poco más de cerca que podría no resolver su problema. Esos archivos son básicamente grandes Expresiones Regulares tablas de búsqueda. ¿Su sistema Linux tiene una caché de APC ¿en él y éste no? La caché de APC probablemente mantener los datos del archivo PHP en caché (aunque no los compilados patrones de expresiones regulares)

 2
Author: Kristopher Ives,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-04 02:06:27

Utilice NGINX y FCGI para PHP a través de socket UNIX (no socket TCP).

Http://wiki.nginx.org/PHPFcgiExample

Notará mejoras de velocidad inmediatamente incluso sin aceleradores. Además, la configuración anterior tendría una huella de uso de memoria mucho menor.

 1
Author: mikikg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-13 06:07:22

Para solucionar un problema de este tipo, debe:

  • Utilice los registros del sistema, es decir, los registros de errores: ordenarlos por nivel de error
    y / o fecha para identificar las fechas de la emisión.
  • Comparar las actualizaciones de Windows en uso en cualquiera de los sistemas, uno de ellos podría ser defectuoso.
  • Compare el software en uso en cualquiera de los sistemas, la configuración de uno de ellos podría ser defectuosa.

Si ese es el caso, querrá desinstalar Windows update y / o el software que causa el problema, apague el servidor por completo y vuelva a instalar la actualización o el software (para garantizar un estado estable durante la configuración).

Las herramientas que pueden ayudarlo a solucionar este problema incluyen la suite sysinternals: http://technet.microsoft.com/en-us/sysinternals/bb842062.aspx

O más simplemente, scripts VBS de código abierto para producir listas comparables de actualizaciones y aplicaciones en un sistema.

 0
Author: Mauro Colella,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-03 17:55:34