El problema fundamental que aborda este rediseño es la ineficiencia y los riesgos de privacidad inherentes a la recuperación de series temporales agregadas (como el historial de estrellas de un repositorio) a partir de un modelo de datos transaccional optimizado para el estado actual (quién ha dado una estrella). Originalmente, la API de GitHub exponía identidades individuales con marcas de tiempo, lo que permitía la recolección masiva de datos y generaba consultas de base de datos extremadamente costosas para repositorios populares, ya que el sistema debía procesar miles de registros individuales para cada solicitud paginada, incluso si solo se necesitaba un conteo agregado.
La necesidad de un historial de estrellas es un caso de uso común para los mantenedores de proyectos, quienes buscan entender la trayectoria de crecimiento de sus proyectos. La solución anterior, que implicaba paginar y descartar identidades, era una adaptación ineficiente. Este rediseño aborda la necesidad de una API que proporcione datos agregados de forma eficiente y segura, sin exponer información personal innecesaria, alineándose con los principios de privacidad por diseño y eficiencia en sistemas distribuidos a gran escala.
Arquitectura del Sistema
La arquitectura original de la API /repos/{owner}/{repo}/stargazers estaba diseñada para devolver una lista paginada de usuarios que habían dado una estrella a un repositorio, incluyendo la marca de tiempo de la estrella. El modelo de datos subyacente almacenaba el estado actual de las estrellas, lo que significaba que al quitar una estrella, el registro se eliminaba, no se mantenía como un evento histórico. Esto hacía que la reconstrucción de un historial de crecimiento implicara recuperar y procesar cada estrella individualmente.
La nueva arquitectura introduce un enfoque de filtrado por tiempo antes de la agregación. En lugar de procesar todas las estrellas actuales del repositorio, la API ahora traduce los parámetros de paginación (página y per_page) en un rango de fechas indexado (created_at). Las estrellas se filtran primero por este rango de fechas y luego se agrupan en conteos diarios. Este diseño permite que cada solicitud procese solo las semanas relevantes, en lugar de todas las estrellas del repositorio. La respuesta incluye hasta 30 semanas de datos, y el incremento del número de página (page) permite retroceder en el historial. Este cambio reduce la carga de la base de datos al limitar el conjunto de datos sobre el que se realiza la agregación, pasando de examinar potencialmente millones de filas a solo las relevantes para el rango de tiempo solicitado.
Flujo de Solicitud de Historial de Estrellas (Nuevo)
- 1 Cliente API Solicita historial de estrellas con `page` y `per_page`.
- 2 Servidor API Traduce `page`/`per_page` a un rango de `created_at` indexado.
- 3 Base de Datos Filtra estrellas por el rango de `created_at`.
- 4 Base de Datos Agrupa las estrellas filtradas en conteos diarios.
- 5 Base de Datos Devuelve hasta 30 semanas de conteos diarios.
- 6 Servidor API Formatea y envía la respuesta al cliente.
| Capa | Tecnología | Justificación |
|---|---|---|
| storage | Relational Database (e.g., MySQL) | Almacenar los registros de estrellas. La optimización se centró en cómo se consultaban estos datos. Índices sobre la columna `created_at` para permitir un filtrado eficiente por rango de tiempo. |
| compute | API Gateway / Backend Service | Procesar las solicitudes entrantes, aplicar lógica de negocio (traducción de paginación a rangos de fecha) y orquestar las consultas a la base de datos. |
Trade-offs
Ganancias
- ▲▲ Reducción de la carga de la base de datos
- ▲ Mejora de la privacidad del usuario
- ▲▲ Reducción del número de solicitudes API para el historial completo
- ▲ Mayor predictibilidad del rendimiento de la API
Costes
- ▲ Pérdida de granularidad de datos individuales (identidades)
- △ Limitación de la ventana de tiempo por solicitud (30 semanas)
- △ Semanas con un número excepcionalmente alto de estrellas aún pueden ser costosas
Fundamentos Teóricos
Este problema de eficiencia en la agregación de datos históricos a partir de un modelo de datos transaccional se relaciona directamente con los principios de los sistemas OLTP (Online Transaction Processing) frente a los sistemas OLAP (Online Analytical Processing). Las bases de datos OLTP están optimizadas para operaciones de lectura/escritura rápidas de registros individuales, mientras que las OLAP están diseñadas para consultas complejas y agregaciones sobre grandes volúmenes de datos. El diseño original de GitHub utilizaba una base de datos OLTP para un caso de uso que se asemejaba más a OLAP.
La solución implementada, que implica filtrar por un rango de tiempo indexado antes de la agregación, es una aplicación práctica del concepto de 'pushing down predicates' o 'predicate pushdown' en optimización de consultas de bases de datos. Este principio, bien establecido en la literatura de bases de datos relacionales desde los años 70 y 80 (por ejemplo, System R de IBM), sugiere que las operaciones de filtrado deben aplicarse lo antes posible en el plan de ejecución de una consulta para reducir la cantidad de datos que deben ser procesados por operaciones más costosas como la agregación o el ordenamiento. Al aplicar el filtro de created_at primero, se reduce el conjunto de datos sobre el cual se realiza el GROUP BY, mejorando significativamente el rendimiento.