A pesar que el uso preferido de un sistema de transferencia P2P "torrent" es entre múltiples usuarios para acceder al máximo beneficio por el aumento de oferta, existe una aplicación que no es de la categoría. Me refiero a la descarga de archivos de respaldo de servicios de hosting web, estos archivos pueden pesar de unos cientos de mega bytes hasta cuantiosos gigabytes y aunque no pensamos que estos respaldos deban ser compartidos por muchos usuarios, si podemos establecer algunos servidores como NAS que cuentan con clientes torrent integrado que puedan recuperar estos datos a través del sistema.
El sistema adecuado requiere una actualización de la plataforma Cpanel. Una vez que escojas si se requiere un respaldo total, de casillas de correos, o de raíz web, esta creará un archivo torrent asociado al archivo tar.gz -rar más adelante- que contiene dicho respaldo; utilizará una semilla web asociada al respaldo de tracker privado, esta permanecerá viva mientras se mantenga en el servidor de hosting, es de esperar que una vez completado exista una web seed esperando conexiones y una semilla torrent disponible si se requiere descargar desde otro equipo por internet y no directamente del NAS que fue el peer original.
¿Pero este beneficio es solo para un grupo específico de usuarios? No, el sistema de descarga entre servidor hosting y cliente es bastante especial, existen restricciones de tráfico y velocidades de transferencias que suelen ser mucho más bajas que las que acostumbramos cuando accedemos a un servicio de video a demanda, un buscador, o un portal de noticias. Las velocidades promedio en este momento -para el respaldo de fin de año- oscilan entre los 10 y 50 KBps lo que es increíblemente bajo incluso para mi conexión.
El sistema de descarga de la plataforma es web, por lo que utiliza el sistema incorporado en el navegador y parte de las funcionalidades del sistema operativo. De utilizar el sistema torrent, el archivo siempre es reanudable, podemos ver el progreso por paquete y resolver problemas asociados a su contenido.
Imaginemos que implementamos una adaptación de rarlabs para poder seleccionar el contenido del respaldo que queremos descargar, tal como seleccionamos los archivos de un torrent tradicional. Vendrá por defecto seleccionado un paquete inicial que es requerido para poder leer el archivo como corresponde, y luego podremos seleccionar los archivos y carpetas deseadas, estas se descargan del respaldo total. Al abrir el archivo resultante se verá un aviso que indica que archivo no está completo, marcado en gris desvanecido aquellas carpetas y archivos no incluidos en la presente versión y permitiéndonos descomprimir aquellos que nos interesaron en un principio.
Las aplicaciones son realmente buenas, sobre todo en respaldos de gran tamaño en que buscamos solo una casilla de correo en particular, o sólo una carpeta de las miles que contiene el respaldo. Sin entrar el todos esos archivos que resultan dañados y que no nos dejan otra alternativa que volver a iniciar el proceso nuevamente.
El trabajo con torrent permite no sólo esto, también nos deja la puerta abierta para la mantención de nuestro trabajo una vez recuperado el respaldo. Podemos dejar copia en servidor y trabajar de la forma señalada con los equipos clientes rescatando directamente cuando sea necesario. Siempre será bien visto considerar que esta hipotética versión de Cpanel incorpore la opción de codificar el respaldo mediante contraseña y no dejarlo abierto como lo hace ahora.
Pablo Rodríguez R.
22-12-2024
Transformándolo a MySQL
Se realizaron pruebas de operación sobre búsquedas de publicaciones por código, los resultados fueron 135, 160 y 147 para un promedio de 147ms de respuesta sobre la base, se piensa que a medida que aumente su tamaño el tiempo de respuesta subirá sobre una relación lineal. Vistos estos resultados, me interesó poder aplicar la metodología considerando que los 70ms máximos reportados implicarían una mejora de un 110% en eficiencia.
El resultado no fue satisfactorio, el llamado al procedimiento no tarda ni cerca de los 70ms de PostgreSQL, se reportan los siguientes resultados 297, 282 y 281 para un promedio de 287ms por los mismos registros. Bajo esta premisa, aplicar la metodología en mySQL no es correcto y aunque en PostgreSQL también existe una mejora de eficiencia solo ronda el 10%. Parece mucho trabajo migrar todo a PostgreSQL para aplicar la metodología por lo que se publicó el problema en StackOverflow para saber si alguien puede orientarme en encontrar un método más eficiente en convertir el código.
Revisando los índices de la tabla [show indexes from posts;] me encontré que tengo tres, la clave primaria que permite encontrar los registros únicos y seriados, la fecha que debe ser única y el postcontrol -también única- que permite identificar si existe un problema de duplicidad con los archivos que contienen las publicaciones. Decidí agregar un nuevo índice asociado a la columna "codigo" que facilite la búsqueda de forma similar a lo planteado, aunque esta debe ser única, como existen cientas de publicaciones que no tienen código -incorporación tardía- no puede ser identificada como tal. Se creó un índice BTREE frente a hash no único de igual forma.
Los resultados fueron instantáneos, las mismas consultas tardaron 1.6, 2.4 y 1.1, promedio 1.7ms por decimales. Queda claro que el sistema de índice incorporado en MySQL es eficiente y el motor utiliza de forma adecuada árboles para econtrar el camino más corto al registro buscado. Sólo basta con saber configurarlo y aplicarlo.
El cambio en el funcionamiento ya esta operativo para el uso de "single view". sv.php?cod=mySQL20241222
Pablo Rodríguez R.
21-12-2024
Nuevas Pruebas en PostgreSQL
Decidido por buscarle explicación y no contento con el resultado final generé un proceso almacenado que por devolución terminó siendo una nueva función. Esta función de nombre get_post(@_userinput) realiza el mismo procedimiento relatado en la publicación anterior, es más, el video muestra una doble ejecución del proceso donde se puede ver el rendimiento de la solución implementada y que el problema de retardo se genera sólo cuando su llamada es en una única sentencia.
La función elaborada realiza la consulta en impresionantes 70ms.
Pablo Rodríguez R.
21-12-2024
Aplicación de lo Analizado
Estuve un par de horas revisando si podía aplicar esta metodología a algo del diario y creo que para la consulta de enlace compartido puede ser muy útil. Se analizó que cuando enviamos un enlace por mensajería usamos la rutina codificada en PHP dentro del archivo sv.php mediante una variable GET de nombre cod, cuando llamamos por ejemplo a esta publicación [sv.php?cod=apindex20241221] la rutina consulta por la fila donde la columna código se iguala a la variable entregada por URL.
Realicé algunas pruebas en Postgre y encontré que una consulta a la tabla de publicaciones por índice tarda entre 60 y 120 milisegundos, pero no tenemos el id. Cree una vista de nombre select_post que me integra todas las publicaciones que tienen código, ordenadas alfabéticamente y sus respectivos id de la tabla de publicaciones, le adicioné un id para poder usar el concepto de máximo visto. El uso de COALESCE tiene el único fin de discriminar aquellas filas que no tienen contenido; posts como se ha de suponer es el nombre de la tabla.
Llevamos 1170 publicaciones desde que comencé con los códigos, esta consulta "SELECT * FROM select_post" tarda 352 milisegundos la primera vez y baja a 113 en segunda instancia. A partir de esta vista se creó una vista secundaria de nombre índice, esta se encarga de generar un índice al instante de los 1170 registros en sistema codificados, la tabla contiene un ID, el índice, y el fin de registro asociado a ese segmento de índice. Solo consta de 291 filas de registros debido a que no existe un registro para cada posible combinatoria de dos caracteres y que los registros repetidos se agrupan. Si no se encuentra la buscada diremos inmediatamente que no existe. Su consulta tarda menos de 200 milisegundos.
Tenemos ya las dos tablas -vistas- que utilizaremos sobre la tabla maestra de publicaciones, solo nos falta la función que recuperará ese índice para que la búsqueda sea directa y no tengamos que buscar en los miles de registros incluso pasando por lo más antiguos vacíos. Creamos la función "what_id(varchar)" donde varchar representa el código del vínculo o código a buscar.
La función recorta los primeros dos caracteres y los busca en el índice, obtiene el id asociado en aux y solicita los registros fin para establecer el rango, luego consulta por el código de una tabla segmentada entre el inicio y fin de la vista select_post consultamos por el id asociado a la tabla maestra que se encuentra en ella (idposts) donde -y esta vez si- el código ingresado en la función sea igual al código de la columna. La comparación puede no ser necesaria si no existe índice, o puede sólo requerir unas cuantas filas porque se realiza sobre el rango acotado. Finalmente devolvemos el código que bien podría haber sido un integer.
Pese a lo que uno puede pensar sobre el uso de tantas consultas y tiempos asociados, la función es extremadamente rápida, toma menos de 100 milisegundos con un promedio de solo 50 rescatar el id de un código. Su ejecución se realiza mediante un SELECT what_id(@cod); donde @cod es el código de la URL. Si toma 50 milisegundos obtener el código de esta forma, y la consulta con código, alrededor de 90 en generar el resultado a partir de él, es lógico pensar que el tiempo de respuesta de esta aproximación debe rondar los 150 milisegundos.
Para mi sorpresa y a pesar que todo lo expuesto es cierto, la consulta SELECT * FROM posts WHERE idposts=what_id(@cod); tarda entre 16 y 19 segundos en retornar la fila correspondiente.
Aún no he resuelto a que se debe ello.
Pablo Rodríguez R.
20-12-2024
Consideraciones sobre Función en PostgreSQL
Una alternativa posterior es utilizar una función que nos entregue el resultado que buscamos, un procedimiento almacenado puede encargarse de tomar la entrada del usuario ya encriptada y seccionarla a los primeros dos dígitos, buscar en la tabla índice los valores correspondientes que en nuestro ejemplo da como resultado 1 y 3 -esto también puede ser una función que retorna un vector de dos posiciones donde res[0] es el inicio y res[1] es el fin. Podemos incluso adaptar el resultado para que la variable en res[0] ya esté aumentada en una posición evitando el su trabajo posterior.
Una vez que tenemos esas variables, realizaremos una segunda función que llamaremos desde el mismo procedimiento. De nombre isuser(userinput), la función requiere como entrada el hash del usuario para verificación.
Esta función se compone de una variable booleana CRC32 la que resulta de la consulta de contar el número de resultados que se validan al preguntar otras dos consultas, leyendo de dentro hacia afuera, preguntamos por la tabla ordenada y serializada, a este resultado le pedimos los usuarios que se encuentre dentro del rango.
De tener la función y variables, deberemos incorporar las variables ini y fin en la entrada como corresponde.
isuser(userinput char[], ini int, fin int)
Para llamar la función requeriremos de los tres parámetros que contamos en el procedimiento almacenado, y remplazamos el 2 y 3 por las variables ini y fin.
Continuando con nuestra simplificación, de la ejecución de la consulta podemos rescatar que sólo tardó 116 milisegundos en buscar el usuario, tendremos que popular una tabla con muchos más valores para poder sacar una relación de eficiencia. Mientras menos campos, el retorno debería ser más rápido, como no necesitamos el campo password para este cometido, podemos prescindir de él si así se desea.