L’architettura di Instagram

Ecco il primo vero articolo del nuovo blog, online in maniera definitiva da oggi pomeriggio!

In realtà sono stato sollecitato da un amico a valutare un articolo interessante da lui scovato riguardante la descrizione dell’infrastruttura utilizzata da instagram. Dopo averlo letto con attenzione, gli ho riposto via email commentandolo punto per punto, alchè mi ha proposto di pubblicare i miei commenti sul mio blog.Lo faccio volentieri, anonimizzando le parti sensibili che riguardano il progetto che sta realizzando.

Lessons learned:
  1. Keep it very simple
  2. Don’t re-invent the wheel
  3. Go with proven and solid technologies when you can.

Nessun commento, corretto.

3 Engineers.

Nel senso che non ne servono 3000 come per Facebook: ne bastano 3 per far girare tutto instagram… Io guardo le cose dal basso e la mia opinione è che 3 è una quantità corretta, 2 resta comunque un numero adeguato per molti progetti, 1 solo amministratore di sistema è troppo poco. In tutte le situazioni in cui lavoro cerco sempre di coinvolgere una persona interna all’azienda in modo che ci sia almeno “un mio backup” in caso di forza maggiore.

Amazon shop. They use many of Amazon’s services. With only 3 engineers so don’t have the time to look at self hosting.

Qui sono dubbioso, ma solo per motivi puramente economici. In USA la tecnologia cloud è molto competitiva perchè hanno costi per la banda Internet molto bassi mentre i costi per il consumo energetico sono identici a quelli Europei, quindi in proporzione molto elevati; in Europa non abbiamo la stessa qualità di banda e i costi per questo componente sono più elevati, quindi la proporzione tra banda e costo dell’energia elettrica è molto inferiore. Questo porta ad avere una maggiore economicità per le offerte cloud americane rispetto alle corrispondenti offerte di housing; al contrario, in Europa, le offerte di housing sono più allettanti rispetto ad un cloud anche se la qualità di banda non è paragonabile, per cui questa è una regola certamente valida per le startup che hanno base/utenze in USA, mentre per noi deve essere valutata attentamente.
Resta il fatto che tutte le ex-startup americane, Twitter e Facebook per citare un paio di nomi, una volta giunte ad una dimensione importante, hanno deciso di abbandonare Amazon e migrare verso ambienti self-hosting, segno che l’economicità del cloud si ha solo sotto una soglia di utilizzo ben determinata.

100+ EC2 instances total for various purposes.

Giusto: meglio tante piccoli istanze che due grossi serveroni con tutto dentro. La separazione delle istanze è il metodo migliore per separare gli ambienti ed essere sicuri che tutti convivano felicemente (diciamolo anche agli Israeliani e ai Palestinesi…)

Ubuntu Linux 11.04 (“Natty Narwhal”). Solid, other Ubuntu versions froze on them.

Nessuna guerra di religione sulle distribuzioni: ciascuna ha le sue caratteristiche e bisogna conoscerle per scegliere quella più adatta:
– le RedHat based (tra cui CentOS e Fedora), sono “vecchie per scelta”: si sceglie una versione master (ad es. CentOS 6 in questo momento) e si saprà che in tutte le release successive (6.1, 6.2, 6.3…) si avrà sempre la stessa versione di ogni pacchetto (ad es. PHP 5.3.3) e saranno applicate solo delle patch create da RedHat per correggere eventuali errori. Quindi si ha una grande solidità in fase di gestione del sistema (aggiornamenti ecc.), ma se si vuole “qualcosa di più” si è con le mani legate. Anche un aggiornamento di master version (passare dalla CentOS 5 alla 6) è praticamente impossibile.
– le Debian based (tra cui la citata Ubuntu) sono solide, hanno un gestore dei pacchetti maglifico (aptitude), ma bisogna prestare moltissima attenzione in fase di aggiornamento perchè sono legate solo alla versione del pacchetto e gli aggiornamenti di sistema seguono quelli del pacchetto senza un sistema di patch interno. Ad esempio su Debian 6 ora si ha PHP 5.3.4, ma con il passare del tempo sarà aggiornato alla versione 5.3.5 poi 5.3.6 e così via. Non si passerà mai alla versione 5.4 a meno di un cambio di versione di Debian (dalla 6 alla futura 7) cosa che, al contrario delle RedHat based, è possibile fare. Normalmente, per esperienza, le Debian based hanno anche meno overhead rispetto alle RedHat based. Personalmente, sui miei server, uso Debian wheezing che è la versione “testing” di Debian su cui si basa Ubuntu: Debian è magari un po’ più ruvida rispetto ad Ubuntu ma qui è solo una questione di gusti personali: i pacchetti sono identici.
– le rolling release (Gentoo, Arch, Debian sid) sono distribuzioni senza versione perchè seguono costantemente gli aggiornamenti di un pacchetto. Quindi è possibile che un aggiornamento di sistema porti PHP dalla versione 5.3 alla 5.4 ma anche alla 6.0! Bello per chi vuole avere sempre l’ultima versione ma poco adatte per i server: personalmente sul mio PC uso Arch Linux nella versione testing, ben conscio che se dopo un aggiornamento non mi parte più il PC me la sono cercata (ma non è mai successo).

Amazon’s Elastic Load Balancer routes requests and 3 nginx instances sit behind the ELB.

Ritengo utile provare nginx al posto di apache come web server per i contenuti statici: io mi trovo benissimo! Nel caso di una realtà che non utilizza i servizi Amazon, non si potrà avere ELB di fronte alle istanze di Nginx, anche perchè nella maggior parte dei casi dubito fortemente che saranno necessarie più istanze di nginx; in qualsiasi caso nulla vieterà in futuro di usare una istanza dedicata di Nginx o di HAproxy per avere le stesse funzionalità di ELB (ELB è basato su HAproxy) di fronte ad X istanze di Nginx.

SSL terminates at the ELB, which lessens the CPU load on nginx.

Giusto: le istanze di ELB sono create su server con schede hardware dedicate alla gestione del criptaggio SSL, quindi delegare ad ELB la gestione del protocollo HTTPs scarica notevolmente i server che stanno alla base e permette di ottenere prestazioni più elevate.

Amazon’s Route53 for the DNS.

Non è possibile migrare indirizzi IP tra diverse zone di Amazon, per cui è come se fossero fornitori separati (ma se Amazon non paga la bolletta della corrente, va giù tutto e fine del film) ed è necessario un sistema in grado di gestire l’alta affidabilità tramite DNS.

25+ Django application servers on High-CPU Extra-Large machines.

Loro usano Phyton con Framework Django, in molti casi italiani si usa PHP. PHP, ad onor del vero, è un linguaggio di scripting molto semplice però non ha prestazioni elevatissime; personalmente Python mi fa venire l’orticaria, ma è una questione di gusti perchè in realtà è un linguaggio molto diffuso: ad esempio tutti gli script di RedHat sono realizzati in Python. Personalmente qualche anno fa mi sono avvicinato al mondo Ruby che è davvero affascinate: prestazioni paragonabili a Python, ma un linguaggio estremamente orientato agli oggetti (ad esempio un semplice ciclo “for i=1 to 20” si traduce in “(1..20).each do |i|” dove (1..20) è un oggetto ed each è un metodo dell’oggetto!) e un framework (Rails) che impone la metodologia MVC (Model View Controller) in modo da avere un codice ordinato e mantenibile facilmente in un team di persone.
Sinceramente, se ora dovessi decidere quale linguaggio studiare per sostituire PHP, mi metterei a lavorare su Scala con il framework Lift: è un linguaggio derivato da Java, quindi il codice viene compilato ed eseguito direttamente e non compilato “in diretta” dal WSGI server: tutto ciò a beneficio delle prestazioni. Inoltre, cosa che mi attira, oltre alla programmazione procedurale e a quella ad oggetti, supporta la programmazione funzionale che permette di sfruttare in maniera pesante il multithreading delle CPU più moderne parallelizzando i processi.

Traffic is CPU-bound rather than memory-bound, so High-CPU Extra-Large machines are a good balance of memory and CPU.

Questa è una caratteristica del progetto Instagram: i filtri per le foto fanno la maggior parte del lavoro e stressano più la CPU che la RAM. Resta inteso che ogni processo ha le sue caratteristiche e quindi questi aspetti devono essere valutati caso per caso.

Gunicorn as their WSGI server. Apache harder to configure and more CPU intensive.

Come per tutti i web server, Apache server può servire nativamente solo i contenuti statici, però Apache ha la caratteristica “unica” di poter usare un suo sistema di moduli interni per lanciare gli script esterni (ad es. mod_php, mod_python e mod_ruby per altri linguaggi); in alternativa può lavorare come tutti gli gli altri web server (ad es. il già citato Nginx) reindirizzando ad un socket esterno ciò che non riesce a servire direttamente. Qui entra in gioco il server WSGI (che è gunicorn per Instagram), cioè quel pezzo di software che fa da “tramite” tra il web server ed il codice Python. Nel caso di ruby, il server WSGI più veloce è Unicorn, mentre per PHP possiamo decidere se usare ilo “vecchio” FastCGI oppure SuPHP oppure, infine, PHP-FPM che è un componente interno di PHP (dalla versione 5.3 in poi) e quindi è quello qualitativamente migliore e più efficiente.

Fabric is used to execute commands in parallel on all machines. A deploy takes only seconds.

Fabric è un sistema per eseguire processi in background per Python usando una connessione SSH; ha la possibilità di lanciare lo stesso comando in contemporanea su più server permettendo il parallel processing. Per Ruby esistono soluzioni analoghe, ma mi piace citare EventMachine in cui non si usa SSH per inviare un comando ad un server remoto, ma si ragiona ad “eventi”. Per PHP sinceramente non è necessario un modulo come fabric: si può arrivare allo stesso risultato con il comado exec “ssh server -c comando”, però si può usare RabbitMQ per avere un sistema di code e comunicazione tra server analogo a quello di EventMachine.

PostgreSQL (users, photo metadata, tags, etc) runs on 12 Quadruple Extra-Large memory instances.

Ok loro usano PostgreSQL per gestire i dati, non MySQL. Loro usano 12 server in replica: le basi dati relazionali si dimostrano sempre uno dei componenti più complessi e pesanti di un sistema.

Twelve PostgreSQL replicas run in a different availability zone.

Anche con MySQL è possibile portare repliche al di fuori del datacenter. Certo che il numero di 12 coincide in entrambi i punti precedenti, quindi immagino che stiamo parlando degli stessi server e quindi che Instagram abbia un totale di 12 server ciascuno istanziato in una istanza 4xExtra-Large sparsi di differenti availability zone.

PostgreSQL instances run in a master-replica setup using Streaming Replication. EBS is used for snapshotting, to take frequent backups.

Sia PostgreSQL sia MySQL possono avere repliche in modalità master-slave, però in entrambi i casi non sono autonomi a gestire eventuali guasti. Ci vuole un software esterno che controlli la funzionalità dei server, che escluda eventuali nodi morti o fuori sincronia e che promuova a master un nodo slave in caso di morte del master. Nel caso di Instagram, hanno usato repmgr per gestire questa cosa, nel caso di MySQL si può usare mysql-mmm.

EBS is deployed in a software RAID configuration. Uses mdadm to get decent IO.

Immagino, poveretti… EBS non è proprio un mostro di velocità I/O per cui usano due dischi in mirror software su ciascuna VM per parallelizzare l’output locale dei dati.

All of their working set is stored memory. EBS doesn’t support enough disk seeks per second.

Ecco la riprova: cache di tutto il database in RAM usando il sistema di cache e buffering interno a Linux perchè EBS non raggiunge velocità di I/O adeguate.

Vmtouch (portable file system cache diagnostics) is used to manage what data is in memory, especially when failing over from one machine to another, where there is no active memory profile already.

Vmtouch è un tool per gestire la cache di linux usata al punto precedente.

XFS as the file system. Used to get consistent snapshots by freezing and unfreezing the RAID arrays when snapshotting.

Aia, qui non mi trovo d’accordo. XFS è il Filesystem più veloce che abbia mai provato, ma ho sperimentato anche blocchi, perdite di dati, incoerenze… No: se parto dal presupposto che uso la cache per tutto, mi “paro il c…” con un filesystem più stabile anche se un po’ più lento come ext4.

Pgbouncer is used pool connections to PostgreSQL.

E per MySQL esiste mysql-proxy.

Several terabytes of photos are stored on Amazon S3.

Ok, le foto non stanno su filesystem locale ma su S3. Penso che alla fine, concettualmente, sia il classico esempio in cui è corretto non reinventare la ruota. Non gestire direttamente lo storage dei file ma tenerli “sul cloud” semplifica notevolmente la vita.

Amazon CloudFront as the CDN.

Certo, questa è l’interfaccia tra S3 e il web.

Redis powers their main feed, activity feed, sessions system, and other services.
Redis runs on several Quadruple Extra-Large Memory instances. Occasionally shard across instances.
Redis runs in a master-replica setup. Replicas constantly save to disk. EBS snapshots backup the DB dumps. Dumping on the DB on the master was too taxing.

Loro usano Redis che è uno storage “noSQL” per i contenuti che cambiano velocemente, in quanto la struttura dati di Postgres non riuscirebbe a stargli dietro. Questa è un’ulteriore testimonianza che tutto non può fare tutto e intestardirsi con una base dati SQL per contenuti che cambiano velocemente (ma anche il contrario come mettersi a creare un gestionale su una base dati Redis o MongoDB solo perchè va di moda) non è una scelta corretta.

Apache Solr powers the geo-search API. Like the simple JSON interface.

Solr è un motore di ricerca interno, probabilmente lo integrano con Apache Hadoop in modo che il secondo acquisisca i dati e crei gli indici che utilizza Solr: i due prodotti sono complementari e spesso sono usati in combinazione.

6 memcached instances for caching. Connect using pylibmc & libmemcached. Amazon Elastic Cache service isn’t any cheaper.

memcached è un sistema di cache condiviso tra più server; è compatibile con tutti i linguaggi di programmazione, anche PHP. Loro dicono che AEC non è economico, a mio avviso nemmeno EBS ed EC2 lo sono…

Gearman is used to: asynchronously share photos to Twitter, Facebook, etc; notifying real-time subscribers of a new photo posted; feed fan-out.

Francamente non capisco perchè usino gearman che è un doppione di fabric, a maggior ragione se hanno pure un sistema Hadoop alla base di Solr (ma questa è solo una mia congettura). Sicuramente hanno reputato che è preferibile isolare ciascuna funzionalità in diversi gruppi di istanze e quindi, a quel punto, tanto vale utilizzare il sistema che più si avvicina a risolvere ciascuna specifica funzione.

200 Python workers consume tasks off the Gearman task queue.

Beve, però questo Gearman!

Pyapns (Apple Push Notification Service) handles over a billion push notifications. Rock solid.

Per comunicare direttamente con i client Apple

Munin to graph metrics across the system and alert on problems. Write many custom plugins using Python-Munin to graph, signups per minute, photos posted per second, etc.

Munin è un tool di monitoraggio e generazione di grafici come cacti o nagios (che preferisco)

Pingdom for external monitoring of the service.

Giusto, lo uso anch’io: è inutile controllare che dentro alla rete funzioni tutto se poi cade il gateway che ti collega ad Internet 🙂

PagerDuty for handling notifications and incidents.

Questo è un servizio di alert che si integra con Pingdom, ma anche con munin e nagios: se si rompe qualcosa, oltre all’email può arrivare un SMS o una telefonata. Francamente ce ne sono molti, ma questo sembra davvero facile da integrare per cui lo valuterò.

Sentry for Python error reporting.

Anche questo è un servizio che come Pingdom uso anch’io ($9 mese) e permette di gestire gli errori sul sito: quando ad un utente arriva un errore di qualsiasi tipo, questo sistema raccoglie tutti i dati per cui il programmatore ha una chiara idea di eventuali bug.