Cómo Instagram escaló a 14 millones de usuarios con sólo 3 programadores

Instagram creció de 0 a 14 millones de usuarios en poco más de un año, desde octubre de 2010 hasta diciembre de 2011.

Lograron esto con solo 3 ingenieros.

Lo lograron siguiendo 3 principios clave.

Los principios de Instagram

  • Mantener las cosas simples.
  • No reinventar la rueda.
  • Usar tecnologías probadas y sólidas.

El stack explicado de forma sencilla

La infraestructura inicial de Instagram funcionaba en AWS, usando EC2 con Ubuntu Linux.

Como referencia: EC2 es el servicio de Amazon que permite a los desarrolladores alquilar computadoras virtuales.

Para simplificar, veamos cómo luce una sesión de usuario, desde la perspectiva de un ingeniero de software.

A continuación se marcará como Sesión, al inicio de cada sección.

Frontend

Sesión: Un usuario abre la aplicación de Instagram.

Instagram inicialmente se lanzó como una aplicación para iOS en 2010.

Desde que Swift fue lanzado en 2014, podemos asumir que Instagram fue escrito usando Objective-C y una combinación de otras cosas como UIKit.

Frontend stack

Balanceo de carga

Sesión: Después de abrir la aplicación, se envía una solicitud al backend para obtener las fotos del feed principal. Instagram cuenta con un balanceador de carga.

Instagram utilizó el servicio "Elastic Load Balancer" de Amazon.

Tenían 3 instancias de NGINX que se intercalaban a conveniencia.

Cada solicitud pasaba por el balanceador de carga antes de ser dirigida al "servidor de aplicación".

Backend

Sesión: El balanceador de carga envía la solicitud al servidor de aplicación, que tiene la lógica para procesar la solicitud correctamente.

El "servidor de aplicación" de Instagram utilizaba Django y estaba escrito en Python, con Gunicorn como su servidor WSGI.

A modo de recordatorio:

  • WSGI significa "Web Server Gateway Interface".
  • Y se encarga de redirigir las solicitudes de un servidor web a una aplicación web.

Instagram utilizaba Fabric para ejecutar comandos en paralelo en muchas instancias a la vez. Esto permitía hacer deploy en segundos.

Contaban con 25 máquinas "High-CPU Extra-Large" provistas por Amazon.

Gracias a que el servidor es stateless (sin estado), cuando necesitaban manejar más solicitudes, podían agregar más máquinas sin problema (escalar horizontalmente).

Backend procesando requests

Almacenamiento de datos

Sesión: El servidor de aplicación ve que la solicitud necesita datos para el feed principal.

Para esto, digamos que necesita:

  • IDs de las fotos relevantes más recientes.
  • Las fotos reales que coincidan con esos IDs de fotos.
  • Datos de usuario para esas fotos.

Base de datos: Postgres

Sesión: El servidor de aplicación toma los IDs de fotos relevantes más recientes de Postgres.

El servidor de aplicación obtiene datos de PostgreSQL, que almacenaba la mayoría de los datos de Instagram, como usuarios y metadatos de fotos.

Las conexiones entre Postgres y Django se agruparon usando Pgbouncer.

Instagram fragmentó sus datos debido al alto tráfico que estaban recibiendo (más de 25 fotos y 90 me gusta por segundo). Usaron código para mapear varios miles de fragmentos 'lógicos' a unos pocos fragmentos físicos.

Un desafío interesante que Instagram enfrentó y resolvió es la generación de IDs que pudieran ordenarse por tiempo.

Sus IDs ordenables por tiempo, constaban de:

  • 41 bits para el tiempo en milisegundos (equivalente a 41 años de IDs, con un custom epoch).
  • 13 bits que representan el ID de fragmento lógico.
  • 10 bits que representan una secuencia autoincrementable, módulo 1024. Esto significa que podemos generar 1024 IDs, por fragmento, por milisegundo.

Gracias a los IDs ordenables por tiempo en Postgres, el servidor de aplicación recibía con éxito los IDs de las fotos relevantes más recientes.

Almacenamiento de fotos: S3 y Cloudfront

Sesión: El servidor de aplicación luego obtiene las fotos reales que coincidan con esos IDs de fotos con enlaces de CDN, para que carguen rápidamente para el usuario.

Varios terabytes de fotos se almacenaron en Amazon S3.

Estas fotos se sirvieron rápidamente a los usuarios utilizando Amazon CloudFront.

Almacenamiento en caché: Redis y Memcached

Sesión: Para obtener los datos de usuario de Postgres, el servidor de aplicación (Django) asociaba los IDs de fotos con IDs de usuario usando Redis.

Instagram usó Redis para almacenar un mapeo de aproximadamente 300 millones de fotos al ID de usuario que las creó, con el fin de saber qué fragmento consultar cuando se obtienen fotos para el feed principal, feed de actividad, etc.

Todo Redis se almacenó en memoria para disminuir la latencia y se dividió en varios fragmentos.

Con un hashing inteligente, Instagram pudo almacenar 300 millones de mapeos de claves en menos de 5 GB.

Este mapeo clave-valor de ID de foto a ID de usuario fue necesario para saber qué fragmento de Postgres consultar.

Sesión: Gracias al almacenamiento en caché eficiente usando Memcached, obtener datos de usuario de Postgres fue rápido, ya que las respuesta recientes se leían de caché.

Para el almacenamiento en caché general, Instagram usó Memcached.

  • Tenían 6 instancias de Memcached en ese momento.
  • Memcached es relativamente simple de implementar sobre Django.

Dato interesante: 2 años después, en 2013, Facebook publicó un paper sobre cómo escaló Memcached, para ayudarles a manejar miles de millones de solicitudes por segundo.

Sesión: El usuario ahora ve el feed de inicio, poblado con las últimas imágenes de personas a las que sigue.

Redis y Memcached

Configuración Maestro-Réplica

Tanto Postgres como Redis se ejecutaron en una configuración master-replica, y usaron instantáneas de Amazon EBS (Elastic Block Store) para realizar copias de seguridad frecuentes de los sistemas.

Notificaciones push y tareas asíncronas

Sesión: Ahora, supongamos que el usuario cierra la aplicación, pero luego recibe una notificación push de que un amigo publicó una foto.

Esta notificación push sería enviada usando pyapns, junto con las más de mil millones de notificaciones push que Instagram ya había enviado.

Pyapns es un proyecto open source, que facilita la integración y uso del Servicio de Notificaciones Push de Apple (APNS).

Sesión: ¡Al usuario le encantó esta foto! Entonces decidió compartirla en Twitter.

En el backend, la tarea se envía a Gearman, una cola de tareas que distribuyó el trabajo a máquinas mejor adaptadas.

Instagram tenía alrededor de 200 workers escritos en Python, consumiendo la cola de tareas definida con Gearman.

Gearman se usó para múltiples tareas asíncronas, como distribuir actividades (como una nueva foto publicada) a todos los seguidores de un usuario (esto se llama fanout).

Push notifications y Task queues

Monitoreo

Sesión: ¡Oh no! La aplicación de Instagram se bloqueó porque algo falló en el servidor y envió una respuesta errónea. Los tres ingenieros de Instagram son alertados instantáneamente.

Instagram usó Sentry, una aplicación de Django de código abierto, para monitorear errores de Python en tiempo real.

Munin se utilizó para graficar métricas a nivel del sistema y alertar anomalías. Instagram tenía un montón de plugins para monitorear métricas a nivel de aplicación (como fotos publicadas por segundo).

Pingdom se utilizó para la monitorización de servicios externos, y PagerDuty se utilizó para manejar incidentes y notificaciones.

Aprende viendo

Si la arquitectura inicial de Instagram te parece interesante:

Te invito a ver el siguiente video en YouTube, donde se explica paso a paso las tecnologías usadas, y se cuenta un poco más sobre la historia de Instagram.

Referencias

# agile # sql # django # python

Logo de Programación y más

Comparte este post si te fue de ayuda 🙂.

Regístrate

Accede a todos los cursos, y resuelve todas tus dudas.

Cursos Recomendados

Imagen para el curso Aprende Python

Aprende Python

Desarrolla tu primer Chatbot para Facebook Messenger sobre Google Cloud, y aprende Python en el camino!

Iniciar curso
Imagen para el curso Laravel y Android

Laravel y Android

Curso intensivo. Incluye el desarrollo de una API, su consumo, y autenticación vía JWT. También vemos Kotlin desde 0.

Iniciar curso
Imagen para el curso Docker y Microservicios

Docker y Microservicios

Aprende por qué es importante y cómo funciona Docker, con este nuevo curso práctico!

Iniciar curso

Espera un momento ...

¿Te gustaría llevar mi curso de Laravel, gratis?

Sólo debes ingresar tus datos: