
En el ecosistema PHP, actualmente hay dos conectores para el servidor Tarantool: la extensi贸n oficial PECL
tarantool / tarantool-php escrita en C, y
tarantool-php / client 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 puede lograr una mejora del rendimiento 3x-5x (隆
en pruebas sint茅ticas! ) Con cambios m铆nimos en el c贸digo.
驴Qu茅 vamos a probar?
Vamos a probar los conectores s铆ncronos mencionados anteriormente lanzados de forma as铆ncrona, en paralelo y as铆ncronamente en paralelo. Adem谩s, no queremos cambios para el c贸digo fuente de los conectores. En este momento hay varias extensiones disponibles que pueden hacer el trabajo:
- Swoole , un marco as铆ncrono de alto rendimiento para PHP. Utilizado por gigantes de Internet como Alibaba y Baidu. Desde la versi贸n 4.1.0, ha aparecido el incre铆ble gancho de tiempo de ejecuci贸n Swoole \ Runtime :: enableCoroutine () , que permite "transformar bibliotecas de red PHP s铆ncronas en bibliotecas de rutina utilizando una sola l铆nea de c贸digo".
- Async, una extensi贸n muy prometedora para el trabajo asincr贸nico en PHP hasta hace poco. 驴Por qu茅 hasta hace poco? Desafortunadamente, por razones que no s茅, el autor elimin贸 el repositorio y el futuro del proyecto es cuestionable. Usar茅 uno de los tenedores. Al igual que Swoole, esta extensi贸n facilita la activaci贸n del modo as铆ncrono al reemplazar las implementaciones de flujo predeterminadas de PHP con su contraparte as铆ncrona. Esto se hace a trav茅s de la opci贸n " async.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 multihilo para 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 vamos a probar?
Ejecutaremos una instancia de Tarantool con el registro de escritura anticipada deshabilitado (
wal_mode = none ) y un b煤fer de red extendido (
readahead = 1 * 1024 * 1024 ). La primera opci贸n evitar谩 las operaciones de E / S en la unidad de disco, la segunda permitir谩 leer m谩s solicitudes del b煤fer del sistema operativo y, por lo tanto, minimizar谩 la cantidad de llamadas al sistema.
Para los puntos de referencia que funcionan con datos (inserci贸n, eliminaci贸n, lectura, etc.), se crear谩 un (re) espacio de memoria antes de que comience el punto de referencia, y el generador de secuencias crear谩 los valores de 铆ndice iniciales para este espacio.
El DDL del espacio es el siguiente:
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 comenzar el punto de referencia, el espacio se llena con 10,000 tuplas de la siguiente forma:
{id, 'tuple_' .. id}
Se accede a las tuplas utilizando el valor de clave aleatorio.
El punto de referencia es una solicitud 煤nica 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 del margen de error del 3% *. Despu茅s de eso, se toma el resultado promedio. Entre iteraciones, hay una pausa de 1 segundo para evitar que la CPU se acelere. El recolector de basura Lua se deshabilita antes de cada iteraci贸n y se ve obligado a comenzar despu茅s de que finaliza la iteraci贸n. El proceso PHP se inicia solo con las extensiones requeridas para el punto de referencia, con el buffer de salida habilitado y el recolector de basura deshabilitado.
* El n煤mero de revoluciones, iteraciones y umbral de error se puede modificar en la configuraci贸n de referencia.Entorno de prueba
Los resultados publicados a continuaci贸n se realizaron en MacBookPro (mediados de 2015) con Fedora 30 (versi贸n del n煤cleo 5.3.8-200.fc30.x86_64). Tarantool se lanz贸 en Docker con la
configuraci贸n "
--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 (parcheado) *
ext-msgpack: 2.0.3
ext-async: 0.3.0-8c1da46
ext-swoole: 4.4.12
paralelo paralelo: 1.1.3
* Desafortunadamente, el conector oficial no funciona con PHP> 7.2. Para compilar y ejecutar la extensi贸n en PHP 7.3, tuve que usar un parche .Resultados
Sincronizaci贸n (predeterminada)
El protocolo Tarantool utiliza el formato binario
MessagePack para serializar mensajes. En el conector PECL, la serializaci贸n est谩 oculta en el fondo de la biblioteca, por
lo que parece imposible afectar el proceso de codificaci贸n del c贸digo de usuario. Por el contrario, el conector PHP puro brinda la capacidad de personalizar el proceso de codificaci贸n, ya sea extendiendo uno de los codificadores est谩ndar o utilizando su propia implementaci贸n. Hay dos codificadores disponibles: uno est谩 basado en
msgpack / msgpack-php (la extensi贸n oficial de MessagePack PECL) y el otro est谩 basado en
rybakit / msgpack (PHP puro).
Antes de proceder a comparar los conectores, midamos el rendimiento de los codificadores de MessagePack para el conector PHP, de modo que usemos el mejor desempe帽o m谩s adelante en nuestras pruebas:
Aunque la versi贸n PHP (Pure) no es tan r谩pida como la extensi贸n PECL, todav铆a recomendar铆a usar
rybakit / msgpack en proyectos reales, porque la extensi贸n PECL oficial implementa la especificaci贸n MessagePack solo parcialmente (por ejemplo, no hay soporte para tipos de datos personalizados, y sin 茅l no puede usar Decimal, un nuevo tipo de datos introducido en Tarantool 2.3) y tiene una serie de otros
problemas (incluidos problemas de compatibilidad con PHP 7.4). Y el proyecto parece abandonado en general.
Entonces, midamos el rendimiento de los conectores en el modo s铆ncrono:
Como puede ver en el gr谩fico, el conector PECL (Tarantool) funciona mejor que el conector PHP (Cliente). Eso no es sorprendente, considerando que este 煤ltimo, adem谩s de implementarse en un lenguaje m谩s lento, en realidad hace m谩s trabajo: se crea un nuevo objeto de
Solicitud y
Respuesta con cada solicitud (en el caso de Seleccionar tambi茅n hay
Criterios , y en el caso de Actualizaci贸n / Upsert hay
operaciones ),
Connection ,
Packer y
Handler tambi茅n agregan algo de sobrecarga. No hace falta decir que una mayor flexibilidad tiene un costo. Sin embargo, el int茅rprete PHP muestra un buen rendimiento en general. Aunque hay una diferencia, es insignificante y puede ser a煤n menos con el uso de precarga en PHP 7.4, sin mencionar JIT en PHP 8.
Continuando ahora. Tarantool 2.0 introdujo el soporte SQL. Intentemos realizar operaciones de Seleccionar, Insertar, Actualizar y Eliminar utilizando el protocolo SQL y comparar resultados con equivalentes noSQL (binarios):
Los resultados de SQL no son tan impresionantes (perm铆tanme recordarles que todav铆a estamos probando el modo sincr贸nico). Sin embargo, no me molestar铆a antes: el soporte de SQL todav铆a est谩 en desarrollo activo (por ejemplo, el soporte para
declaraciones preparadas se ha agregado no hace mucho tiempo) y, de acuerdo con la lista de
problemas , el motor SQL obtenga una serie de optimizaciones en el futuro.
As铆ncrono
Bueno, veamos ahora c贸mo la extensi贸n Async puede ayudarnos a mejorar los resultados anteriores. Para la programaci贸n asincr贸nica, la extensi贸n proporciona una API basada en corutinas, que vamos a utilizar aqu铆. Primero, como descubrimos a trav茅s de las pruebas, el n煤mero 贸ptimo de corutinas para nuestro entorno es 25:
Luego, distribuimos 10,000 operaciones en 25 corutinas y verificamos el resultado:
隆El n煤mero de operaciones por segundo ha crecido m谩s de 3 veces para el conector PHP! Lamentablemente, el conector PECL no se pudo iniciar con ext-async.
驴Y qu茅 hay de SQL?
Como puede ver, en el modo as铆ncrono, la diferencia entre el protocolo binario y SQL cae dentro del margen de error.
Swoole
Nuevamente, determinemos el n煤mero 贸ptimo de corutinas, esta vez para Swoole:
Tomemos 25. Ahora, repitiendo el mismo truco que con la extensi贸n Async: distribuya 10,000 operaciones entre 25 corutinas. Adem谩s de eso, agreguemos una prueba m谩s, donde dividimos todo en dos procesos (es decir, cada proceso realizar谩 5.000 operaciones en 25 corutinas). Los procesos se crear谩n con la ayuda de
Swoole \ Process .
Resultados:
Swoole muestra un rendimiento ligeramente inferior en comparaci贸n con Async cuando se ejecuta en un proceso, pero con 2 procesos, la imagen cambia dr谩sticamente (2 no se elige por accidente, en mi m谩quina este n煤mero exacto de procesos mostr贸 el mejor resultado).
Por cierto, tambi茅n hay una API para trabajar con procesos en la extensi贸n Async, pero no not茅 ninguna diferencia entre lanzar puntos de referencia en un solo proceso o en varios procesos (aunque es posible que haya cometido algunos errores).
SQL versus protocolo binario:
Al igual que con Async, la diferencia entre las operaciones binarias y SQL se nivela en el modo asincr贸nico.
Paralelo
Como la extensi贸n paralela se trata de hilos, no de corutinas, debemos medir el n煤mero 贸ptimo de hilos paralelos:
Son las 16 en mi m谩quina. Ahora comparemos los conectores en 16 hilos paralelos:
Como puede ver, el resultado es incluso mejor que con extensiones asincr贸nicas (excepto Swoole lanzado con 2 procesos). Tenga en cuenta que para el conector PECL, las operaciones de Actualizaci贸n y Upsert no tienen barra. Esto se debe a que esas operaciones se bloquearon con un error, y no estoy seguro de cu谩l es la culpa: ext-parallel o ext-tarantool, o ambos.
Ahora agreguemos el rendimiento de SQL a la comparaci贸n:
驴Has notado similitudes con el gr谩fico para los conectores lanzados sincr贸nicamente?
Todo en uno
Finalmente, combinemos todos los resultados en un gr谩fico para ver la imagen completa de las extensiones bajo prueba. Vamos a agregar solo una nueva prueba al gr谩fico, lo que a煤n no hemos hecho: lanzar corrutinas Async en paralelo usando Parallel *. La idea de integrar las extensiones antes mencionadas ya ha sido
discutida por los autores, pero no se ha alcanzado un consenso, por lo que tendremos que hacerlo nosotros mismos.
* No pude iniciar las corutinas de Swoole con Paralelo; Parece que estas extensiones son incompatibles.Ahora, los resultados finales:
Conclusi贸n
En mi opini贸n, los resultados son bastante decentes, 隆pero hay algo que me hace creer que a煤n no hemos llegado! Si tiene alguna idea sobre c贸mo mejorar los puntos de referencia, me complacer谩 revisar su solicitud de extracci贸n. Todo el c贸digo con instrucciones de lanzamiento y resultados se publica en un
repositorio dedicado.
Dejando que usted decida si necesitar铆a esto en un proyecto real, solo dir铆a que fue un experimento emocionante que me permiti贸 estimar cu谩nto se podr铆a hacer con un conector TCP s铆ncrono con un m铆nimo esfuerzo.