Acelerando conectores PHP para Tarantool usando Async, Swoole y Parallel

Acelerando conectores PHP para Tarantool usando Async, Swoole y Parallel

En el ecosistema PHP actualmente hay dos conectores para trabajar con el servidor Tarantool: esta es la extensión oficial de PECL tarantool/tarantool-php, escrito en C, y tarantool-php/cliente, escrito en PHP. Soy el autor de este último.

En este artículo, me gustaría compartir los resultados de las pruebas de rendimiento de ambas bibliotecas y mostrar cómo, con cambios mínimos en el código, se puede lograr un aumento de rendimiento de 3 a 5 (¡En pruebas sintéticas!).

¿Qué probaremos?

Probaremos los mencionados anteriormente. síncrono Conectores que se ejecutan de forma asíncrona, en paralelo y de forma asíncrona en paralelo. 🙂 Tampoco queremos tocar el código de los propios conectores. Actualmente hay varias extensiones disponibles para lograr lo que deseas:

  • lana ― un marco asincrónico de alto rendimiento para PHP. Utilizado por gigantes de Internet como Alibaba y Baidu. Desde la versión 4.1.0 ha aparecido un método mágico. SwooleRuntime::enableCoroutine(), que le permite "convertir bibliotecas de red PHP síncronas en asíncronas con una línea de código".
  • Async era hasta hace poco una extensión muy prometedora para el trabajo asincrónico en PHP. ¿Por qué hasta hace poco? Desafortunadamente, por una razón que desconozco, el autor eliminó el repositorio y el destino futuro del proyecto no está claro. tendré que usarlo uno de tenedores. Al igual que Swoole, esta extensión le permite ponerse los pantalones fácilmente con un movimiento de muñeca para permitir la asincronía al reemplazar la implementación estándar de transmisiones TCP y TLS con sus versiones asincrónicas. Esto se hace a través de la opción “asíncrono.tcp = 1«.
  • Paralelo ― una extensión bastante nueva del conocido Joe Watkins, autor de bibliotecas como phpdbg, apcu, pthreads, pcov, uopz. La extensión proporciona una API para subprocesos múltiples en PHP y se posiciona como un reemplazo para pthreads. Una limitación importante de la biblioteca es que solo funciona con la versión ZTS (Zend Thread Safe) de PHP.

¿Cómo lo probaremos?

Lancemos una instancia de Tarantool con el registro de escritura anticipada deshabilitado (wal_mode = ninguno) y mayor búfer de red (lectura anticipada = 1 * 1024 * 1024). La primera opción eliminará el trabajo con el disco, la segunda permitirá leer más solicitudes del búfer del sistema operativo y así minimizar la cantidad de llamadas al sistema.

Para los puntos de referencia que trabajan con datos (inserción, eliminación, lectura, etc.), antes de iniciar el punto de referencia, se (re)creará un espacio memtx, en el que los valores del índice primario son creados por un generador de valores enteros ordenados. (secuencia).
El espacio DDL se ve así:

space = box.schema.space.create(config.space_name, {id = config.space_id, temporary = true})
space:create_index('primary', {type = 'tree', parts = {1, 'unsigned'}, sequence = true})
space:format({{name = 'id', type = 'unsigned'}, {name = 'name', type = 'string', is_nullable = false}})

Si es necesario, antes de ejecutar el benchmark, el espacio se llena con 10,000 tuplas del formulario

{id, "tuplе_<id>"}

Se accede a las tuplas mediante un valor de clave aleatoria.

El punto de referencia en sí es una única solicitud al servidor, que se ejecuta 10,000 veces (revoluciones), que, a su vez, se ejecutan en iteraciones. Las iteraciones se repiten hasta que todas las desviaciones de tiempo entre 5 iteraciones estén dentro de un error aceptable del 3%*. Después de esto, se toma el resultado promedio. Hay una pausa de 1 segundo entre iteraciones para evitar que el procesador se acelere. El recolector de basura de Lua se desactiva antes de cada iteración y se ve obligado a iniciarse una vez completada. El proceso PHP se inicia solo con las extensiones necesarias para el punto de referencia, con el almacenamiento en búfer de salida habilitado y el recolector de basura deshabilitado.

* El número de revoluciones, iteraciones y umbral de error se pueden cambiar en la configuración de referencia.

Entorno de prueba

Los resultados publicados a continuación se realizaron en una MacBookPro (2015), sistema operativo: Fedora 30 (versión del kernel 5.3.8-200.fc30.x86_64). Tarantool se inició en la ventana acoplable con el parámetro "--network host".

Versiones del paquete:

Tarantool: 2.3.0-115-g5ba5ed37e
Docker: 19.03.3, compilación a872fc2f86
PHP: 7.3.11 (cli) (construido: 22 de octubre de 2019 08:11:04)
tarantool/cliente: 0.6.0
rybakit/msgpack: 0.6.1
ext-tarantool: 0.3.2 (+ parche para 7.3)*
paquete de mensajes externo: 2.0.3
ext-asíncrono: 0.3.0-8c1da46
lana externa: 4.4.12
extra-paralelo: 1.1.3

* Desafortunadamente, el conector oficial no funciona con la versión PHP > 7.2. Para compilar y ejecutar la extensión en PHP 7.3, tuve que usar parche.

resultados

Modo sincrónico

El protocolo Tarantool utiliza un formato binario. Paquete de mensajes para serializar mensajes. En el conector PECL, la serialización está oculta en lo más profundo de la biblioteca y afecta el proceso de codificación desde el código del usuario. no es posible. Un conector PHP puro, por el contrario, ofrece la posibilidad de personalizar el proceso de codificación ampliando el codificador estándar o utilizando su propia implementación. Hay dos codificadores disponibles listos para usar, uno se basa en msgpack/msgpack-php (extensión oficial de MessagePack PECL), el otro está encendido rybakit/msgpack (en PHP puro).

Antes de comparar conectores, mediremos el rendimiento de los codificadores MessagePack para el conector PHP y en pruebas posteriores usaremos el que muestre el mejor resultado:

Acelerando conectores PHP para Tarantool usando Async, Swoole y Parallel
Aunque la versión PHP (Pure) es inferior en velocidad a la extensión PECL, en proyectos reales aún recomendaría usarla rybakit/msgpack, porque en la extensión oficial MessagePack la especificación de formato solo está implementada parcialmente (por ejemplo, no hay soporte para tipos de datos personalizados, sin los cuales no podrá usar Decimal, un nuevo tipo de datos introducido en Tarantool 2.3) y tiene una número de otros проблем (incluidos problemas de compatibilidad con PHP 7.4). Bueno, en general el proyecto parece abandonado.

Entonces, midamos el rendimiento de los conectores en modo síncrono:

Acelerando conectores PHP para Tarantool usando Async, Swoole y Parallel
Como se puede ver en el gráfico, el conector PECL (Tarantool) muestra un mejor rendimiento en comparación con el conector PHP (Cliente). Pero esto no es sorprendente, dado que este último, además de implementarse en un lenguaje más lento, en realidad hace más trabajo: se crea un nuevo objeto con cada llamada. SOLICITUD и Respuesta (en el caso de Select - también Criterios, y en el caso de Actualización/Upsert ― Operaciones), entidades separadas Conexión, Envasador и Manejador también añaden gastos generales. Obviamente, la flexibilidad tiene un precio. Sin embargo, en general, el intérprete de PHP muestra un buen rendimiento, aunque hay una diferencia, es insignificante y, quizás, será incluso menor cuando se usa la precarga en PHP 7.4, sin mencionar JIT en PHP 8.

Vamonos. Tarantool 2.0 agregó soporte para SQL. Intentemos realizar operaciones de selección, inserción, actualización y eliminación utilizando el protocolo SQL y comparemos los resultados con los equivalentes noSQL (binario):

Acelerando conectores PHP para Tarantool usando Async, Swoole y Parallel
Los resultados de SQL no son muy impresionantes (permítanme recordarles que todavía estamos probando el modo sincrónico). Sin embargo, no me enojaría por esto de antemano; el soporte para SQL todavía está en desarrollo activo (hace relativamente poco tiempo, por ejemplo, se agregó soporte declaraciones preparadas) y, a juzgar por la lista cuestiones, el motor SQL se someterá a una serie de optimizaciones en el futuro.

Asíncrono

Bueno, ahora veamos cómo la extensión Async puede ayudarnos a mejorar los resultados anteriores. Para escribir programas asincrónicos, la extensión proporciona una API basada en corrutinas, que usaremos. Descubrimos empíricamente que el número óptimo de corrutinas para nuestro entorno es 25:

Acelerando conectores PHP para Tarantool usando Async, Swoole y Parallel
"Distribuya" 10,000 operaciones en 25 corrutinas y vea qué sucede:

Acelerando conectores PHP para Tarantool usando Async, Swoole y Parallel
El número de operaciones por segundo aumentó más de 3 veces para tarantool-php/cliente!

Lamentablemente, el conector PECL no se inició con ext-async.

¿Qué pasa con SQL?

Acelerando conectores PHP para Tarantool usando Async, Swoole y Parallel
Como puede ver, en modo asíncrono la diferencia entre el protocolo binario y SQL quedó dentro del margen de error.

lana

Nuevamente descubrimos el número óptimo de corrutinas, esta vez para Swoole:
Acelerando conectores PHP para Tarantool usando Async, Swoole y Parallel
Detengámonos en 25. Repitamos el mismo truco que con la extensión Async: distribuya 10,000 operaciones entre 25 corrutinas. Además, añadiremos otra prueba en la que dividiremos todo el trabajo en 2 dos procesos (es decir, cada proceso realizará 5,000 operaciones en 25 corrutinas). Los procesos se crearán utilizando Proceso Swoole.

resultados:

Acelerando conectores PHP para Tarantool usando Async, Swoole y Parallel
Swole muestra un resultado ligeramente inferior en comparación con Async cuando se ejecuta en un proceso, pero con 2 procesos la imagen cambia dramáticamente (el número 2 no fue elegido por casualidad; en mi máquina, fueron 2 procesos los que mostraron el mejor resultado).

Por cierto, la extensión Async también tiene una API para trabajar con procesos, pero allí no noté ninguna diferencia al ejecutar puntos de referencia en uno o más procesos (es posible que haya cometido un error en alguna parte).

SQL vs protocolo binario:

Acelerando conectores PHP para Tarantool usando Async, Swoole y Parallel
Al igual que con Async, la diferencia entre operaciones binarias y SQL se elimina en el modo asíncrono.

Paralelo

Dado que la extensión Parallel no se trata de corrutinas, sino de subprocesos, midamos el número óptimo de subprocesos paralelos:

Acelerando conectores PHP para Tarantool usando Async, Swoole y Parallel
Es igual a 16 en mi máquina. Ejecutemos pruebas comparativas de conectores en 16 subprocesos paralelos:

Acelerando conectores PHP para Tarantool usando Async, Swoole y Parallel
Como puede ver, el resultado es incluso mejor que con las extensiones asincrónicas (sin contar Swoole ejecutándose en 2 procesos). Tenga en cuenta que para el conector PECL, las operaciones Actualizar y Upsert están vacías. Esto se debe al hecho de que estas operaciones fallaron con un error; no sé si fue culpa de ext-parallel, ext-tarantool o ambos.

Ahora comparemos el rendimiento de SQL:

Acelerando conectores PHP para Tarantool usando Async, Swoole y Parallel
¿Observa la similitud con el gráfico de conectores que se ejecutan sincrónicamente?

Juntos

Y finalmente, resumamos todos los resultados en un gráfico para ver el panorama general de las extensiones probadas. Agreguemos solo una nueva prueba al gráfico, que aún no hemos hecho: ejecutemos rutinas asíncronas en paralelo usando Parallel*. La idea de integrar las extensiones anteriores ya está discutido autores, pero no se llegó a un consenso, tendrá que hacerlo usted mismo.

* No fue posible lanzar corrutinas Swoole con Parallel; parece que estas extensiones son incompatibles.

Entonces, los resultados finales:

Acelerando conectores PHP para Tarantool usando Async, Swoole y Parallel

En lugar de una conclusión

En mi opinión, los resultados resultaron ser bastante dignos y, por alguna razón, estoy seguro de que este no es el límite. Si necesita decidir esto en un proyecto real exclusivamente para usted, solo diré que para mí fue un experimento interesante que le permite evaluar cuánto puede "exprimir" de un conector TCP síncrono con un mínimo esfuerzo. Si tiene ideas para mejorar los puntos de referencia, estaré encantado de considerar su solicitud de extracción. Todo el código con instrucciones de inicio y resultados se publica en un documento separado. repositorios.

Fuente: habr.com

Añadir un comentario