Ciao!
Di nuovo con voi Nikita - ingegnere di sistema dell'azienda SEMrush. E con questo articolo continuo la storia su come abbiamo trovato una soluzione per bypassare il Firewall Cinese per il nostro servizio semrush.com.
In Ho raccontato:
- quali problemi sorgono dopo aver preso la decisione 'Dobbiamo fare in modo che il nostro servizio funzioni in Cina'
- quali problemi ha Internet cinese
- perché è necessaria una licenza ICP
- come e perché abbiamo deciso di testare i nostri ambienti di prova con Catchpoint
- quali risultati ha dato la nostra prima soluzione, basata sulla Cloudflare China Network
- come abbiamo trovato un bug nel DNS di Cloudflare
Questa parte è la più interessante, a mio avviso, perché si concentra su realizzazioni tecniche specifiche degli staging. E iniziamo, o meglio continuiamo, con Alibaba Cloud.
Alibaba Cloud
Alibaba Cloud un grande fornitore di cloud, che offre tutti i servizi che gli consentono di definirsi legittimamente cloud provider. È positivo che gli utenti stranieri possano registrarsi, e che gran parte del sito sia tradotta in inglese (una rarità per la Cina). In questo cloud è possibile lavorare con molte regioni del mondo, della Cina continentale, così come dell'Asia Pacifica (Hong Kong, Taiwan, ecc.).
IPSEC
Abbiamo iniziato con la geografia. Poiché il nostro sito di test si trovava in Google Cloud, dovevamo 'collegare' Alibaba Cloud con GCP, quindi abbiamo aperto l'elenco delle località in cui Google è presente. A quel tempo non avevano ancora un proprio data center a Hong Kong.
La regione più vicina risultò essere asia-east1 (Taiwan). La regione più vicina di Ali alla Cina continentale rispetto a Taiwan risultò essere cn-shenzhen (Shenzhen).
Utilizzando terraform Abbiamo descritto e lanciato l'intera infrastruttura in GCP e Ali. Il tunnel di 100 Mbps tra i cloud è stato attivato praticamente istantaneamente. Dalla parte di Shenzhen e Taiwan sono state attivate macchine virtuali di proxy. A Shenzhen il traffico degli utenti viene terminato, proxyizzato attraverso il tunnel verso Taiwan, e da lì va direttamente all'IP esterno del nostro servizio in us-east (Costa orientale degli Stati Uniti). Il ping tra le macchine virtuali attraverso il tunnel è di 24 ms, che non è poi così male.
Contemporaneamente, abbiamo posizionato un'area di test in Alibaba Cloud DNS. Dopo aver delegato l'area a NS Ali, il tempo di risoluzione è sceso da 470 ms a 50 ms. Prima di ciò, l'area era anche su Cloudflare.
Parallelamente al tunnel verso asia-east1 abbiamo attivato un altro tunnel da Shenzhen direttamente in us-east4. Hanno creato ulteriori virtual machine proxy e hanno iniziato a misurare entrambe le soluzioni, instradando il traffico di test tramite Cookies o DNS. Lo schema del banco di prova è descritto nel seguente disegno:
La latenza dei tunnel è risultata la seguente:
Ali cn-shenzhen GCP asia-east1 — 24ms
Ali cn-shenzhen GCP us-east4 — 200ms
I test del browser Catchpoint hanno riportato un ottimo miglioramento delle prestazioni.
Confronta i risultati dei test per le due soluzioni:
Soluzione
Uptime
Mediana
75 Percentile
95 Percentile
75 Percentile
86.6
18s
30s
60s
IPsec
99.79
18s
21s
30s
Questi sono i dati della soluzione che utilizza un tunnel IPSEC attraverso asia-east1. I risultati tramite us-east4 sono stati peggiori e ci sono stati più errori, quindi non li presenterò.
Dai risultati di questo test sui due tunnel, uno dei quali termina nella regione più vicina alla Cina e l'altro nel punto di destinazione finale, è emerso chiaramente che è importante 'emergere' il prima possibile dal firewall cinese e poi utilizzare reti veloci (fornitori di CDN, fornitori di cloud, ecc.). Non è necessario tentare di superare il firewall in un colpo solo e arrivare al punto di destinazione. Non è il percorso più veloce.
In generale, i risultati sono buoni, tuttavia, su semrush.com la mediana è di 8.8s, e il 75° percentile è di 9.4s (sullo stesso test).
E prima di andare avanti, vorrei fare una piccola digressione.
Divagazione lirica
Dopo che l'utente accede al sito www.semrushchina.cn, che viene risolto tramite 'veloci' server DNS cinesi, la richiesta HTTP passa attraverso la nostra soluzione veloce. La risposta torna lungo lo stesso percorso, ma in tutti gli script JS, pagine HTML e altri elementi della pagina web è indicato il dominio semrush.com per risorse aggiuntive che devono essere caricate durante il rendering della pagina. Quindi il client risolve il record A 'principale' www.semrushchina.cn e entra nel tunnel veloce, ricevendo rapidamente la risposta — la pagina HTML, in cui è indicato:
- scarica il js da sso.semrush.com,
- prendi i file CSS da cdn.semrush.com,
- e prendi anche le immagini da dab.semrush.com
- e così via.
Il browser inizia a navigare nel 'mondo esterno' per queste risorse, passando ogni volta attraverso il firewall che consuma tempo di risposta.
Ma nel test precedente sono stati presentati i risultati quando nella pagina non ci sono risorse semrush.com, solo semrushchina.cn, e *.semrushchina.cn si risolve nell'indirizzo della virtual machine a Shenzhen, per poi entrare nel tunnel.
Solo in questo modo, massimizzando tutto il traffico possibile attraverso la nostra soluzione di bypass del firewall cinese, è possibile ottenere velocità accettabili e tassi di disponibilità del sito, oltre a risultati onesti nei test delle soluzioni.
Lo abbiamo fatto senza una sola modifica del codice lato prodotti dei team.
Subfilter
La soluzione è emersa praticamente immediatamente dopo che il problema è diventato evidente. Avevamo bisogno di PoC (Proof of Concept), che le nostre soluzioni di bypass del firewall funzionassero davvero bene. A tal fine, dovevamo massimizzare il wrapping di tutto il traffico del sito in questa soluzione. E abbiamo applicato in nginx.
Subfilter È un modulo abbastanza semplice in nginx, che consente di sostituire una stringa nel corpo della risposta con un'altra stringa. Così abbiamo sostituito tutte le occorrenze semrush.com in semrushchina.cn in tutte le risposte.
E… non ha funzionato, perché dai backend ricevevamo contenuti compressi, quindi subfilter non trovava la stringa necessaria. Abbiamo dovuto aggiungere un altro server locale in nginx, che decomprimeva la risposta e la trasmetteva al successivo server locale, che si occupava della sostituzione della stringa, della compressione e della restituzione al prossimo server proxy nella catena.
Di conseguenza, dove il cliente avrebbe ottenuto .semrush.com, riceveva .semrushchina.cn e procedeva diligentemente attraverso la nostra soluzione.
Tuttavia, non è sufficiente cambiare semplicemente il dominio in una direzione, poiché i backend continuano ad aspettarsi semrush.com nelle richieste successive del cliente. Di conseguenza, sullo stesso server, dove avviene la sostituzione in una direzione, utilizziamo una semplice espressione regolare per ottenere il sottodominio dalla richiesta e poi facciamo proxy_pass con la variabile $host, impostata su $subdomain.semrush.com. Potrebbe sembrare complicato, ma funziona. E funziona bene. Per domini specifici che richiedono una logica diversa, vengono semplicemente creati i propri blocchi server e viene effettuata una configurazione separata. Di seguito sono presentate configurazioni nginx abbreviate per illustrare e dimostrare questo schema.
La configurazione seguente gestisce tutte le richieste dalla Cina a .semrushchina.cn:
ascolta 80;
server_name ~^(?<subdomain>[w-]+).semrushchina.cn$;
sub_filter '.semrush.com' '.semrushchina.cn';
sub_filter_last_modified on;
sub_filter_once off;
sub_filter_types *;
gzip on;
gzip_proxied any;
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript;
location / {
proxy_pass http://127.0.0.1:8083;
proxy_set_header Accept-Encoding "";
proxy_set_header Host $subdomain.semrush.com;
proxy_set_header X-Accept-Encoding $http_accept_encoding;
}
}Questo config fa da proxy su localhost alla porta 83, e lì aspetta il prossimo config:
ascolta 127.0.0.1:8083;
server_name *.semrush.com;
location / {
resolver 8.8.8.8 ipv6=off;
gunzip on;
proxy_pass https://$host;
proxy_set_header Accept-Encoding gzip;
}
}Ripeto, questi sono config ridotti.
Circa così. Può sembrare complicato, ma a parole. In realtà è tutto più semplice di quanto si pensi 🙂
Fine della digressione poetica
Per un certo periodo siamo stati felici, perché il mito dei tunnel IPSEC in caduta non si è confermato. Ma poi i tunnel hanno iniziato a cadere. Diverse volte al giorno per alcuni minuti. Pochissimo, ma non ci andava bene. Poiché entrambi i tunnel terminavano sul lato Ali su un solo router, abbiamo pensato che potesse essere un problema regionale e che fosse necessario attivare un'area di emergenza.
Lo abbiamo fatto. I tunnel hanno iniziato a cadere a tempi diversi, ma il failover a livello upstream in nginx funzionava perfettamente. Ma poi i tunnel hanno iniziato a cadere più o meno contemporaneamente 🙂 E sono ricominciati gli errori 502 e 504. L'uptime ha iniziato a peggiorare, quindi abbiamo iniziato a lavorare su un'opzione con Alibaba CEN (Cloud Enterprise Network).
CEN
CEN — è la connettività tra due VPC di diverse regioni all'interno di Alibaba Cloud, cioè è possibile collegare reti private di qualsiasi regione all'interno del cloud tra loro. E cosa più importante: questo canale ha requisiti piuttosto severi SLA. È molto stabile sia in termini di velocità, sia di uptime. Ma non è mai così semplice:
- è MOLTO difficile ottenerlo, se non si è cittadini cinesi o entità legali,
- dove è necessario pagare per ogni megabit di larghezza di banda del canale.
Avendo ottenuto la possibilità di collegare Mainland China e Overseas, abbiamo creato un CEN tra due regioni di Ali: cn-shenzhen e us-east-1 (il punto più vicino a us-east4). In Ali us-east-1 abbiamo attivato un'altra macchina virtuale, per avere un ulteriore hop.
Risultato:
I risultati dei test del browser sono qui sotto:
Soluzione
Uptime
Mediana
75 Percentile
95 Percentile
75 Percentile
86.6
18s
30s
60s
IPsec
99.79
18s
21s
30s
CEN
99.75
16s
21s
27s
Le prestazioni sono leggermente migliori di quelle di IPSEC. Ma tramite IPSEC potenzialmente si possono scaricare a 100 mbit/s, mentre tramite CEN solo con una velocità di 5 mbit/s e più costoso.
Serve un ibrido, giusto? Unire la velocità di IPSEC e la stabilità di CEN.
Così abbiamo proceduto, permettendo il traffico sia tramite IPSEC che tramite CEN in caso di caduta del tunnel IPSEC. L'uptime è diventato molto più alto, ma la velocità di caricamento del sito lasciava ancora a desiderare. Allora ho disegnato tutti gli schemi che avevamo già utilizzato e testato, e ho deciso di provare ad aggiungere a questo schema un po' di GCP, vale a dire GLB.
GLB
GLB è (o Google Cloud Load Balancer). Ha un vantaggio importante per noi: nel contesto del CDN ha anycast IP, che permette di instradare il traffico verso il data center più vicino al cliente, il che consente al traffico di entrare più rapidamente nella rete veloce di Google e di percorrere meno strada sulla ‘normale’ internet.
Non ci abbiamo pensato a lungo, abbiamo attivato HTTP/HTTPS LB in GCP e come backend abbiamo impostato le nostre macchine virtuali con subfilter.
C'erano diversi schemi:
- di utilizzare Cloudflare China Network, ma stavolta come Origin abbiamo indicato il globale IP GLB.
- Terminare i clienti in cn-shenzhen, e da lì fare un proxy del traffico direttamente in GLB.
- Andare direttamente dalla Cina a GLB.
- Terminare i clienti in cn-shenzhen, da lì fare un proxy in asia-east1 tramite IPSEC (in us-east4 tramite CEN), da lì andare a GLB (tranquillo, in fondo ci sarà un’immagine e una spiegazione)
Abbiamo testato tutte queste opzioni e anche alcune soluzioni ibride:
- Cloudflare + GLB
Questo schema non ci ha soddisfatti per quanto riguarda l'uptime e gli errori DNS. Ma il test è stato effettuato prima della correzione del bug da parte di CF, forse ora è migliorato (tuttavia, questo non esclude i timeout HTTP).
- Ali + GLB
Anche questo schema non ci ha soddisfatti per quanto riguarda l'uptime, poiché GLB spesso cadeva dall'upstream a causa dell'impossibilità di connettersi in un tempo accettabile o a causa di timeout, dato che per il server all'interno della Cina l'indirizzo GLB rimane all’esterno, e quindi oltre il firewall cinese. Non è successa alcuna magia.
- GLB only
Un'opzione simile alla precedente, solo che in essa non sono stati utilizzati server nella Cina stessa: il traffico andava direttamente a GLB (abbiamo cambiato le voci DNS). Di conseguenza, i risultati non ci hanno soddisfatti, poiché per i normali clienti cinesi che utilizzano i servizi dei normali provider internet, la situazione con il superamento del firewall è molto peggiore rispetto a Ali Cloud.
- Shenzhen -> (CEN/IPSEC) -> Proxy -> GLB
Qui abbiamo deciso di utilizzare il meglio di tutte le soluzioni:
- stabilità e SLA garantito da CEN
- alta velocità da IPSEC
- la rete ‘veloce’ di Google e il suo anycast.
Lo schema appare circa così: il traffico degli utenti viene terminato su una macchina virtuale in ch-shenzhen. Lì sono configurati gli upstream di nginx, alcuni dei quali fanno riferimento a server con IP privati, situati all'altro capo del tunnel IPSEC, mentre altri upstream rimandano a indirizzi privati di server dall'altra parte del CEN. L'IPSEC è stato configurato nella regione asia-east1 in GCP (era la regione più vicina alla Cina al momento della creazione della soluzione. Ora GCP ha anche una presenza a Hong Kong). CEN — nella regione us-east1 in Ali Cloud.
Successivamente, il traffico proveniente da entrambe le estremità è stato indirizzato a anycast IP GLB, cioè al punto di presenza più vicino di Google, e procede attraverso le sue reti verso la regione us-east4 in GCP, in cui erano configurate le macchine virtuali di sostituzione (con subfilter in nginx).
Questa soluzione ibrida, come ci aspettavamo, ha permesso di sfruttare i vantaggi di ogni tecnologia. Nel complesso, il traffico passa attraverso un IPSEC veloce, ma se sorgono problemi, possiamo rapidamente escludere questi server dagli upstream per alcuni minuti e indirizzare il traffico solo attraverso il CEN, finché il tunnel non si stabilizza.
Implementando la quarta soluzione dell'elenco sopra, abbiamo raggiunto ciò che volevamo e ciò che l'azienda richiedeva in quel momento.
I risultati dei test del browser per la nuova soluzione rispetto alle precedenti:
Soluzione
Uptime
Mediana
75 Percentile
95 Percentile
75 Percentile
86.6
18s
30s
60s
IPsec
99.79
18s
21s
30s
CEN
99.75
16s
21s
27s
CEN/IPsec + GLB
99.79
13s
16s
25s
CDN
Nella soluzione che abbiamo implementato va tutto bene, tranne che non c'è un CDN che possa accelerare il traffico a livello di regioni e persino di città. In teoria, questo dovrebbe velocizzare il funzionamento del sito per gli utenti finali grazie all'uso di canali veloci forniti dal CDN. E noi ci abbiamo pensato costantemente. Ed ecco, è giunto il momento della prossima iterazione del progetto: ricerca e test dei fornitori di CDN in Cina.
E di questo vi parlerò nella prossima e ultima parte 🙂
Fonte: habr.com
