Antes de contestar esto, nunca he desarrollado algo lo suficientemente popular como para alcanzar altas cargas de servidor. Trátame como (suspiro) un alienígena que acaba de aterrizar en el planeta, aunque conozca PHP y algunas técnicas de optimización.
Estoy desarrollando una herramienta en PHP que podría llegar a muchos usuarios, si funciona correctamente. Sin embargo, si bien soy completamente capaz de desarrollar el programa, no tengo ni idea cuando se trata de hacer algo que pueda manejar un tráfico enorme. Aquí hay algunas preguntas al respecto (siéntase libre de convertir esta pregunta en un hilo de recursos también).
Bases de datos
Por el momento planeo usar las características de MySQLi en PHP5. Sin embargo, ¿cómo debo configurar las bases de datos en relación con los usuarios y el contenido? ¿Realmente necesito múltiples bases de datos? Por el momento, todo está mezclado en una base de datos, aunque he estado considerando difundir los datos de los usuarios a uno, el contenido real a otro y finalmente el contenido del sitio central (maestros de plantillas, etc.) a otro. Mi razonamiento detrás de esto es que enviar consultas a diferentes bases de datos facilitará la carga en ellas como una base de datos = 3 fuentes de carga. ¿Esto también sería efectivo si todos estuvieran en el mismo servidor?
Almacenamiento en caché
Tengo un sistema de plantillas que se usa para construir las páginas e intercambiar variables. Las plantillas maestras se almacenan en la base de datos y cada vez que se llama a una plantilla se llama a la copia en caché (un documento html). Por el momento tengo dos tipos de variables en estas plantillas: una variable estática y una variable dinámica. Los vars estáticos suelen ser cosas como nombres de páginas, el nombre del sitio, cosas que no cambian con frecuencia; Las variables dinámicas son cosas que cambian en cada carga de página.
Mi pregunta sobre esto:
Digamos que tengo comentarios sobre diferentes artículos. Cuál es una mejor solución: almacenar la plantilla de comentario simple y presentar comentarios (de una llamada de DB) cada vez que se carga la página o almacenar una copia en caché de la página de comentarios como una página html, cada vez que se agrega / edita / elimina un comentario Se recupera la página.
Finalmente
¿Alguien tiene algún consejo / puntero para ejecutar un sitio de alta carga en PHP? Estoy bastante seguro de que es un lenguaje viable de usar: Facebook y Yahoo! darle una gran prioridad, pero ¿hay alguna experiencia que deba tener en cuenta?
fuente
Respuestas:
No hay dos sitios iguales. Realmente necesita obtener una herramienta como jmeter y benchmark para ver dónde estarán sus puntos problemáticos. Puede pasar mucho tiempo adivinando y mejorando, pero no verá resultados reales hasta que mida y compare sus cambios.
Por ejemplo, durante muchos años, el caché de consultas MySQL fue la solución a todos nuestros problemas de rendimiento. Si su sitio era lento, los expertos de MySQL sugirieron activar el caché de consultas. Resulta que si tienes una alta carga de escritura, el caché es realmente paralizante. Si lo encendiste sin probar, nunca lo sabrías.
Y no olvides que nunca has terminado de escalar. Un sitio que maneja 10req / s necesitará cambios para soportar 1000req / s. Y si tiene la suficiente suerte como para admitir 10,000 req / s, su arquitectura probablemente también se verá completamente diferente.
Bases de datos
Almacenamiento en caché
fuente
Soy desarrollador principal en un sitio con más de 15 millones de usuarios. Hemos tenido muy pocos problemas de escalado porque lo planeamos TEMPRANO y lo escalamos cuidadosamente. Estas son algunas de las estrategias que puedo sugerir a partir de mi experiencia.
ESQUEMA Primero, desnormalice sus esquemas. Esto significa que, en lugar de tener varias tablas relacionales, debería optar por tener una tabla grande. En general, las uniones son un desperdicio de recursos valiosos de la base de datos porque hacer múltiples preparaciones y colaciones quema las E / S del disco. Evítalos cuando puedas.
La desventaja aquí es que almacenará / extraerá datos redundantes, pero esto es aceptable porque los datos y el ancho de banda dentro de la jaula son muy baratos (discos más grandes), mientras que las E / S de preparación múltiple son mucho más caras (más servidores) .
ÍNDICE Asegúrese de que sus consultas utilizan al menos un índice. Sin embargo, tenga en cuenta que los índices le costarán si escribe o actualiza con frecuencia. Hay algunos trucos experimentales para evitar esto.
Puede intentar agregar columnas adicionales que no estén indexadas que se ejecutan paralelas a las columnas que están indexadas. Entonces puede tener un proceso fuera de línea que escribe las columnas no indexadas sobre las columnas indexadas en lotes. De esta manera, puede controlar mejor cuándo mySQL necesitará volver a calcular el índice.
Evite consultas calculadas como una plaga. Si debe calcular una consulta, intente hacerlo una vez en el momento de la escritura.
CACHING Recomiendo encarecidamente Memcached. Ha sido probado por los jugadores más importantes en la pila de PHP (Facebook) y es muy flexible. Hay dos métodos para hacerlo, uno es el almacenamiento en caché en la capa de base de datos, el otro es el almacenamiento en caché en la capa de lógica de negocios.
La opción de capa de base de datos requeriría almacenar en caché el resultado de las consultas recuperadas de la base de datos. Puede hacer hash en su consulta SQL usando md5 () y usar eso como una clave de búsqueda antes de ir a la base de datos. La ventaja de esto es que es bastante fácil de implementar. La desventaja (dependiendo de la implementación) es que pierde flexibilidad porque trata a todos los cachés de la misma manera con respecto a la caducidad del caché.
En la tienda en la que trabajo, utilizamos el almacenamiento en caché de la capa empresarial, lo que significa que cada clase concreta en nuestro sistema controla su propio esquema de almacenamiento en caché y tiempos de espera de caché. Esto ha funcionado bastante bien para nosotros, pero tenga en cuenta que los elementos recuperados de DB pueden no ser los mismos que los elementos de la memoria caché, por lo que deberá actualizar la memoria caché y la base de datos juntas.
RECUBRIMIENTO DE DATOS La replicación solo te lleva muy lejos. Antes de lo esperado, sus escritos se convertirán en un cuello de botella. Para compensar, asegúrese de admitir el fragmentación de datos lo antes posible. Es probable que quieras dispararte más tarde si no lo haces.
Es bastante simple de implementar. Básicamente, desea separar la autoridad clave del almacenamiento de datos. Use una base de datos global para almacenar una asignación entre las claves principales y los identificadores de clúster. Consulta esta asignación para obtener un clúster y luego consulta el clúster para obtener los datos. Puede almacenar en caché esta operación de búsqueda, lo que la convertirá en una operación insignificante.
La desventaja de esto es que puede ser difícil juntar datos de múltiples fragmentos. Pero también puedes diseñar tu camino alrededor de eso.
PROCESAMIENTO SIN CONEXIÓN No haga que el usuario espere su backend si no tiene que hacerlo. Cree una cola de trabajos y mueva cualquier procesamiento que pueda sin conexión, separándolo de la solicitud del usuario.
fuente
He trabajado en algunos sitios que obtienen millones / visitas / mes respaldados por PHP y MySQL. Aquí hay algunos conceptos básicos:
Recomiendo leer Creación de sitios web escalables , fue escrito por uno de los ingenieros de Flickr y es una gran referencia.
Consulte también mi publicación de blog sobre escalabilidad, tiene muchos enlaces a presentaciones sobre escalado con múltiples idiomas y plataformas: http://www.ryandoherty.net/2008/07/13/unicorns-and-scalability/
fuente
Re: PDO / MySQLi / MySQLND
@ @ gary
No puede simplemente decir "no use MySQLi", ya que tienen objetivos diferentes. PDO es casi como una capa de abstracción (aunque en realidad no lo es) y está diseñado para facilitar el uso de múltiples productos de bases de datos, mientras que MySQLi es específico para las conexiones de MySQL. Es incorrecto decir que PDO es la capa de acceso moderna en el contexto de compararla con MySQLi porque su declaración implica que la progresión ha sido mysql -> mysqli -> PDO, lo cual no es el caso.
La elección entre MySQLi y PDO es simple: si necesita admitir múltiples productos de base de datos, entonces usa PDO. Si solo está utilizando MySQL, puede elegir entre PDO y MySQLi.
Entonces, ¿por qué elegirías MySQLi sobre PDO? Vea abajo...
@ross
Estás en lo cierto acerca de MySQLnd, que es la biblioteca de nivel de lenguaje central más reciente de MySQL, sin embargo, no es un reemplazo para MySQLi. MySQLi (como con PDO) sigue siendo la forma en que interactuaría con MySQL a través de su código PHP. Ambos usan libmysql como el cliente C detrás del código PHP. El problema es que libmysql está fuera del motor central de PHP y ahí es donde entra mysqlnd, es decir, es un controlador nativo que hace uso de los componentes internos centrales de PHP para maximizar la eficiencia, específicamente en lo que respecta al uso de memoria.
MySQLnd está siendo desarrollado por MySQL y recientemente aterrizó en la rama PHP 5.3 que está en pruebas RC, lista para su lanzamiento a finales de este año. Entonces podrá usar MySQLnd con MySQLi ... pero no con PDO. Esto le dará a MySQLi un aumento de rendimiento en muchas áreas (no todas) y lo convertirá en la mejor opción para la interacción de MySQL si no necesita la abstracción como las capacidades de PDO.
Dicho esto, MySQLnd ahora está disponible en PHP 5.3 para PDO y, por lo tanto, puede obtener las ventajas de las mejoras de rendimiento de ND a PDO, sin embargo, PDO sigue siendo una capa de base de datos genérica y, por lo tanto, es poco probable que pueda beneficiarse tanto de las mejoras en ND como MySQLi puede .
Aquí se pueden encontrar algunos puntos de referencia útiles, aunque son de 2006. También debe ser consciente de cosas como esta opción .
Hay muchas consideraciones que deben tenerse en cuenta al decidir entre MySQLi y PDO. En realidad, no va a importar hasta que obtenga números de solicitud ridículamente altos y, en ese caso, tiene más sentido usar una extensión que se haya diseñado específicamente para MySQL en lugar de una que abstraiga cosas y proporcione un controlador MySQL .
No es una simple cuestión de cuál es mejor porque cada uno tiene ventajas y desventajas. Debe leer los enlaces que he proporcionado y llegar a su propia decisión, luego probarlo y averiguarlo. He usado PDO en proyectos anteriores y es una buena extensión, pero mi elección para un rendimiento puro sería MySQLi con la nueva opción MySQLND compilada (cuando se lanza PHP 5.3).
fuente
General
Código
Bases de datos
Almacenamiento en caché
Diverso
fuente
APC es una necesidad absoluta. No solo es un gran sistema de almacenamiento en caché, sino que la ganancia de los archivos PHP de almacenamiento en caché automático es una bendición. En cuanto a la idea de múltiples bases de datos, no creo que se pueda sacar mucho provecho de tener diferentes bases de datos en el mismo servidor. Puede darle un poco de ganancia de velocidad durante el tiempo de consulta, pero dudo que el esfuerzo que se necesitaría para implementar y mantener el código para los tres mientras se asegura de que estén sincronizados valdría la pena.
También recomiendo ejecutar Xdebug para encontrar cuellos de botella en su programa. Hizo de la optimización una brisa para mí.
fuente
En primer lugar, como creo que dijo Knuth, "La optimización prematura es la raíz de todo mal". Si no tiene que lidiar con estos problemas ahora, no lo haga, concéntrese en entregar algo que funcione correctamente primero. Dicho esto, si las optimizaciones no pueden esperar.
Intente perfilar las consultas de su base de datos, descubra lo que es lento y lo que sucede mucho, e idee una estrategia de optimización a partir de eso.
Investigaría Memcached ya que es lo que muchos de los sitios de mayor carga usan para almacenar en caché de manera eficiente contenido de todo tipo, y la interfaz de objetos PHP es bastante agradable.
La división de bases de datos entre servidores y el uso de algún tipo de técnica de equilibrio de carga (por ejemplo, generar un número aleatorio entre 1 y # bases de datos redundantes con los datos necesarios, y usar ese número para determinar a qué servidor de bases de datos conectarse) también puede ser una excelente manera de aumentar eficiencia.
Todo esto ha funcionado bastante bien en el pasado para algunos sitios de carga bastante alta. Espero que esto ayude a comenzar :-)
fuente
Definir su aplicación con algo como Xdebug (como se recomienda tj9991) definitivamente será imprescindible. No tiene mucho sentido simplemente optimizar las cosas a ciegas. Xdebug lo ayudará a encontrar los cuellos de botella reales en su código para que pueda pasar su tiempo de optimización con prudencia y corregir fragmentos de código que realmente están causando desaceleraciones.
Si está usando Apache, otra utilidad que puede ayudar en las pruebas es Siege . Le ayudará a anticipar cómo su servidor y su aplicación reaccionarán a las altas cargas al realmente ponerlo a prueba.
Cualquier tipo de caché de código de operación para PHP (como APC o uno de los muchos otros) también ayudará mucho.
fuente
Tengo un sitio web con 7-8 millones de visitas al mes. No mucho, pero lo suficiente como para que nuestro servidor sintiera la carga. La solución que elegimos fue simple: Memcache a nivel de base de datos. Esta solución funciona bien si la carga de la base de datos es su principal problema.
Comenzamos usando Memcache para almacenar en caché objetos completos y los resultados de la base de datos que se usaban con mayor frecuencia. Funcionó, pero también introdujo errores (podríamos haber evitado algunos si hubiéramos sido más cuidadosos).
Entonces cambiamos nuestro enfoque. Creamos un contenedor de base de datos (con exactamente los mismos métodos que nuestra base de datos anterior, por lo que fue fácil cambiarlo), y luego lo subclasificamos para proporcionar métodos de acceso a la base de datos memcached.
Ahora todo lo que tiene que hacer es decidir si una consulta puede usar resultados en caché (y posiblemente desactualizados) o no. La mayoría de las consultas ejecutadas por los usuarios ahora se obtienen directamente de Memcache. Las excepciones son las actualizaciones e inserciones, que para el sitio web principal solo ocurren debido al registro. Esta medida bastante simple redujo la carga de nuestro servidor en aproximadamente un 80%.
fuente
Por lo que vale, el almacenamiento en caché es DIRT SIMPLE en PHP incluso sin un paquete de extensión / ayuda como memcached.
Todo lo que necesitas hacer es crear un buffer de salida usando
ob_start()
.Crea una función de caché global. Llamada
ob_start
, pasa la función como devolución de llamada. En la función, busque una versión en caché de la página. Si existe, sírvela y termina.Si no existe, el script continuará procesándose. Cuando llegue al ob_end () correspondiente, llamará a la función que especificó. En ese momento, solo obtiene el contenido del búfer de salida, los coloca en un archivo, guarda el archivo y finaliza.
Agregue un poco de vencimiento / recolección de basura.
Y muchas personas no se dan cuenta de que puedes anidar
ob_start()
/ob_end()
llamar. Entonces, si ya está utilizando un búfer de salida para, por ejemplo, analizar anuncios o resaltar la sintaxis o lo que sea, simplemente puede anidar otraob_start/ob_end
llamada.fuente
En realidad, muchos usan APC y memcached juntos ...
fuente
Parece que me equivoqué . MySQLi aún se está desarrollando. Pero según el artículo, el equipo de MySQL está contribuyendo a PDO_MySQL. Del artículo:
Para mí, parece que el artículo está sesgado hacia MySQLi. Supongo que soy parcial hacia la DOP. Realmente me gusta PDO sobre MySQLi. Es directo para mí. La API está mucho más cerca de otros lenguajes que he programado. Las interfaces de la base de datos OO parecen funcionar mejor.
No he encontrado ninguna característica específica de MySQL que no estuviera disponible a través de PDO. Me sorprendería si alguna vez lo hiciera.
fuente
PDO también es muy lento y su API es bastante complicada. Nadie en su sano juicio debería usarlo si la portabilidad no es una preocupación. Y seamos sinceros, en el 99% de todas las aplicaciones web no lo es. Simplemente se queda con MySQL o PostrgreSQL, o con lo que sea que esté trabajando.
En cuanto a la pregunta de PHP y qué tener en cuenta. Creo que la optimización prematura es la raíz de todo mal. ;) Primero haga su aplicación, trate de mantenerla limpia cuando se trata de programación, haga un poco de documentación y escriba pruebas unitarias. Con todo lo anterior, no tendrá problemas para refactorizar el código cuando llegue el momento. Pero primero quieres terminar y sacarlo para ver cómo reacciona la gente.
fuente
Claro que pdo es bueno, pero ha habido algunos controversia sobre su rendimiento frente a mysql y mysqli, aunque ahora parece arreglado.
Debería usar pdo si visualiza la portabilidad, pero si no, mysqli debería ser el camino. Tiene una interfaz OO, declaraciones preparadas y la mayoría de lo que ofrece pdo (excepto, bueno, portabilidad).
Además, si realmente se necesita rendimiento, prepárese para el controlador MysqLnd (nativo de mysql) en PHP 5.3, que estará mucho más integrado con php, con un mejor rendimiento y un mejor uso de la memoria (y estadísticas para el ajuste del rendimiento).
Memcache es bueno si tienes servidores en clúster (y una carga similar a YouTube), pero también probaría APC primero.
fuente
Ya se dieron muchas buenas respuestas, pero me gustaría señalarle un caché de código de operación alternativo llamado XCache . Es creado por un colaborador ligero.
Además, si necesita equilibrar la carga de su servidor de base de datos en el futuro, MySQL Proxy podría ayudarlo a lograrlo.
Ambas herramientas deberían conectarse a una aplicación existente con bastante facilidad, por lo que esta optimización se puede hacer cuando la necesite, sin demasiados problemas.
fuente
La primera pregunta es ¿qué tan grande realmente espera que sea? ¿Y cuánto planea invertir en su infraestructura? Dado que siente la necesidad de hacer la pregunta aquí, supongo que espera comenzar de a poco con un presupuesto limitado.
El rendimiento es irrelevante si el sitio no está disponible. Y para disponibilidad, necesita escala horizontal. El mínimo con el que puede salirse con la suya es 2 servidores, ambos con apache, php y mysql. Configure un DBMS como esclavo del otro. Realice todas las escrituras en el maestro y todas las lecturas en la base de datos local (sea lo que sea), a menos que por alguna razón necesite volver a leer los datos que acaba de leer (use el maestro). Asegúrese de tener la maquinaria en su lugar para promover automáticamente al esclavo y cercar al maestro. Utilice DNS de round-robin para las direcciones del servidor web para dar más afinidad al nodo esclavo.
Particionar sus datos en diferentes nodos de bases de datos en esta etapa es una muy mala idea; sin embargo, es posible que desee considerar dividirlos en diferentes bases de datos en el mismo servidor (lo que facilitará la partición entre nodos cuando supere a Facebook).
Asegúrese de contar con las herramientas de monitoreo y análisis de datos para medir el rendimiento de sus sitios e identificar cuellos de botella. La mayoría de los problemas de rendimiento se pueden solucionar escribiendo un mejor SQL / arreglando el esquema de la base de datos.
Mantener el caché de su plantilla en la base de datos es una idea tonta: la base de datos debe ser un repositorio común central para datos estructurados. Mantenga su caché de plantilla en el sistema de archivos local de sus servidores web: estará disponible más rápido y no ralentizará el acceso a su base de datos.
Utilice un caché de código operativo.
Dedique mucho tiempo a estudiar su sitio y sus registros para comprender por qué va tan lento.
Empuje la mayor cantidad de caché posible en el cliente.
Usa mod_gzip para comprimir todo lo que puedas.
C.
fuente
Mi primer consejo es pensar en este problema y tenerlo en cuenta al diseñar el sitio, pero no exagerar . A menudo es difícil predecir el éxito de un nuevo sitio y su tiempo será mejor empleado para terminar temprano y optimizarlo más tarde.
En general, simple es rápido . Las plantillas te ralentizan. Las bases de datos te ralentizan. Las bibliotecas complejas te ralentizan. Colocando las plantillas una sobre otra, recuperándolas de las bases de datos y analizándolas en una biblioteca compleja -> los retrasos se multiplican entre sí.
Una vez que tenga el sitio básico en funcionamiento, realice pruebas para mostrarle dónde gastar sus esfuerzos. Es difícil ver a dónde apuntar. A menudo, para acelerar las cosas, tendrá que desentrañar la complejidad del código, esto lo hace más grande y más difícil de mantener, por lo que solo desea hacerlo cuando sea necesario.
En mi experiencia, establecer la conexión de la base de datos fue relativamente costoso. Si puede salirse con la suya, no se conecte a la base de datos para visitantes generales en las páginas más transitadas, como la página principal del sitio. Crear múltiples conexiones de bases de datos es una locura con muy pocos beneficios.
fuente
@ Gary
Estoy buscando PDO en este momento y parece que tienes razón, sin embargo, sé que MySQL está desarrollando la extensión MySQLd para PHP. Creo que MySQL o MySQLi tienen éxito, ¿qué piensas al respecto?
@ Ryan , Eric , tj9991
Gracias por el consejo sobre las extensiones de almacenamiento en caché de PHP. ¿Podría explicar las razones para usar una sobre otra? He escuchado grandes cosas sobre memcached a través de IRC, pero nunca he oído hablar de APC, ¿cuáles son sus opiniones sobre ellos? Supongo que usar múltiples sistemas de almacenamiento en caché es bastante contra-efectivo.
Definitivamente ordenaré algunos probadores de perfiles. Muchas gracias por sus recomendaciones.
fuente
No me veo cambiando de MySQL pronto, así que supongo que no necesito las capacidades de abstracción de PDO. Gracias por esos artículos, DavidM, me han ayudado mucho.
fuente
Mire en mod_cache , un caché de salida para el servidor web Apache, similar al almacenamiento en caché de salida en ASP.NET.
Sí, puedo ver que todavía es experimental, pero algún día será definitivo.
fuente
No puedo creer que nadie ya haya mencionado esto: modularización y abstracción. Si cree que su sitio va a tener que crecer en muchas máquinas, debe diseñarlo para que pueda! Eso significa cosas estúpidas como no asumir que la base de datos está en localhost. También significa cosas que serán una molestia al principio, como escribir una capa de abstracción de base de datos (como PDO, pero mucho más ligera porque solo hace lo que necesita hacer).
Y significa cosas como trabajar con un marco. Necesitará capas en su código para que luego pueda obtener un rendimiento refactorizando la capa de abstracción de datos, por ejemplo, enseñándole que algunos objetos están en una base de datos diferente, y que el código no tiene que saberlo ni importarle .
Finalmente, tenga cuidado con las operaciones intensivas en memoria, por ejemplo, la copia innecesaria de cadenas. Si puede mantener bajo el uso de memoria de PHP, obtendrá más rendimiento de su servidor web y esto es algo que escalará cuando vaya a una solución de carga equilibrada.
fuente
Si está trabajando con grandes cantidades de datos y el almacenamiento en caché no es suficiente, busque en Sphinx. Hemos tenido excelentes resultados con el uso de SphinxSearch no solo para una mejor búsqueda de texto, sino también como un reemplazo de recuperación de datos para MySQL cuando se trata de tablas más grandes. Si usa SphinxSE (complemento MySQL), superó nuestras ganancias de rendimiento que obtuvimos al almacenar en caché varias veces, y la implementación de la aplicación es muy sencilla.
fuente
Los puntos hechos sobre el caché son precisos; Es la parte menos complicada y más importante de construir una aplicación eficiente. Me gustaría agregar que si bien memcached es excelente, APC es aproximadamente cinco veces más rápido si su aplicación vive en un solo servidor.
La publicación "Comparación de rendimiento de caché" en el blog de rendimiento de MySQL tiene algunos puntos de referencia interesantes sobre el tema: http://www.mysqlperformanceblog.com/2006/08/09/cache-performance-comparison/ .
fuente