La optimización del backend de un servicio web siempre tiene como objetivo aumentar su rendimiento, cuyo aspecto clave es la aceleración del procesamiento de datos. Este proceso engloba muchas mejoras importantes encaminadas a hacer un uso más eficiente de los recursos y minimizar el tiempo de respuesta del sistema a las solicitudes. En este artículo, compartiré varias técnicas comprobadas que pueden acelerar significativamente su servicio web.
Muchos programadores, en su afán por hacer que una aplicación sea más rápida, se centran en optimizar el código y los algoritmos, elegir estructuras de datos adecuadas y operaciones óptimas. Por lo general, esto conduce a un mejor rendimiento, lo que a menudo mejora la velocidad del código optimizado, pero no sustancialmente.
El modesto aumento se debe a la velocidad inherente de las operaciones de la memoria y no deberían esperarse mejoras significativas a menos que el código original fuera muy ineficiente. Sin embargo, se debe priorizar la optimización de ciertas operaciones que consumen mucho tiempo, en particular las operaciones de entrada-salida.
Ya sea que se trabaje con archivos o interactúe con una base de datos, el tiempo de ejecución de estas tareas siempre es notable en comparación con las operaciones en memoria. No puede influir significativamente en el proceso de lectura de datos de un archivo, pero trabajar con la base de datos está bajo su control directo. Como desarrollador, tienes todas las capacidades para mejorar significativamente esta interacción.
Exploremos las siguientes estrategias para hacer que trabajar con su base de datos sea más eficiente, mejorando así significativamente el rendimiento de su servicio backend.
Hoy en día, es raro encontrar un servicio web backend que no utilice un sistema de mapeo relacional de objetos (ORM) para las interacciones con bases de datos. Si busca resultados de primer nivel, considere personalizar el ORM. Aunque los ORM son eficientes y no contienen errores, están diseñados para uso general. Esta amplia aplicabilidad a menudo se produce a expensas de un alto rendimiento.
Recuerde, los ORM se crean para ser compatibles con varias bases de datos, lo que podría significar perder ventajas específicas de la base de datos que ha seleccionado para su proyecto. Por ejemplo, como se ilustra aquí, aprovechar las características únicas de la base de datos puede mejorar significativamente la velocidad de las interacciones de la base de datos hasta 30 veces.
En lugar de depender únicamente de las consultas predeterminadas proporcionadas por un ORM, vale la pena crear sus propias consultas optimizadas. Las consultas personalizadas suelen funcionar mejor, especialmente en escenarios que involucran múltiples uniones.
A continuación se muestra un ejemplo sencillo en Spring JPA de cómo se puede mejorar el rendimiento mediante una consulta de unión:
@Transactional @Lock(LockModeType.PESSIMISTIC_READ) @Query(value = """ SELECT e FROM EmployeeRecord e LEFT JOIN DepartmentRecord d ON e.departmentId = d.id WHERE e.departmentId = :departmentId; """) List<EmployeeRecord> findEmployeesByDepartmentId(Integer departmentId);
El uso de clases complejas con objetos anidados y un sistema jerárquico profundo puede provocar una pérdida significativa en el rendimiento del sistema. A menudo no es necesario consultar la base de datos para toda la estructura anidada, especialmente cuando no todas las clases de la estructura se utilizan por completo.
Si bien la inicialización diferida ayuda a mitigar consultas innecesarias sobre objetos anidados, surgen desafíos cuando se necesita un objeto anidado, pero no todos sus datos. La solución a este dilema es emplear clases de datos planos.
Debe crear una clase diseñada para recopilar solo los datos de campo necesarios de la base de datos. Luego, con una consulta de base de datos personalizada que incorpore todas las uniones necesarias, seleccione solo aquellos campos que sean realmente necesarios.
Este enfoque no sólo mejorará la velocidad de las consultas sino que también reducirá el tráfico de datos desde la base de datos a su servicio.
Por ejemplo, utilizando NamedParameterJdbcTemplate de Spring JPA, se puede crear una clase plana con los campos necesarios:
public record EmployeeDepartment(Integer employeeId, String employeeName, String departmentName) { }
A continuación, utilizando un script sencillo, solo se recopilan los campos necesarios de las tablas principal y unida:
public List<EmployeeDepartment> employeeDepartments() { return template.query(""" SELECT employees.employee_id, employees.employee_name, departments.department_name FROM employees LEFT JOIN departments ON employees.department_id = departments.department_id; """, new MapSqlParameterSource(), employeeDepartmentMapper); }
Este enfoque reducirá significativamente la carga y hará que trabajar con datos sea mucho más eficiente.
El siguiente paso importante al trabajar con datos es definir los tipos de datos, siendo el tipo principal Hot Data.
Hot Data son los datos que el servicio procesa en tiempo real. Estos datos no se pueden almacenar en caché porque la relevancia de la respuesta del servicio web depende de su capacidad de respuesta inmediata. Por tanto, estos datos deben estar siempre actualizados. El servicio trabaja constantemente con Hot Data, registrando continuamente nuevos valores y extrayendo información para actualizaciones oportunas.
Para trabajar con Hot Data de la manera más eficiente posible, es crucial asegurarse de que la tabla en la que se almacena permanezca lo más compacta posible.
Mantenga la menor cantidad de columnas posible
Su tabla debe contener solo los campos que se utilizan activamente y almacenar todos los demás datos en una tabla separada, conservando solo el ID de la fila relevante. Este enfoque le permite acceder a todos los campos no utilizados cuando sea necesario, como para fines de generación de informes, sin sobrecargar la tabla principal con estos datos.
Mantenga la menor cantidad de filas posible
No almacene líneas que ya no necesite. En su lugar, muévalos a la tabla de archivo. Este enfoque permite que sus consultas encuentren las filas requeridas más rápido y al mismo tiempo conserva todos los datos históricos en un archivo. Automatizar este proceso con un trabajo simple minimiza su participación en el archivo de datos.
Mantener los índices actualizados
Recuerde crear índices. Los índices son cruciales para búsquedas rápidas de datos y, a menudo, los programadores los pasan por alto. Una indexación adecuada puede reducir significativamente los tiempos de búsqueda y el consumo de memoria de su base de datos. Asegúrese de crear índices tanto para las condiciones como para las columnas involucradas en las uniones, incluidos los índices compuestos.
Dejar de usar claves foráneas
El uso de claves externas supone una carga adicional en la base de datos para garantizar que la clave exista en la tabla asociada, lo que ralentiza las operaciones de datos, especialmente al escribir datos. No me malinterpretes; almacenar una clave externa en dicha tabla es posible y, a veces, incluso necesario, pero es mejor almacenar la clave simplemente como un valor simple.
Estos métodos simples le permitirán maximizar la eficiencia y utilidad de su mesa.
Los Warm Data son datos que se utilizan para preparar una respuesta, aunque su relevancia no tiene un impacto crítico. Los ejemplos incluyen descripciones de productos o una lista de accesorios disponibles. Mientras se almacenan dichos datos, ya no es necesario controlar de cerca el tamaño de la tabla. Sin embargo, es importante no pasar por alto la creación de índices en estas tablas, ya que se utilizan con frecuencia para uniones.
Caché de datos cálidos
Una ventaja clave de Warm Data es su capacidad de caché. Una vez realizada una solicitud, puede almacenar los datos en la memoria, lo que reduce la cantidad de llamadas a la base de datos y acelera los cálculos. Sin embargo, recuerde que el caché necesita actualizaciones periódicas.
Establezca un TTL (tiempo de vida) razonable
Configure el tiempo de vida (TTL) correcto para un funcionamiento adecuado. Por lo general, un TTL de alrededor de 90 segundos es suficiente, lo que se alinea con el tiempo promedio que tarda un usuario en tomar una decisión y realizar un pedido en un sitio web. Ajuste siempre el TTL según los requisitos de su servicio.
Utilice clases más pequeñas para almacenar datos cálidos
Para el almacenamiento en caché, utilice clases compactas. Incluso cuando se realizan consultas completas y se recopilan todos los datos de las tablas, evite almacenar todo en la memoria caché. Almacene sólo los datos necesarios. Este enfoque reduce significativamente el consumo de memoria de su servicio backend.
Configurar Warm Data no requerirá mucho tiempo y, en última instancia, logrará resultados tangibles.
Los datos fríos se refieren a datos que rara vez cambian pero que son necesarios para una respuesta. Ejemplos de dichos datos incluyen el nombre o la dirección de una tienda. Estos datos cambian muy raramente y tienen un impacto mínimo en la relevancia de la respuesta.
Almacenar en caché los datos fríos o almacenarlos en un archivo
Este tipo de datos siempre debe almacenarse en caché. Si no es posible guardar dichos datos en la memoria debido a su gran tamaño, considere descargarlos de la base de datos y almacenarlos en archivos en un formato listo para usar. Dividirlo en categorías y seleccionar solo las que se usan con más frecuencia ayudará a reducir el uso de memoria. Además, este enfoque mejora notablemente la velocidad en comparación con la recuperación de datos de la base de datos, ya que elimina la necesidad de trabajar a través de la red.
Actualizar caché al activar
El tiempo de vida (TTL) de dicha caché normalmente se establece en 24 horas. Para mantener la caché actualizada, debe programar una tarea o crear un activador que supervise los cambios en estos datos e inicie una actualización de la caché. Por ejemplo, si se llama a un punto final para publicar o actualizar datos fríos, se debe activar un disparador para actualizar el caché.
La gestión eficaz de Cold Data también es una parte importante para optimizar la eficiencia de la respuesta, mejorando así el rendimiento general del sistema.
En conclusión, optimizar el backend de un servicio web no depende únicamente de la optimización del código y el algoritmo. Mejorar las interacciones de la base de datos conducirá a una mayor eficiencia y rendimiento general del servicio. La implementación de técnicas como el ajuste de consultas ORM (mapeo relacional de objetos), el uso de clases de datos planos, la definición precisa de tipos de datos y la adopción de estrategias de almacenamiento en caché pueden mejorar significativamente el rendimiento del servicio. A través de estas medidas, el servicio web logrará en última instancia una mayor eficiencia, capacidad de respuesta y una funcionalidad general mejorada.
Pasos clave :