Diseño de sistema de un news feed: fan-out en escritura o en lectura

Cómo diseñar un news feed: fan-out en escritura o en lectura, el híbrido de los grandes feeds, cachés de feed, ranking, paginación y un diagrama de arquitectura.

· Fundador y desarrollador

Publicado el

Diseño de sistema de un news feed: fan-out en escritura o en lectura

El feed de inicio es la página más leída de cualquier producto social y una de las más caras de construir. Cada usuario sigue a cientos de cuentas, cada cuenta publica a su ritmo y el feed tiene que volver en menos de unos cientos de milisegundos, ordenado, cada vez que alguien abre la app.

La pregunta central de diseño tiene dos respuestas clásicas, fan-out en escritura y fan-out en lectura, y todo feed grande acaba usando una mezcla de ambas. Este artículo las compara con números, muestra el híbrido y termina con un diagrama de las rutas completas de lectura y escritura.

Requisitos

  • Un usuario ve las publicaciones recientes de las cuentas que sigue, ordenadas por relevancia o por tiempo.
  • Abrir el feed tarda bastante menos de un segundo en el percentil 99.
  • Una publicación nueva aparece en los feeds de los seguidores en pocos segundos.
  • Scroll infinito sin duplicados ni huecos.
  • Sigue funcionando cuando una cuenta tiene decenas de millones de seguidores.

Dominan las lecturas. En 2013, Twitter servía unas 300 000 lecturas de timeline por segundo frente a unas 6000 escrituras de tweets por segundo, según este análisis de su arquitectura. Diseña primero para las lecturas.

Cuentas rápidas

Supuesto Valor
Usuarios activos diarios 10 millones
Aperturas del feed por usuario al día 10, unas 1160 lecturas/s de media
Publicaciones nuevas al día 1 millón, unas 12 publicaciones/s
Seguidores medios por autor 200, unas 2300 escrituras de fan-out/s
Tamaño del feed en caché 800 ID de publicación de 8 bytes, unos 64 GB para todos los usuarios

Las medias parecen inofensivas. Los casos extremos no: un autor con 20 millones de seguidores genera 20 millones de escrituras de fan-out con una sola publicación, una décima parte del trabajo diario de fan-out de todos los demás. Ese caso extremo es lo que tiene que resolver el diseño que sigue.

Fan-out en escritura (push)

Cuando alguien publica, un trabajo en segundo plano busca a sus seguidores e inserta el ID de la publicación al principio del feed en caché de cada uno. Leer el feed es entonces una sola búsqueda: tomar los ID más recientes de tu propia lista y obtener las publicaciones.

  • Fortaleza: las lecturas son rápidas y predecibles.
  • Coste: una publicación genera tantas escrituras como seguidores tiene el autor. Una cuenta con 30 millones de seguidores convierte una publicación en 30 millones de escrituras en caché, y esos seguidores la ven tarde. El mismo análisis describe publicaciones de las cuentas más grandes que tardaban minutos en llegar a todos sus seguidores.
  • Desperdicio: escribes en los feeds de usuarios que no abrirán la app esta semana.

Mantén corto cada feed en caché. Twitter limitaba entonces las timelines de inicio a 800 entradas en Redis; las publicaciones más antiguas salen de la base de datos cuando alguien hace scroll hasta allí.

Fan-out en lectura (pull)

No hagas nada cuando alguien publica. Cuando un usuario abre el feed, obtén las publicaciones recientes de todas las cuentas que sigue, combínalas y ordénalas.

  • Fortaleza: las escrituras son baratas y las cuentas grandes no cuestan nada extra.
  • Coste: cada lectura del feed toca a cientos de autores. A 300 000 lecturas por segundo, son muchísimas consultas para un trabajo que en su mayor parte se repite.

El híbrido

La mayoría de los feeds grandes combinan los dos:

  • Empuja las publicaciones de las cuentas normales a los feeds en caché de sus seguidores.
  • Sáltate el fan-out para las cuentas que superan un umbral de seguidores y obtén sus publicaciones recientes al leer.
  • Al leer, combina el feed en caché con las publicaciones obtenidas y después ordena.

El umbral es un parámetro que se ajusta, no una ley. Colócalo donde el coste de las escrituras de fan-out empiece a superar al de las lecturas extra, y revísalo cuando cambie la distribución de seguidores. Los usuarios que no siguen a ninguna cuenta grande nunca pagan la ruta pull.

Ranking

Un feed cronológico ordena por tiempo. Un feed con ranking funciona en tres pasos: reunir publicaciones candidatas (la lista combinada de antes, más recomendaciones si las tienes), puntuar cada candidata con señales como la recencia, la frecuencia con que el usuario interactúa con el autor y la interacción con la publicación, y luego filtrar (cuentas bloqueadas, publicaciones ya vistas, casi duplicados).

Mantén el ranking fuera de la ruta de fan-out. El fan-out guarda candidatas; el ranking ocurre al leer, con las señales más recientes. Así, un cambio en el modelo de ranking no obliga a rellenar de nuevo los feeds en caché.

Borrados, bloqueos y cuentas privadas

Los feeds guardan ID, así que borrar una publicación es una sola escritura en el almacén de publicaciones; el servicio de feed descarta los ID que ya no se resuelven. Los bloqueos y las cuentas que pasan a privadas necesitan el mismo filtro al leer, porque quitar un ID de millones de feeds en caché es lento y fácil de hacer mal.

Paginación

Nunca pagines un feed con offsets. Llegan publicaciones nuevas arriba mientras el usuario hace scroll, así que la «página 2» se desplaza y muestra duplicados. Devuelve un cursor que codifique la posición, como el ID o la puntuación del último elemento servido, y pide «los elementos después de este cursor». En los feeds con ranking, guarda durante un rato la lista ordenada de la sesión para que las páginas siguientes sean coherentes con la primera.

El diagrama de arquitectura

Un servicio de publicaciones las guarda y publica eventos. Los workers de fan-out leen el grafo social y comprueban si el autor supera el millón de seguidores. Si no, empujan el ID a las cachés de feed de los seguidores; si sí, se lee al consultar. Un servicio de feed combina y ordena.

13 componentes · 13 conexiones

Abrir en Archboard
Contenido del diagrama
  • User
  • Post service
  • Posts store
  • Post events
  • Fan-out workers
  • Social graph
  • Author over 1M followers?
  • Feed cache
  • Pulled at read time
  • Feed service
  • Ranking
  • Media CDN
  • POST /posts
  • post.created
  • followers
  • no: push post ID
  • yes
  • GET /feed
  • cached timeline
  • big accounts
  • images and video
Un news feed híbrido. Las publicaciones de la mayoría de los autores se empujan al feed en caché de cada seguidor; las de cuentas con muchísimos seguidores se leen en el momento de la lectura, se combinan con el feed en caché y se ordenan antes de devolver la página.

Cómo leerlo:

  • Ruta de escritura (arriba): el servicio de publicaciones guarda la publicación y publica un evento. Los workers de fan-out leen el grafo social y comprueban el número de seguidores del autor.
  • La decisión: para la mayoría de los autores, los workers empujan el ID de la publicación a la caché de feed de cada seguidor. Para las cuentas por encima del umbral no se empuja nada; sus publicaciones se obtienen al leer.
  • Ruta de lectura (abajo): el servicio de feed lee el feed en caché del usuario y las publicaciones recientes de las cuentas grandes desde el almacén de publicaciones, los combina y los envía al ranking.
  • Los archivos multimedia pasan por un CDN y nunca por el servicio de feed.
  • El bloque Markdown mantiene las reglas prácticas junto al diseño.

Qué poner en el diagrama

  • Las dos rutas, bien separadas. Escrituras y lecturas tienen problemas de escala distintos.
  • El umbral de fan-out. Escribe el número en la decisión, aunque cambie más adelante.
  • Qué se guarda dónde. Las cachés de feed guardan ID de publicaciones, no publicaciones; el contenido está en el almacén de publicaciones.
  • Dónde ocurre el ranking. Quien lo lea debe ver que se ejecuta al leer.

La caché que está en el centro de este diseño merece su propio diagrama; consulta el artículo sobre estrategias de caché. El artículo sobre arquitectura orientada a eventos cubre el lado de eventos y consumidores, y el ejemplo de diagrama de diseño de sistemas aplica las mismas convenciones a otro sistema.

Constrúyelo en Archboard

  1. Inicia sesión con Google o GitHub y crea un diagrama.
  2. Añade una Persona del pack Modelo C4 y después nodos Contenedor para el servicio de publicaciones, los workers de fan-out, el servicio de feed y el ranking.
  3. Añade nodos Base de datos del pack Modelo C4 para el almacén de publicaciones y el grafo social, Kafka y Redis del pack Datos para los eventos de publicación y las cachés de feed, y un CDN del pack Nube.
  4. Añade una Decisión y un Inicio / Fin del pack Diagrama de flujo para el umbral de seguidores.
  5. Dibuja la ruta de escritura arriba y la de lectura debajo, y añade un bloque Markdown del pack Básico con tus reglas prácticas.

El ejemplo usa 13 nodos de diagrama, dentro del plan Free.

Preguntas frecuentes

¿Qué es mejor, fan-out en escritura o en lectura? Ninguno por sí solo. El fan-out en escritura da lecturas rápidas pero explota con cuentas de muchísimos seguidores; el fan-out en lectura es barato al escribir pero lento al leer. Los feeds grandes usan un híbrido.

¿Qué debe guardar la caché de feed? ID de publicaciones, la más reciente primero, con un límite de unos cientos por usuario. Obtén el contenido aparte, para que las ediciones y los borrados no obliguen a reescribir todos los feeds.

¿Cómo gestiono la publicación de una celebridad? Sáltate el fan-out para las cuentas que superan un umbral de seguidores y obtén sus publicaciones recientes cuando los seguidores abren el feed.

¿Cómo debe funcionar la paginación del feed? Con un cursor basado en el último elemento servido, no con números de página u offsets, para que las publicaciones nuevas no provoquen duplicados mientras el usuario hace scroll.

¿Dónde ocurre el ranking? Al leer, sobre la lista combinada de candidatas. Mantenerlo fuera del fan-out significa que puedes cambiar el ranking sin reconstruir los feeds en caché.

Empieza gratis — un puesto, sin tarjeta de crédito.

Artículos relacionados

← Volver al blog

Abre un lienzo en un minuto

Inicia sesión con Google o GitHub. Gratis para un asiento. Mejora el plan cuando se una el equipo.