Questo articolo è un articolo speculare di traduzione automatica, clicca qui per saltare all'articolo originale.

Vista: 13027|Risposta: 0

StackOverflow è così grande, qual è la sua architettura?

[Copiato link]
Pubblicato su 11/04/2018 17:33:18 | | | |
Per rendere più facile capire di cosa parla questo articolo, iniziamo con il cambiamento nella statistica media giornaliera di Stack Overflow. Le seguenti cifre sono tratte dalle statistiche al 12 novembre 2013:

  • Il bilanciatore di carico accettava 148.084.833 richieste HTTP
  • Di queste, 36.095.312 erano carichi di pagine
  • 833.992.982.627 byte (776 GB) di traffico HTTP vengono utilizzati per inviare
  • Sono stati ricevuti in totale 286.574.644.032 byte (267 GB) di dati
  • Sono stati inviati in totale 1.125.992.557.312 byte (1.048 GB) di dati
  • 334.572.103 query SQL (inclusi solo da richieste HTTP)
  • 412.865.051 richieste Redis
  • 3.603.418 richieste di motori tag
  • Ci sono voluti 558.224.585 ms (155 ore) per query SQL
  • Ci sono voluti 99.346.916 ms (27 ore) per le richieste Redis
  • Ha impiegato 132.384.059 ms (36 ore) sulla richiesta del motore tag
  • Ci sono voluti 2.728.177.045 ms (757 ore) per l'elaborazione ASP.Net processo



I seguenti dati mostrano i cambiamenti nelle statistiche al 9 febbraio 2016, così puoi confrontare:

  • Richieste HTTP ricevute dal bilanciatore di carico: 209.420.973 (+61.336.090)
  • 66.294.789 (+30.199.477) di cui carica la pagina
  • Dati HTTP inviati: 1.240.266.346.053 (+406.273.363.426) byte (1,24 TB)
  • Quantità totale di dati ricevuti: 569.449.470.023 (+282.874.825.991) byte (569 GB)
  • Quantità totale di dati inviati: 3.084.303.599.266 (+1.958.311.041.954) byte (3,08 TB)
  • Query SQL (solo da richieste HTTP): 504.816.843 (+170.244.740)
  • Risultati della cache Redis: 5.831.683.114 (+5.418.818.063)
  • Ricerche elastiche: 17.158.874 (non tracciate nel 2013)
  • Richieste motori tag: 3.661.134 (+57.716)
  • Tempo cumulativo consumato per eseguire query SQL: 607.073.066 (+48.848.481) ms (168 ore)
  • Tempo consumato per la cache Redis: 10.396.073 (-88.950.843) ms (2,8 ore)
  • Tempo consumato dalle richieste del motore di tag: 147.018.571 (+14.634.512) ms (40,8 ore)
  • Tempo consumato nell'elaborazione ASP.Net: 1.609.944.301 (-1.118.232.744) ms (447 ore)
  • 22,71 ms (-5,29) ms 49.180.275 pagine di emissione tempo medio di rendering (di cui 19,12 ms consumati in ASP.Net)
  • 11,80 (-53,2) ms 6.370.076 prime pagine Tempo medio di rendering (di cui 8,81 ms consumati in ASP.Net)



Potresti chiederti perché ASP.Net sta elaborando 61 milioni di richieste in più al giorno ma riducendo i tempi di elaborazione di 757 ore (rispetto al 2013). Questo è dovuto principalmente agli aggiornamenti che abbiamo apportato ai nostri server all'inizio del 2015, oltre a molto lavoro di ottimizzazione delle prestazioni in-app. Non dimenticare: le prestazioni restano ancora un punto di forza. Se siete più curiosi dei dettagli specifici dell'hardware, non preoccupatevi, fornirò i dettagli hardware specifici dei server utilizzati per far funzionare questi siti sotto forma di appendice nel prossimo articolo (aggiornerò questo link quando sarà il momento).

Cosa è cambiato negli ultimi due anni? Non molto, solo sostituire alcuni server e apparecchiature di rete. Ecco una panoramica dei server utilizzati oggi per gestire il tuo sito web (nota come sono cambiati dal 2013)

  • 4 server Microsoft SQL Server (2 dei quali utilizzano nuovo hardware)
  • 11 Server Web IIS (Nuovo Hardware)
  • 2 server Redis (nuovo hardware)
  • 3 server Tag Engine (2 dei quali utilizzano nuovo hardware)
  • 3 server Elasticsearch (uguali a quelli sopra)
  • 4 server di bilanciamento del carico HAProxy (2 aggiunti per supportare CloudFlare)
  • 2 dispositivi di rete (Nexus 5596 core + 2232TM Fabric Extender, tutti i dispositivi aggiornati a 10Gbps di larghezza di banda)
  • 2 x Fortinet 800C Firewall (sostituisce gli ASA Cisco 5525-X)
  • 2 router Cisco ASR-1001 (sostituiscono i router Cisco 3945)
  • 2 router Cisco ASR-1001-x (NUOVI!) )



Cosa ci serve per far funzionare Stack Overflow? Non è cambiato molto dal 2013, ma grazie alle ottimizzazioni e al nuovo hardware menzionato sopra, ora ci serve solo un server web. Abbiamo già testato questa situazione involontariamente, con successo più volte. Nota: ho appena detto che funziona, non ho detto che sia una buona idea. Ma ogni volta che succede, è piuttosto interessante.

Ora che abbiamo alcuni dati di riferimento sulle idee di scalabilità dei server, vediamo come abbiamo creato queste pagine web interessanti. Pochi sistemi esistono completamente in modo indipendente (e i nostri non fanno eccezione), e senza una visione olistica che integri queste parti, il significato della pianificazione architettonica si riduce notevolmente. Il nostro obiettivo è comprendere la situazione complessiva. In futuro ci saranno molti articoli che approfondiranno ciascun campo specifico. Questo articolo è solo un riassunto della struttura logica dell'hardware chiave, e il prossimo articolo conterrà dettagli specifici su questi hardware.

Se vuoi vedere come appare oggi questo hardware, ecco alcune foto che ho scattato all'Armadio A (l'Armadio B è esattamente uguale) quando ho aggiornato il server a febbraio 2015:



Ora, immergiamoci nella disposizione architettonica. Di seguito è riportato un riassunto dell'architettura logica dei principali sistemi esistenti:



Principi di base

Ecco alcuni principi comuni che non devono essere introdotti a loro volta:

  • Tutto ha backup ridondanti.
  • Tutti i server e dispositivi di rete hanno almeno due connessioni a larghezza di banda da 10Gbps.
  • Tutti i server hanno due fonti di alimentazione che forniscono energia tramite due unità UPS, due generatori dietro di essi e due feedforward di tensione di rete.
  • Tutti i server hanno un backup ridondante situato nel Rack A e nel Rack B.
  • Tutti i server e i servizi hanno backup doppi ridondanti in un data center separato (in Colorado), anche se io mi occupo principalmente di New York.
  • Tutto ha backup ridondanti.


Internet

Prima devi trovare il nostro sito web, che è una cosa del DNS. Trovare siti web è veloce, quindi ora lo affidiamo a CloudFlare perché hanno server DNS in ogni angolo del mondo. Aggiorniamo i record DNS tramite API, e loro sono responsabili della "gestione" del DNS. Tuttavia, nelle nostre menti da malvagi, abbiamo ancora i nostri server DNS a causa dei profondi problemi di fiducia. Quando l'apocalisse è apocalittica – forse a causa della GPL, Punyon o problemi di cache – e la gente vuole ancora programmare per distogliere l'attenzione, passiamo ai nostri server DNS.

Una volta che il tuo browser trova il nostro nascondiglio, il traffico HTTP dei nostri quattro ISP (Level 3, Zayo, Cogent e Lightower a New York) entra in uno dei nostri quattro router avanzati. Utilizziamo il Border Gateway Protocol (BGP, un protocollo molto standard) per fare peer-to-peer del traffico dai fornitori di rete, al fine di controllarlo e fornire il modo più efficiente per accedere ai nostri servizi. I router ASR-1001 e ASR-1001-X sono divisi in due gruppi, ciascuno dei quali dovrebbe utilizzare la modalità attiva/attiva per gestire il traffico proveniente da entrambi i provider di rete – qui ci sono backup ridondanti. Sebbene abbiano tutti la stessa larghezza di banda fisica di 10Gbps, il traffico esterno è comunque indipendente dal traffico proveniente dalla VLAN esterna ed è collegato separatamente al bilanciamento del carico. Dopo che il traffico passa attraverso il router, arriverai al bilanciatore di carico (load balancer).

Penso sia il momento di menzionare che abbiamo MPLS con una larghezza di banda di 10Gbps tra i due data center, anche se questo non è direttamente collegato ai servizi del sito web. Utilizziamo questa tecnologia per eseguire repliche fuori sede e recupero rapido dei dati per gestire determinate emergenze. "Ma Nick, non c'è ridondanza in questo!" Beh, dal punto di vista tecnico hai ragione (in senso positivo), a questo livello si tratta davvero di un unico punto di fallimento. Ma aspetta! Attraverso il provider di rete, abbiamo anche due rotte di failover OSPF aggiuntive (MPLS è la prima scelta, e queste sono la seconda e la terza scelta per motivi di costo). Ognuno dei set di dispositivi menzionati in precedenza sarà collegato al data center del Colorado per bilanciare il traffico di rete in caso di failover. Ovviamente, avremmo potuto collegare questi due set di dispositivi tra loro, così che ci fossero quattro set di percorsi, ma lasciamo perdere, andiamo avanti.

Bilanciamento del carico (HAProxy)

Il bilanciamento del carico è implementato con HAProxy 1.5.15, che gira su CentOS 7 (la nostra versione preferita di Linux). E aggiungere il protocollo di trasmissione sicura TLS (SSL) su HAProxy. Stiamo anche tenendo d'occhio HAProxy 1.7, che fornirà subito il supporto per il protocollo HTTP/2.

A differenza di altri server con doppie connessioni di rete LACP da 10Gbps, ogni bilanciatore di carico ha due connessioni da 10Gbps: una per la rete esterna e l'altra per la DMZ. Questi server dispongono di 64GB o più di memoria per gestire il livello protocollo SSL in modo più efficiente. Quando possiamo memorizzare e riutilizzare più sessioni TLS in memoria, consumiamo meno risorse di calcolo quando ci connettiamo allo stesso client. Questo significa che possiamo ripristinare le sessioni in modo più rapido ed economico. La memoria è così economica che è una scelta facile.

Il bilanciamento del carico è facile da configurare. Ascoltiamo diversi siti web su più IP diversi (principalmente per motivi di gestione dei certificati e DNS) e poi instradamo il traffico verso diversi backend (principalmente in base alle header host). L'unica cosa che facciamo qui è limitare la velocità e estrarre alcune informazioni di header (dal livello web) per accedere ai messaggi di log di sistema di HAProxy, così possiamo registrare le metriche di performance per ogni richiesta. Ne parleremo in dettaglio più avanti.

Livello web (IIS 8.5, ASP.Net MVC 5.2.3 e .Net 4.6.1)

Il bilanciamento del carico distribuisce il traffico tra 9 di quelli che chiamiamo il server web principale (01-09) e 2 server web di sviluppo (10-11, il nostro ambiente di test). Il server principale gestisce Stack Overflow, Careers e tutti i siti di Stack Exchange, mentre meta.stackoverflow.com e meta.stackexchange.com girano su altri due server. L'app principale di Q&A è multi-tenant, il che significa che una singola app gestisce tutte le richieste dal sito Q&A. In altre parole, possiamo eseguire l'intera app Q&A su un unico pool di applicazioni su un solo server. Altre app come Careers, API v2, Mobile API, ecc., sono indipendenti. Ecco cosa vedi in IIS per i server master e di sviluppo:



Ecco la distribuzione del livello web di Stack Overflow come vista in Opserver (la nostra dashboard interna di monitoraggio):



Ecco il consumo di risorse di questi server web:



Entrerò più nei dettagli in un articolo successivo sul perché stiamo fornendo così tante risorse, concentrandoci su build rotante, margine di flessibilità e ridondanza.

Livello di servizio (IIS, ASP.Net MVC 5.2.3, . NET 4.6.1 e HTTP. SYS)

Accanto al livello web c'è il livello di servizio. Girano anche su IIS 2012 in Windows 8.5R2. Questo livello esegue alcuni servizi interni che supportano il livello web e altri sistemi interni dell'ambiente di produzione. I due principali servizi sono: "Stack Server", che utilizza un motore di tag ed è basato su http.sys (non IIS); API di Providence (basata su IIS). Un fatto interessante: ho dovuto correlare i due processi per collegarsi a socket diversi, perché lo Stack Server accedeva molto frequentemente alle cache L2 e L3 quando aggiornava la lista dei problemi a intervalli di due minuti.

Le macchine che esegue questi servizi sono fondamentali per il motore di tag e le API backend, quindi devono essere ridondanti, ma non 9 volte ridondanti. Ad esempio, carichiamo tutti gli articoli e i loro tag dal database ogni n minuti (attualmente 2 minuti), il che non è basso. Non vogliamo ripetere questa operazione di caricamento 9 volte al livello web, 3 volte è abbastanza sicuro per noi. Utilizziamo anche diverse configurazioni hardware per questi server per ottimizzare meglio le caratteristiche computazionali e di carico dati del motore dei tag e dei job elastici (anch'essi in esecuzione in questo livello). Il "motor di tag" è un argomento relativamente complesso che sarà trattato in un articolo dedicato. Il principio di base è che quando accedi all'indirizzo /questions/tagged/java, visiti il motore di tagging per trovare le domande che corrispondono. Il motore gestisce tutte le coincidenze dei tag tranne /search, quindi ovunque, compresa la nuova navigazione, riceve i dati tramite questo servizio.

Cache e pubblicazione/iscrizione (Redis)

Abbiamo usato Redis in alcuni punti e ha una stabilità solidissima. Sebbene ci siano fino a 160 miliardi di operazioni al mese, la CPU per istanza non supera il 2%, che di solito è inferiore:



Usiamo Redis per i sistemi di cache a livello L1/L2. Il livello "L1" è la cache HTTP che funziona in un server web o in qualsiasi applicazione simile. Il livello "L2" serve a ottenere dati tramite Redis dopo che la cache del livello precedente si è guastata. I nostri dati sono memorizzati in formato Protobuf, implementato tramite protobuf-dot-net scritto da Marc Gravel. Per il client Redis, abbiamo utilizzato la libreria StackExchange.Redis, che è una libreria open-source sviluppata internamente. Se un server web non colpisce sia nelle cache L1 che L2, recupera i dati dalle sue fonti dati (query del database, chiamate API, ecc.) e salva i risultati nella cache locale e in Redis. Il server successivo potrebbe mancare dalla cache L1 quando recupera gli stessi dati, ma recupererà i dati in L2/Redis, eliminando la necessità di query del database o chiamate API.

Gestiamo anche molti siti Q&A, ognuno con la propria cache L1/L2: key come prefisso nella cache L1 e ID database nella cache L2/Redis. Approfondiremo questo argomento in prossimi articoli.

Oltre ai due principali server Redis (uno master e uno slave) che esegue tutte le istanze del sito, abbiamo anche configurato un'istanza per il machine learning (principalmente per motivi di memoria) utilizzando altri due server slave dedicati. Questo gruppo di server viene utilizzato per fornire servizi come la raccomandazione di domande sulla homepage e la migliore corrispondenza dei lavori. Questa piattaforma si chiama Providence, e Kevin Montrose ne ha scritto.

Il server Redis principale ha 256GB di RAM (circa 90GB utilizzati), mentre il server Providence ha 384GB di memoria (circa 125GB utilizzati).

Redis non serve solo per la caching, ma ha anche un meccanismo di pubblicazione e iscrizione in cui un server può pubblicare un messaggio e altri abbonati possono riceverlo (inclusi Redis dai client a valle sul server). Utilizziamo questo meccanismo per svuotare la cache L1 su altri servizi al fine di mantenere la coerenza della cache sul server web. Ma ha un altro uso importante: i websocket.

Websockets (NetGain)

Utilizziamo websocket per inviare aggiornamenti in tempo reale agli utenti, come notifiche nella barra superiore, voti, nuova navigazione, nuove risposte, commenti e altro ancora.

Il socket server stesso gira sul livello web, usando socket nativi. Questa è un'applicazione molto piccola basata sulla nostra implementazione open-source di libreria: StackExchange.NetGain. Nei momenti di picco, avevamo circa 500.000 connessioni websocket contemporanee, che sono molti browser. Curiosità: alcuni di questi browser sono aperti da oltre 18 mesi, e dovrai trovare qualcuno per vedere se quegli sviluppatori sono ancora attivi. Il grafico seguente mostra il modello di concorrenza tramite websocket questa settimana:



Perché usare i websocket? Alla nostra scala, è molto più efficiente dei sondaggi. In questo modo, possiamo semplicemente inviare più dati con meno risorse e essere più in tempo reale per gli utenti. Questo approccio non è privo di problemi: porte temporanee, gestione dei file esauriti nei load balancer sono problemi molto interessanti, di cui parleremo più avanti.

Ricerca (Elasticsearch)

Spoiler: non c'è molto di cui entusiasmarsi qui. Il livello web utilizza Elasticsearch 1.4 e implementa un client StackExchange.Elastic ultra-leggero e ad alte prestazioni. A differenza della maggior parte delle cose, non abbiamo intenzione di rendere open source questa parte, semplicemente perché espone un sottoinsieme molto piccolo delle API di cui abbiamo bisogno. Sono sicuro che renderlo pubblico compensi la perdita e confonderà solo gli sviluppatori. Usiamo elastic:/search in questi punti per calcolare domande correlate e dare suggerimenti quando poniamo domande.

Ogni cluster Elastic (uno per ogni data center) contiene 3 nodi, ciascuno con il proprio indice. Il sito Careers dispone anche di indici aggiuntivi. Una parte leggermente meno standard della nostra configurazione in cerchi elastici è che il nostro cluster di 3 server è un po' più potente rispetto alla configurazione abituale: ogni server utilizza storage SSD, 192GB di memoria, doppia rete di 10Gbps di banda larghezza.

Lo stesso dominio applicativo di Stack Server (sì, ci ha fatto girare .Net Core in questo posto) ospita anch'esso un motore di tag, che utilizza anch'esso Elasticsearch per indicizzazione continua. Qui usiamo un piccolo trucco, come l'uso di ROWVERSION in SQL Server (la fonte dati) per confrontare con il documento "ultimo posto" in Elastic. Poiché apparentemente è sequenziale, è facile per noi scansionare e indicizzare i contenuti se vengono modificati dopo l'ultima visita.

Il motivo principale per cui utilizziamo Elasticsearch invece di tecnologie come la ricerca full-text SQL è la sua scalabilità e la sua costi-efficacia. SQL è relativamente costoso sulle CPU, mentre Elastic è molto più economico e ha molte nuove funzionalità ultimamente. Perché non usare Solr? Dobbiamo cercare in tutta la rete (con più indici contemporaneamente), e Solr non supporta questo scenario al momento delle nostre decisioni. Il motivo per cui non abbiamo ancora usato la 2.x è che i tipi sono cambiati molto nella 2.x, il che significa che dobbiamo ri-indicizzare tutto se vogliamo aggiornare. Semplicemente non ho abbastanza tempo per pianificare i cambiamenti dei requisiti e le migrazioni.

Database (SQL Server)

Usiamo SQL Server come unica fonte di verità. Tutti i dati in Elastic e Redis provengono da SQL Server. Abbiamo due cluster SQL Server e siamo configurati con gruppi di disponibilità AlwaysOn. Ogni cluster ha un server primario a New York (che supporta quasi tutto il carico) e un server replica, oltre a un server replica in Colorado (il nostro data center di disaster recovery). Tutte le operazioni di copia sono asincrone.

Il primo cluster è un insieme di server Dell R720xd, ciascuno con 384GB di memoria, un SSD PCIe con 4TB di spazio e due CPU da 12 core. Include Stack Overflow, Sites (che nome sbagliato, lo spiegherò dopo), PRIZM e il database di Mobile.

Il secondo cluster è un insieme di server Dell R730xd, ciascuno con 768GB di memoria, un SSD PCIe con 6TB di spazio e due CPU da 8 core. Questo cluster contiene tutti gli altri database, inclusi Careers, Open ID, Chat, log delle eccezioni e altri siti di domande e risposte (ad esempio, Super User, Server Fault, ecc.).

A livello di database, vogliamo mantenere l'utilizzo della CPU a un livello molto basso, anche se in pratica l'uso della CPU sarà leggermente superiore quando si verificano problemi di cache pianificati (che stiamo risolvendo i problemi). Attualmente, NY-SQL02 e 04 sono i server principali e 01 e 03 sono i server replica, e li abbiamo appena riavviati oggi a causa dell'aggiornamento SSD. Ecco come si sono comportati nelle ultime 24 ore:



Il nostro uso di SQL è molto semplice. Semplice significa veloce. Sebbene alcune query statement possano essere pervertite, la nostra interazione con SQL stessa avviene in modo abbastanza nativo. Abbiamo un po' di Linq2SQL legacy, ma tutti i nostri nuovi sviluppi utilizzano Dapper, il nostro framework open-source micro-ORM che utilizza POCO. Lasciate che vi spieghi in un altro modo: Stack Overflow ha una sola procedura memorizzata nel suo database, e io eliminerò quest'ultima procedura rimasta e la sostituirò con del codice.

Biblioteca

Bene, cambiamo idea, ecco cose che possono aiutarti in modo più diretto. Ne ho già menzionati alcuni, ma vi darò una lista delle tante librerie open-source .Net che manteniamo e che tutti usano. Le rendiamo open source perché non hanno un valore aziendale fondamentale, ma possono aiutare sviluppatori in tutto il mondo. Spero che ora tu possa usarli:

  • Dapper (.Net Core) – Un framework micro-ORM ad alte prestazioni per ADO.Net
  • StackExchange.Redis – Un client Redis ad alte prestazioni
  • MiniProfiler – un profiler leggero che utilizziamo su ogni pagina (supporta anche Ruby, Go e Node)
  • Eccezionale – Per la registrazione degli errori in SQL, JSON, MySQL, ecc
  • Jil – Serializzazione JSON ad alte prestazioni e deserializzatore
  • Sigillo – .Net CIL Generation Helper (usato quando C# non è abbastanza veloce)
  • NetGain – Server websocket ad alte prestazioni
  • Opserver – Dashboard di monitoraggio che interroga direttamente la maggior parte dei sistemi e può recuperare informazioni da Orion, Bosun o WMI
  • Bosun – Sistema di monitoraggio in background, scritto in Go






Precedente:enum enum verifica se un valore è incluso in un enum
Prossimo:Come posso trovare MB rapidamente
Disconoscimento:
Tutto il software, i materiali di programmazione o gli articoli pubblicati dalla Code Farmer Network sono destinati esclusivamente all'apprendimento e alla ricerca; I contenuti sopra elencati non devono essere utilizzati per scopi commerciali o illegali, altrimenti gli utenti dovranno sostenere tutte le conseguenze. Le informazioni su questo sito provengono da Internet, e le controversie sul copyright non hanno nulla a che fare con questo sito. Devi eliminare completamente i contenuti sopra elencati dal tuo computer entro 24 ore dal download. Se ti piace il programma, ti preghiamo di supportare software autentico, acquistare la registrazione e ottenere servizi autentici migliori. In caso di violazione, vi preghiamo di contattarci via email.

Mail To:help@itsvse.com