miércoles, 16 de mayo de 2012

Cómo es la arquitectura de Instagram


Un ingeniero de Instagram, la empresa recientemente comprada por Facebook publicó en el blog -oficial- del team de ingeniería de Instagram los detalles de la arquitectura que sostiene Instagram.

Acá pueden leer el artículo completo
http://instagram-engineering.tumblr.com/post/13649370142/what-powers-instagram-hundreds-of-instances-dozens-of

Me gusta leer estos textos para ir viendo qué se usa hoy en deployments grandes, cómo lo usan, qué cosas deberían funcionar y no lo hacen, qué otras cosas no están tan probadas pero funcionan muy bien, etc. Startups como Instagram hacen un uso extensivo de tecnología opensource - obviamente - para reducir costos al máximo, así que - en gral. - el profile de TCO de este tipo de arquitecturas suele ser muy bajo en consumo de recursos, lo más bajo posible sin afectar la escalabilidad y la calidad de los servicios (más o menos el requerimiento base presente en toda arquitectura de sistemas).


Traduzco/colaboro el artículo original:

La arquitectura evolucionó durante un año, provee servicios para 14+ millones de usuarios. La infra la manejan 3 ingenieros. Tres principios de la arquitectura:

- Mantener las cosas bien simples.
- No reinventar la rueda.
- Aplicar, cuando se pueda, tecnologías sólidas y probadas.

La arquitectura, de arriba hacia abajo

1) OS / Hosting
Ubuntu 11.04 (Natty), corriendo sobre Amazon EC2.
Los Ubuntus anteriores les dieron problemas en EC2 con alto tráfico, pero Natty funcionó bien. Por ahora están con Amazon, ya que con 3 ingenieros es poco viable el hosting propio.

2) Balanceo de Carga
Todo request a los servers de Instagram pasa por balanceadores. Solían correr 2 Nginx y balancearlos con DNS Round-Robin. El problema con eso es el tiempo que tarda DNS en actualizarse, para el caso en que hubiera que decomisionar alguno de los servers. Ahora están usando Amazon Elastic Load Balancer, con 3 instancias Nginx detrás y las pueden sacar y poner sin problemas (son sacadas de la rotación automáticamente si alguna falla en un health-check). También terminan su SSL a nivel ELB, lo que libera carga de CPU en los Nginx. Usan amazon Route53 para DNS.

3) Servers de aplicación
Corren Django sobre 25 máquinas Amazon High-CPU Extra-Large. La carga de trabajo está muy ligada a las CPU más que a la memoria. así que las máquinas mencionadas le ofrecen un buen balance de memoria y cpu.

Usan gunicorn como server WSGI, antes usaban mod_wsgi de Apache, pero Gunicorn les resultó más fácil de configurar y con menos consumo de CPU. Para correr comandos en varias instancias a la vez, usan Fabric, que hace poco tiene un modo paralelo que les permite deployar código en muy poco tiempo.


4) Data Storage
La mayoría de los datos (usuarios, metadatos de fotos, tags, etc.), están guardados en Postgresql, en este link explican como "shardean" a través de varias diferente instancias de Postgresql.
http://instagram-engineering.tumblr.com/post/10853187575/sharding-ids-at-instagram

¿Qué es "shardear" en bases de datos?
http://en.wikipedia.org/wiki/Shard_(database_architecture)

El cluster shard principal tiene 12 instancias de memoria Quadruple Extra-Large (y 12 réplicas en una zona diferente).

Los ingenieros se dieron cuenta que el network filesystem de Amazon (EBS), no soportaba suficientes búsquedas de disco por segundo, así se dedicaron a mantener en memoria todo el set de trabajo. Para lograr buena performance de IO (entrada/salida), configuraron los discos EBS en RAIDS por software usando mdadm.

Un tip que dan: se dieron cuenta que vmtouch ( http://hoytech.com/vmtouch/vmtouch.c ) es una muy buena herramienta para ver qué datos están en memoria, especialmente al hacer failover de una máquina a la otra donde no hay un perfil de memoria activo todavía. Hay un script ( https://gist.github.com/1424540 ) que usan para parsear el output de vmtouch y mostrar el comando vmtouch correspondiente a correr en otro sistema para hacerlo coincidir con el estado de la memoria de la anterior.

Todas las instancias Postgresql corren en un esquema master-replica usando Streaming Replication. Usan snapshots EBS, para hacer snapshots frecuentes de los sistema para backup. Usan XFS como filesystem del OS, lo cual les permite congelar/descongelar los arreglos RAID cuando están haciendo el snapshot, garantizando así la consistencia del - filesystem dentro del - snapshot. Se inspiraron en ec2-consistent-snapshot ( http://alestic.com/2009/09/ec2-consistent-snapshot ). Para arrancar la replicación, la herramienta que usan es repmgr. de 2ndQuadrant ( https://github.com/greg2ndQuadrant/repmgr ).

Para conectar las bases de datos con los servers de aplicación, se dieron cuenta pronto que ello tenía un fuerte impacto en la performance, así que usan Pgbouncer para poolear conecciones a Postgresql. El blog de Christopher Pettus es una gran fuente de datos respecto de Django, Postgresql y Pgbouncer.

http://pgfoundry.org/projects/pgbouncer/
http://thebuild.com/blog/

Las fotos en sí las guardan en Amazon S3, la cual guarda ahora varios terabytes de datos de fotos para Instagram. Usan Amazon CloudFront como CDN, lo que ayuda a los tiempos de carga de imágenes de usuarios alrededor del mundo.

También usan Redis extensivamente. que abastece el feed principal, el de actividades y el del sistema de sesiones (este es el backend de session de Django > https://gist.github.com/910392), y el de otros sistemas relacionados ( http://instagram-engineering.tumblr.com/post/12202313862/storing-hundreds-of-millions-of-simple-key-value-pairs ). Todos los datos de Redis necesitan estar en memoria, así que terminaron corriendo varias instancias de memoria Quadruple Extra-Large para Redis, ocasionalemente shardean en varias instancias de Redis para algun subsistema. Corren Redis en un esquema master-replica, y las réplicas constantemente guardan la DB a disco; para terminar usan snapshots EBS para backupear esos dumps DB (lo hacen en la réplica porque se dieron cuenta que dumpear la DB en el master era muy "costoso" en recursos). Ya que Redis permite escribir a las réplicas, se hace para para lograr un fácil failover a nuevas máquinas Redis, sin que sea necesario un downtime (bajar el servicio).

Para la API de geo-búsqueda usaron Postgresql por varios meses, pero cuando shardearon sus entradas Media, se mudaron a Apache Solr, que tiene una interfaz JSON simple, así que por lo que concierne a su aplicación, es solo otra API a consumir.

Finalmente, como todo servicio web moderno, usan Memcached para cacheo y tienen 6 instancias Memcached, a las que se conectan usando pylibmc y libmemcached, cuentan que Amazon tiene el servicio Elastic Cache, pero no es más barato ($$$), que correr las instancias Memcached, así que todavía no lo están usando.


5) Cola de tareas y envío de notificaciones
Cuando un usuario quiere compartir una foto Instagram en Twitter o Facebook, o cuando necesitan notificar a los suscriptores "Real-Time" ( http://instagram.com/developer/realtime/ ), de que una nueva foto fue posteada, manejan esa tarea con Gearman ( http://gearman.org/ ), un sistema de manejo de colas escrito en Danga. Proceder asincrónicamente en la cola implica que los uploads de medios terminan rápidamente, mientras que los más pesados pueden correr en background. Tienen unos 200 workers (todos escritos en Python), consumiendo de la cola de tareas en cualquier momento, divididos entre los servicios que comparten. También manejan el feed de fan-out en Gearman, así que postear es tan responsivo para un nuevo usuario como lo es para un usuario con muchos followers.

Para enviar notificaciones la solución de mejor costo-beneficio que encontraron fue https://github.com/samuraisam/pyapns , un servicio opensource de Twisted que llegó a manejar más de un billón de envíos de notificaciones y funcionó bien.


6) Monitoreo
Con más de 100 instancias, es importante saber qué está pasando. Usan Munin ( http://munin-monitoring.org/  ) para graficar métricas de todos los sistemas, y también los alerta si algo está fuera de rangos normales. Escriben muchos plugins customizados para Munin, sobre Python-Munin (http://samuelks.com/python-munin/ ), para graficar métricas que no son del sistema (por ejemplo, suscripciones por minuto, fotos posteadas por segundo, etc.), Usan Pingdom ( http://pingdom.com/ ) para monitoreo externo del servicio y PagerDuty ( http://pagerduty.com/ )para manejar notificaciones e incidentes.

Para reporte de errores de Python usan Sentry ( http://pypi.python.org/pypi/django-sentry) una muy buen app Django escrita por la gente de Disqus. En cualquier momento dado, se loguean y pueden ver qué errores están ocurriendo en el sistema, en tiempo real.

2 comentarios:

Anónimo dijo...

me parece muy buena tu traducción muchas gracias

yo pienso que al principio seria algo muy sencillo, con el trascurso del tiempo fueron implementando nuevas tecnologías debido a la cantidad de usuarios e información que gestionan

tu que opinas?

homero dijo...

Hola, muy buenas.

Un buen post, sin duda, pero creo que falta un apartado en este post. ¿Con que herramienta o framework o lenguaje está programado Instagram?

Que se utiliza, con qué se ha desarrollado el front de esta red social.

Saludos!