Optimización de sitios web basados ​​en Kohana para lograr velocidad y escalabilidad


80

Un sitio que construí con Kohana se estrelló con una enorme cantidad de tráfico ayer, lo que me hizo dar un paso atrás y evaluar parte del diseño. Tengo curiosidad por saber cuáles son algunas de las técnicas estándar para optimizar las aplicaciones basadas en Kohana.

También me interesa la evaluación comparativa. ¿Necesito configurarBenchmark::start() y Benchmark::stop()para cada método de controlador para ver los tiempos de ejecución de todas las páginas, o puedo aplicar la evaluación comparativa global y rápidamente?

Usaré la biblioteca de caché más en el futuro, pero estoy abierto a más sugerencias, ya que estoy seguro de que hay muchas cosas que puedo hacer de las que simplemente no estoy al tanto en este momento.


¿Probaste la compilación en Kohana Profiler para obtener información de la aplicación? Es bastante bueno
Yasen Zhelev

Respuestas:


211

Lo que diré en esta respuesta no es específico de Kohana y probablemente se pueda aplicar a muchos proyectos PHP.

Aquí hay algunos puntos que me vienen a la mente cuando hablo de rendimiento, escalabilidad, PHP, ...
He usado muchas de esas ideas mientras trabajaba en varios proyectos, y me ayudaron; por lo que probablemente también podrían ayudar aquí.


En primer lugar, cuando se trata de actuaciones, hay muchos aspectos / preguntas que se deben considerar :

  • configuración del servidor (tanto Apache, PHP, MySQL, otros posibles demonios y sistema) ; podría obtener más ayuda al respecto en ServerFault , supongo,
  • Código PHP,
  • Consultas de bases de datos,
  • ¿Utilizas o no tu servidor web?
  • ¿Puede utilizar algún tipo de mecanismo de almacenamiento en caché? ¿O necesita siempre más datos actualizados en el sitio web?


Usando un proxy inverso

Lo primero que podría ser realmente útil es usar un proxy inverso , como barniz , frente a su servidor web: deje que almacene en caché tantas cosas como sea posible , de modo que solo las solicitudes que realmente necesiten cálculos de PHP / MySQL (y, por supuesto, algunos otros solicitudes, cuando no están en la caché del proxy) llegan a Apache / PHP / MySQL.

  • Primero que nada, su CSS / Javascript / Imágenes - bueno, todo lo que es estático - probablemente no necesite ser servido siempre por Apache.
    • Entonces, puede tener el caché de proxy inverso todos esos.
    • Servir esos archivos estáticos no es un gran problema para Apache, pero cuanto menos tenga que trabajar para ellos, más podrá hacer con PHP.
    • Recuerde: Apache solo puede servir un número finito y limitado de solicitudes a la vez.
  • Luego, haga que el proxy inverso sirva tantas páginas PHP como sea posible desde la caché: probablemente hay algunas páginas que no cambian con tanta frecuencia y podrían ser servidas desde la caché. En lugar de usar un caché basado en PHP, ¿por qué no dejar que otro servidor más liviano los sirva (y obtenerlos del servidor PHP de vez en cuando, para que siempre estén casi actualizados) ?
    • Por ejemplo, si tiene algunos feeds RSS (generalmente tendemos a olvidarlos cuando intentamos optimizar el rendimiento) que se solicitan con mucha frecuencia. , tenerlos en caché durante un par de minutos podría ahorrar cientos / miles de solicitudes a Apache + PHP + MySQL!
    • Lo mismo para las páginas más visitadas de su sitio, si no cambian durante al menos un par de minutos (ejemplo: ¿página de inicio?) , Entonces, no hay necesidad de desperdiciar CPU para volver a generarlas cada vez que un usuario las solicita.
  • Tal vez haya una diferencia entre las páginas servidas para usuarios anónimos (la misma página para todos los usuarios anónimos) y las páginas servidas para usuarios identificados ("Hola Sr. X, tiene mensajes nuevos", por ejemplo) .
    • Si es así, probablemente pueda configurar el proxy inverso para almacenar en caché la página que se sirve para usuarios anónimos (en función de una cookie, como la cookie de sesión, normalmente)
    • Significará que Apache + PHP tiene menos con qué lidiar: solo usuarios identificados, que pueden ser solo una pequeña parte de sus usuarios.

Acerca del uso de un proxy inverso como caché , para una aplicación PHP, puede, por ejemplo, echar un vistazo a Benchmark Results Show 400% -700% Increase In Server Capabilities with APC y Squid Cache .
(Sí, están usando Squid, y estaba hablando de barniz, esa es solo otra posibilidad ^^ Varnish es más reciente, pero más dedicado al almacenamiento en caché)

Si lo hace lo suficientemente bien y logra dejar de volver a generar demasiadas páginas una y otra vez, tal vez ni siquiera tenga que optimizar su código ;-)
Al menos, tal vez no con prisa ... Y siempre es mejor realizar optimizaciones cuando no estás bajo demasiada presión ...


Como nota al margen: está diciendo en el OP:

Un sitio que construí con Kohana recibió una enorme cantidad de tráfico ayer,

Este es el tipo de situación repentina en la que un proxy inverso puede literalmente salvar el día , si su sitio web puede lidiar con no estar actualizado en el segundo:

  • instálelo, configúrelo, déjelo siempre , todos los días normales, ejecutar:
    • Configúrelo para que no mantenga las páginas PHP en caché; o solo por una corta duración; De esta manera, siempre se muestran datos actualizados.
  • Y, el día que toma un efecto slashdot o digg:
    • Configure el proxy inverso para mantener las páginas PHP en caché; o por un período de tiempo más largo; tal vez sus páginas no estén actualizadas en un segundo, ¡pero permitirá que su sitio web sobreviva al efecto digg!

Acerca de eso, ¿cómo puedo detectar y sobrevivir siendo "Slashdotted"? podría ser una lectura interesante.


En el lado de PHP de las cosas:

En primer lugar: ¿está utilizando una versión reciente de PHP ? Regularmente hay mejoras en la velocidad, con nuevas versiones ;-)
Por ejemplo, eche un vistazo a Benchmark of PHP Branches 3.0 a 5.3-CVS .

Tenga en cuenta que el rendimiento es una buena razón para usar PHP 5.3 ( hice algunos puntos de referencia (en francés) y los resultados son excelentes) ...
Otra razón bastante buena es, por supuesto, que PHP 5.2 ha llegado al final de su vida útil. ¡y ya no se mantiene!

¿Está utilizando alguna caché de código de operación?

  • Estoy pensando en APC - Caché PHP alternativo , por ejemplo ( pecl , manual ) , que es la solución que he visto más utilizada, y que se utiliza en todos los servidores en los que he trabajado.
  • Realmente puede reducir mucho la carga de la CPU de un servidor, en algunos casos (¡he visto que la carga de la CPU en algunos servidores pasa del 80% al 40%, simplemente instalando APC y activando su funcionalidad de caché de código de operación!)
  • Básicamente, la ejecución de un script PHP se realiza en dos pasos:
    • Compilación del código fuente PHP en códigos de operación (una especie de equivalente del código de bytes de JAVA)
    • Ejecución de esos códigos de operación
    • APC los mantiene en la memoria, por lo que hay menos trabajo por hacer cada vez que se ejecuta un script / archivo PHP: solo obtenga los códigos de operación de la RAM y ejecútelos.
  • Puede que tenga que echar un vistazo a la APC opciones de configuración , por cierto
    • hay bastantes de esos, y algunos pueden tener un gran impacto tanto en la velocidad / carga de CPU / facilidad de uso para usted
    • Por ejemplo, la desactivación [apc.stat](https://php.net/manual/en/apc.configuration.php#ini.apc.stat)puede ser buena para la carga del sistema; pero significa que las modificaciones realizadas a los archivos PHP no se tendrán en cuenta a menos que vacíe todo el caché de código de operación; sobre eso, para obtener más detalles, consulte, por ejemplo, To stat () o Not To stat ()?


Usar caché para datos

En la medida de lo posible, es mejor evitar hacer lo mismo una y otra vez. .

Lo principal en lo que estoy pensando es, por supuesto, en las consultas SQL: muchas de sus páginas probablemente hagan las mismas consultas, y los resultados de algunas de ellas probablemente sean casi siempre los mismos ... Lo que significa muchas consultas "inútiles" en la base de datos, que tiene que dedicar tiempo a entregar los mismos datos una y otra vez.
Por supuesto, esto es cierto para otras cosas, como llamadas de servicios web, obtener información de otros sitios web, cálculos pesados, ...

Puede resultarle muy interesante identificar:

  • Qué consultas se ejecutan muchas veces, siempre devolviendo los mismos datos
  • Qué otros cálculos (pesados) se realizan mucho tiempo, siempre devolviendo el mismo resultado

Y almacene estos datos / resultados en algún tipo de caché, para que sean más fáciles de obtener, más rápido , y no tenga que ir a su servidor SQL por "nada".

Los grandes mecanismos de almacenamiento en caché son, por ejemplo:

  • APC : además del opcode-cache del que hablé antes, te permite almacenar datos en la memoria,
  • Y / o memcached ( ver también ) , que es muy útil si literalmente tienes muchos datos y / o estás usando varios servidores. , ya que están distribuidos.
  • por supuesto, puede pensar en archivos; y probablemente muchas otras ideas.

Estoy bastante seguro de que su marco viene con algunas cosas relacionadas con la caché; probablemente ya lo sepas, como dijiste "Usaré la biblioteca Cache más en el futuro" en el OP ;-)


Perfilado

Ahora, una buena cosa sería usar la extensión Xdebug para perfilar su aplicación : a menudo permite encontrar un par de puntos débiles con bastante facilidad, al menos, si hay alguna función que requiere mucho tiempo.

Configurado correctamente , generará archivos de perfilado que se pueden analizar con algunas herramientas gráficas, como:

  • KCachegrind : mi favorito, pero solo funciona en Linux / KDE
  • Wincachegrind para Windows; Desafortunadamente, hace un poco menos de cosas que KCacheGrind; por lo general, no muestra gráficos de llamadas.
  • Webgrind, que se ejecuta en un servidor web PHP, funciona en cualquier lugar, pero probablemente tiene menos funciones.

Por ejemplo, aquí hay un par de capturas de pantalla de KCacheGrind:

KCacheGrind: pantalla principal
(fuente: pascal-martin.fr ) (fuente: pascal-martin.fr )
KCacheGrind: Callgraph exportado como una imagen

(Por cierto, el gráfico de llamadas presentado en la segunda captura de pantalla suele ser algo que ni WinCacheGrind ni Webgrind pueden hacer, si no recuerdo mal ^^)


(Gracias @Mikushi por el comentario) Otra posibilidad que no he usado mucho es el xhprof extensión : también ayuda con la creación de perfiles, puede generar gráficos de llamadas, pero es más liviana que Xdebug, lo que significa que debería poder instalarla en un servidor de producción.

Debería poder usarlo junto con XHGui , lo que ayudará a visualizar los datos.


En el lado SQL de las cosas:

Ahora que hemos hablado un poco sobre PHP, tenga en cuenta que es más que posible que su cuello de botella no sea el lado de PHP , sino el de la base de datos ...

Al menos dos o tres cosas, aquí:

  • Debes determinar:
    • ¿Cuáles son las consultas más frecuentes que realiza su aplicación?
    • Si están optimizados (¿utilizando los índices correctos , principalmente?) , Utilizando la EXPLAINinstrucción, si está utilizando MySQL
    • si puede almacenar en caché algunas de estas consultas (vea lo que dije antes)
  • ¿Está bien configurado MySQL? No sé mucho sobre eso, pero hay algunas opciones de configuración que pueden tener algún impacto.

Aún así, las dos cosas más importantes son:

  • No vaya a la base de datos si no lo necesita: ¡ caché tanto como pueda !
  • Cuando tenga que ir a la base de datos, utilice consultas eficientes: utilice índices; y perfil!


¿Y ahora qué?

Si todavía está leyendo, ¿qué más se puede optimizar?

Bueno, todavía hay espacio para mejoras ... Un par de ideas orientadas a la arquitectura podrían ser:

  • Cambie a una arquitectura de n niveles:
    • Ponga MySQL en otro servidor (2 niveles: uno para PHP; el otro para MySQL)
    • Utilice varios servidores PHP (y equilibre la carga de los usuarios entre ellos)
    • Utilice otras máquinas para archivos estáticos, con un servidor web más ligero, como:
      • lighttpd
      • o nginx : este se está volviendo cada vez más popular, por cierto.
    • Utilice varios servidores para MySQL, varios servidores para PHP y varios proxies inversos delante de esos
    • Por supuesto: instale demonios memcached en cualquier servidor que tenga cualquier cantidad de RAM libre y utilícelos para almacenar en caché tanto como pueda / tenga sentido.
  • ¿Usar algo "más eficiente" que Apache?
    • Escucho cada vez más a menudo sobre nginx , que se supone que es genial cuando se trata de PHP y sitios web de alto volumen; Yo nunca lo he usado, pero puede encontrar algunos artículos interesantes sobre él en la red;

Bueno, tal vez algunas de esas ideas sean un poco exageradas en tu situación ^^
Pero, aún así ... ¿Por qué no estudiarlas un poco, por si acaso? ;-)


¿Y qué hay de Kohana?

Su pregunta inicial fue sobre la optimización de una aplicación que usa Kohana ... Bueno, he publicado algunas ideas que son ciertas para cualquier aplicación PHP ... Lo que significa que también son ciertas para Kohana ;-)
(Incluso si no son específicas para ella ^^)

Dije: usa caché; Kohana parece admitir algunas cosas de almacenamiento en caché (lo hablaste tú mismo, así que no hay nada nuevo aquí ...)
Si hay algo que se pueda hacer rápidamente, pruébalo ;-)

También dije que no deberías hacer nada que no sea necesario; ¿Hay algo habilitado por defecto en Kohana que no necesite?
Navegando por la red, parece que hay al menos algo sobre el filtrado XSS; lo necesitas?

Aún así, aquí hay un par de enlaces que pueden ser útiles:


¿Conclusión?

Y, para concluir, un simple pensamiento:

  • ¿Cuánto le costará a su empresa pagarle 5 días? - considerando que es una cantidad de tiempo razonable para realizar grandes optimizaciones
  • ¿Cuánto le costará a su empresa comprar (pagar?) un segundo servidor y su mantenimiento?
  • ¿Qué pasa si tienes que escalar más?
    • ¿Cuánto costará gastar 10 días? ¿más? optimizar cada parte posible de su aplicación?
    • ¿Y cuánto por un par de servidores más?

No estoy diciendo que no debas optimizar: ¡definitivamente deberías!
Pero opte por optimizaciones "rápidas" que le proporcionarán grandes recompensas primero: usar un caché de código de operación puede ayudarlo a obtener entre un 10 y un 50 por ciento de descuento en la carga de CPU de su servidor ... Y solo toma un par de minutos configurarlo; - ) Por otro lado, gastar 3 días por 2 por ciento ...

Ah, y, por cierto: antes de hacer nada: ponga algunas cosas de monitoreo en su lugar , para que sepa qué mejoras se han realizado y cómo.
Sin monitoreo, no tendrá idea del efecto de lo que hizo ... ¡Ni siquiera si es una optimización real o no!

Por ejemplo, podría usar algo como RRDtool + cactus .
Y mostrarle a tu jefe algunos gráficos agradables con una caída de carga de CPU del 40% siempre es genial ;-)


De todos modos, y para concluir realmente: ¡diviértete!
(¡Sí, optimizar es divertido!)
(Ergh, no pensé que escribiría tanto ... Espero que al menos algunas partes de esto sean útiles ... Y debo recordar esta respuesta: podría ser útil en otras ocasiones. ..)


Si bien agregar nuevos servidores puede ser más económico que tener un desarrollador trabajando durante 5 días, no olvide que es posible que su software no funcione correctamente cuando se ejecuta desde varios servidores (es posible que tenga que compartir archivos entre servidores de alguna manera; NFS puede ser una molestia. ¿Estás usando sesiones? Mejor muévelas a la base de datos, etc.). y eso en sí mismo requerirá que el desarrollador también trabaje en las cosas.
NSSec

16
¡Gran explicación! ¿Tiene un blog al que pueda suscribirme? :-)
Pantera gris

@ dnh828: Lo escribí con la esperanza de reutilizarlo para otras ocasiones (en realidad ya lo hice) ;; @MathieuK: definitivamente cierto (sobre las sesiones, aunque, en lugar de DB, también podría considerar usar Memcache) ;; @ Cd-MaN: ¡Gracias! De hecho, tengo un blog, pero está en francés y realmente no blogueo a menudo ... aún así, si estás interesado: blog.pascal-martin.fr
Pascal MARTIN

Considere echar un vistazo a XHProf ( pecl.php.net/package/xhprof ), me parece mejor que XDebug para perfilar mi código, especialmente en servidores de producción, combinado con XHGui ( github.com/preinheimer/xhprof ) es un verdadero placer trabajar con.
Mikushi

Lástima, ¿no? ;-) ;; Sin embargo, algo que puede hacer es usar el enlace stackoverflow.com/q/1260134/138475 para compartir esta pregunta, para que más personas puedan leer esta respuesta (es precisamente por eso que he escrito una respuesta tan larga: para que ser leído ^^)
Pascal MARTIN


5

Código de perfil con XDebug .

Utiliza mucho almacenamiento en caché. Si sus páginas son relativamente estáticas, el proxy inverso podría ser la mejor manera de hacerlo.


5

Kohana está listo para usar muy, muy rápido, excepto por el uso de objetos de base de datos. Para citar a Zombor "Puede reducir el uso de memoria asegurándose de que está utilizando el objeto de resultado de la base de datos en lugar de matrices de resultados". Esto marca una GRAN diferencia de rendimiento en un sitio que está siendo criticado. No solo utiliza más memoria, sino que ralentiza la ejecución de los scripts.

Además, debe usar el almacenamiento en caché. Prefiero Memcache y lo uso en mis modelos así:

public function get($e_id)
{
    $event_data = $this->cache->get('event_get_'.$e_id.Kohana::config('config.site_domain'));

    if ($event_data === NULL)
    {
        $this->db_slave
            ->select('e_id,e_name')
            ->from('Events')
            ->where('e_id', $e_id);

        $result = $this->db_slave->get();
        $event_data = ($result->count() ==1)? $result->current() : FALSE;

        $this->cache->set('event_get_'.$e_id.Kohana::config('config.site_domain'), $event_data, NULL, 300); // 5 minutes
    }

    return $event_data;
}

Esto también aumentará drásticamente el rendimiento. Las dos técnicas anteriores mejoraron el rendimiento de un sitio en un 80%.

Si proporcionó más información sobre dónde cree que está el cuello de botella, estoy seguro de que podríamos darle algunas ideas mejores.

Consulte también yslow (google it) para obtener otros consejos de rendimiento.


1

Estrictamente relacionado con Kohana (probablemente ya lo haya hecho, o no):

En modo de producción:

  1. Habilite el almacenamiento en caché interno (esto solo almacenará en caché los resultados de Kohana :: find_file, pero esto en realidad puede ayudar mucho.
  2. Deshabilitar generador de perfiles

Solo mis 2 centavos :)


0

Estoy totalmente de acuerdo con las respuestas de XDebug y el almacenamiento en caché. No busque en la capa Kohana para la optimización hasta que haya identificado sus cuellos de botella de mayor velocidad y escala.

XDebug le dirá dónde pasa la mayor parte de su tiempo e identificará "puntos de acceso" en su código. Conserve esta información de creación de perfiles para que pueda medir y medir las mejoras de rendimiento.

Problema y solución de ejemplo: si descubre que está creando objetos costosos de la base de datos cada vez, que en realidad no cambian con frecuencia, puede buscar almacenarlos en caché con memcached u otro mecanismo. Todas estas correcciones de rendimiento toman tiempo y agregan complejidad a su sistema, así que asegúrese de sus cuellos de botella antes de comenzar a corregirlos.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.