PHP Opcode: Mejore la performance de aplicaciones sin cambiar tu código

El opcode generado por el motor de PHP está influenciado fuertemente por la forma en que escribes tu código, no solo en términos del número de declaraciones para realizar una tarea. Claramente, importa mucho, y creo que es obvio para ti.

lo que podría ser menos obvio es que incluso la sintaxis del código puede cambiar completamente el opcode generado, causando un montón de sobrecarga para el CPU de la máquina para ejecutar el mismo código exacto.

En los últimos años, mi producto SaaS ha crecido mucho y me ha dado la oportunidad de ir más profundo y profundo en técnicas de optimización para ejecutar mi carga de trabajo lo más eficientemente posible.

Los resultados que vi son impresionantes y me han ayudado mucho en desbloquear el flujo de caja libre para seguir desarrollando mi viaje SaaS.

En este punto, el proceso de PHP dentro de mi producto SaaS está procesando más de 1.2 billones (con “b”) de paquetes de datos cada día en una máquina con 2vCPU y 8GB de memoria. Uso un grupo de escalado de AWS para tener más flexibilidad en caso de picos impredecibles, pero rara vez agrega una segunda máquina (una o dos veces por semana).

Vamos al tema del artículo. Creo que te encontrarás muy interesado.

¿Qué es el Opcode de PHP?

El opcode de PHP significa código de operación, y se refiere a las instrucciones de bajo nivel que ejecuta el motor de PHP después de que el código fuente de PHP que has escrito haya sido compilado.

En PHP, la compilación del código sucede en tiempo de ejecución: básicamente, la primera vez que tu código es tomado por el motor de PHP se compilará en este código amigable para la máquina, se almacenará en caché (por lo que el motor no compila el mismo código de nuevo) y luego se ejecutará.

Esta es una representación simple del proceso:

Almacenamiento en caché de opcodes de PHP

El almacenamiento en caché de opcodes de PHP le permite ahorrar tres pasos en el proceso de ejecución de código: la parsición del código PHP sin procesar, la tokenización y la compilación.

Una vez generado el opcode por primera vez, se almacena en memoria para que pueda ser reutilizado en solicitudes posteriores. Esto reduce la necesidad de que el motor de PHP vuelva a compilar el mismo código PHP cada vez que se ejecuta, ahorrando mucho consumo de CPU y memoria.

El almacenamiento en caché de opcodes más utilizado en PHP es OPCache, y se incluye de forma predeterminada a partir de PHP 5.5 hasta las versiones recientes. Es altamente eficiente y ampliamente compatible.

Almacenar en caché el bytecode precompilado del script requiere invalidar la caché tras cada despliegue. Esto es así porque si los archivos modificados tienen la versión de bytecode en la caché, PHP seguirá ejecutando la versión antigua del código hasta que purge la caché de opcodes, de modo que el nuevo código se compilará de nuevo generando un nuevo elemento de caché.

Cómo investigar los opcodes de PHP

Para comprender cómo diferentes sintaxis pueden afectar el opcode del script necesitamos una manera de capturar el código compilado generado por el motor de PHP.

Hay dos maneras de obtener los opcodes.

Funciones nativas del OPCache

Si tienes la extensión OPCache habilitada en tu máquina, puedes usar sus funciones nativas para obtener el opcode de un archivo PHP específico:

PHP

 

VLD (Vulcan Logic Disassembler) PHP Extension

VLD es una popular extensión de PHP que desensambla el código PHP compilado y emite los opcodes. Es una herramienta poderosa para entender cómo PHP interpreta y ejecuta tu código. Una vez instalado, puedes ejecutar un script PHP con VLD habilitado usando el comando php con las opciones -d:

Shell

 

La salida incluirá información detallada sobre los opcodes compilados, incluyendo cada operación, su línea de código asociada y más.

Uso de 3v4l (Acrónimo para EVAL)

3v4l es una herramienta en línea muy útil que permite ver los opcodes generados por un código PHP que escribes en el editor. Básicamente es un servidor PHP con VLD instalado para que pueda agarrar la salida de VLD y mostrarte los opcodes en el navegador.

Como es gratuito, usaremos esta herramienta en línea para las próximas análisis.

Cómo Generar Opcode PHP Eficiente

3v4l es perfecto para entender cómo la sintaxis de código que utilizamos puede influir en el opcode PHP resultante de una buena o mala manera. Comencemos a pegar el código de abajo en 3v4l. Mantiene la configuración “todas las versiones soportadas” y hace clic en “eval“.

PHP

 

Después de ejecutar el código, aparecerá un menú de pestañas en la parte inferior. Vaya a la pestaña VLD para visualizar el opcode correspondiente.

Shell

 

Tenga en cuenta que la primera operación es INIT_NS_FCALL_BY_NAME. El intérprete construye el nombre de la función usando el espacio de nombres del archivo actual, pero no existe en el espacio de nombres App\Example — ¿cómo funciona?

El intérprete verificará si la función existe en el espacio de nombres actual. Si no, intentará llamar a la función correspondiente del núcleo.

Aquí tenemos la oportunidad de decirle al intérprete que evite este doble chequeo y ejecute directamente la función del núcleo.

Pruebe a agregar una barra invertida (\) antes de strlen y haga clic en “eval”:

PHP

 

En la pestaña VLD, ahora puede ver el opcode con solo una sentencia.

Debido a que se ha comunicado la ubicación exacta de la función, no necesita considerar ninguna alternativa.

Si no le gusta usar la barra invertida, puede importar la función como cualquier otra clase desde el espacio de nombres raíz:

PHP

 

Aprovechar Optimizaciones de Opcode Automáticas

También hay muchos automatismos internos del motor PHP para generar un opcode optimizado que evalúa expresiones estáticas anticipadamente. Esto fue una de las razones más importantes para la gran mejora de rendimiento de PHP desde la versión 7.x.

Being aware of these dynamics can really help you reduce resource consumption and cut costs. Once I did this research, I started using these tricks throughout the code.

Let me show you an example using PHP constants. Run this script into 3v4l:

PHP

 

Take a look at the first two lines of the PHP opcode:

FETCH_CONSTANT intenta obtener el valor de PHP_OS del espacio de nombres actual y buscará en el espacio de nombres global, ya que no existe aquí. Luego, la instrucción IS_IDENTICAL ejecuta la declaración IF.

Ahora intente agregar una barra invertida a una constante:

PHP

 

Como puede ver en las instrucciones de bytecode, el motor no necesita intentar cargar la constante porque ahora es claro dónde está, y como es un valor estático ya lo tiene en memoria.

Además, la declaración IF desapareció porque el otro lado de la expresión IS_IDENTICAL es una cadena estática (‘Linux’), de modo que la IF se puede marcar como “true” sin el overhead de interpretarla con cada ejecución.

Esta es la razón por la que tiene mucho poder para influir en el rendimiento final de su código PHP.

Conclusión

Espero que haya sido un tema interesante. Como mencioné al principio del artículo, estoy obteniendo muchos beneficios al usar esta táctica y, de hecho, también la usamos en nuestros paquetes.

Puede ver un ejemplo aquí de cómo usé estos consejos en nuestro paquete PHP para optimizar su rendimiento.

Si desea aprender más sobre los desafíos de construir una empresa dirigida por desarrolladores, puede seguir conmigo en LinkedIn.

Source:
https://dzone.com/articles/php-opcode-improve-application-performance