Resumen : para aproximadamente 1 millón de usuarios activos y 150 millones de actividades almacenadas, lo mantengo simple:
- Use una base de datos relacional para almacenar actividades únicas (1 registro por actividad / "cosa que sucedió") Haga los registros lo más compactos posible. Estructura para que pueda tomar rápidamente un lote de actividades por ID de actividad o mediante el uso de un conjunto de ID de amigos con limitaciones de tiempo.
- Publique los ID de actividad en Redis siempre que se cree un registro de actividad, agregando el ID a una lista de "flujo de actividad" para cada usuario que sea un amigo / suscriptor que debería ver la actividad.
Consulte Redis para obtener el flujo de actividad de cualquier usuario y luego tome los datos relacionados de la base de datos según sea necesario. Vuelva a consultar la base de datos por tiempo si el usuario necesita navegar muy atrás en el tiempo (incluso si ofrece esto)
Utilizo una tabla simple de MySQL para tratar con unos 15 millones de actividades.
Se parece a esto:
id
user_id (int)
activity_type (tinyint)
source_id (int)
parent_id (int)
parent_type (tinyint)
time (datetime but a smaller type like int would be better)
activity_type
me dice el tipo de actividad, source_id
me dice el registro con el que está relacionada la actividad. Entonces, si el tipo de actividad significa "favorito agregado", entonces sé que source_id se refiere a la ID de un registro favorito.
Los parent_id
/ parent_type
son útiles para mi aplicación: me dicen con qué está relacionada la actividad. Si se favoreció un libro, entonces parent_id / parent_type me diría que la actividad se relaciona con un libro (tipo) con una clave primaria (id) dada
Indico (user_id, time)
y busco actividades que sean user_id IN (...friends...) AND time > some-cutoff-point
. Quitar la identificación y elegir un índice agrupado diferente podría ser una buena idea, no he experimentado con eso.
Bastante básico, pero funciona, es simple y es fácil trabajar con él a medida que cambian sus necesidades. Además, si no está usando MySQL, podría hacerlo mejor en cuanto a índice.
Para un acceso más rápido a las actividades más recientes, he estado experimentando con Redis . Redis almacena todos sus datos en la memoria, por lo que no puede poner todas sus actividades allí, pero podría almacenar lo suficiente para la mayoría de las pantallas comúnmente visitadas en su sitio. Los 100 más recientes para cada usuario o algo así. Con Redis en la mezcla, podría funcionar así:
- Crea tu registro de actividad MySQL
- Para cada amigo del usuario que creó la actividad, inserte el ID en su lista de actividades en Redis.
- Recorte cada lista a los últimos X elementos
Redis es rápido y ofrece una forma de canalizar comandos a través de una conexión, por lo que llevar una actividad a 1000 amigos lleva milisegundos.
Para una explicación más detallada de lo que estoy hablando, vea el ejemplo de Twitter de Redis: http://redis.io/topics/twitter-clone
Actualización de febrero de 2011 Tengo 50 millones de actividades activas en este momento y no he cambiado nada. Una cosa buena de hacer algo similar a esto es que usa filas pequeñas y compactas. Estoy planeando hacer algunos cambios que involucrarían muchas más actividades y más consultas de esas actividades y definitivamente usaré Redis para mantener las cosas rápidas. Estoy usando Redis en otras áreas y realmente funciona bien para ciertos tipos de problemas.
Actualización de julio de 2014 Hasta 700,000 usuarios activos mensuales. Durante los últimos dos años, he estado usando Redis (como se describe en la lista con viñetas) para almacenar los últimos 1000 ID de actividad para cada usuario. Por lo general, hay alrededor de 100 millones de registros de actividad en el sistema y todavía están almacenados en MySQL y siguen siendo el mismo diseño. Estos registros nos permiten salir con menos memoria de Redis, sirven como registro de datos de actividad y los usamos si los usuarios necesitan retroceder más en el tiempo para encontrar algo.
Esta no fue una solución inteligente o especialmente interesante, pero me ha servido bien.