Come abbiamo superato il Grande Firewall Cinese (parte 2)

Ciao!

Sono di nuovo Nikita, ingegnere di sistema dell'azienda SEMrush. Con questo articolo continuo la storia su come abbiamo sviluppato una soluzione per eludere il Firewall cinese per il nostro servizio semrush.com.

In parte precedente Ho raccontato:

  • quali problemi sorgono dopo la decisione "Dobbiamo fare in modo che il nostro servizio funzioni in Cina"
  • quali problemi presenta Internet in Cina
  • perché è necessaria una licenza ICP
  • come e perché abbiamo deciso di testare i nostri ambienti di test utilizzando Catchpoint
  • quali risultati ci ha fornito la nostra prima soluzione basata sulla Cloudflare China Network
  • come abbiamo trovato un bug nel DNS di Cloudflare

Questa parte è, a mio avviso, la più interessante perché si concentra su specifiche implementazioni tecniche dei nostri stadi. E iniziamo, o piuttosto continuiamo, con Alibaba Cloud.

Alibaba Cloud

Alibaba Cloud — un fornitore di cloud piuttosto ampio, che dispone di tutti i servizi che gli consentono di definirsi un cloud provider. È positivo che gli utenti stranieri possano registrarsi e che gran parte del sito sia tradotto in inglese (un lusso per la Cina). In questo cloud è possibile lavorare in molte regioni del mondo, della Cina continentale e anche dell'Asia Oceania (Hong Kong, Taiwan, ecc.).

IPSEC

Abbiamo iniziato con la geografia. Poiché il sito di prova si trovava in Google Cloud, era necessario “collegare” Alibaba Cloud a GCP, quindi abbiamo aperto l'elenco delle località in cui era presente Google. In quel momento non avevano ancora il loro data center a Hong Kong.
La regione più vicina era asia-east1 (Taiwan). La regione più vicina di Ali alla Cina continentale rispetto a Taiwan era cn-shenzhen (Shenzhen).

Con terraform abbiamo descritto e attivato tutta l'infrastruttura in GCP e Ali. Un tunnel da 100 Mbit/s tra i cloud si è alzato praticamente all'istante. Dal lato di Shenzhen e Taiwan, sono state attivate delle macchine virtuali proxy. A Shenzhen, il traffico utente viene terminato, viene proxyizzato attraverso il tunnel verso Taiwan, e da lì si dirige direttamente verso l'IP pubblico del nostro servizio in us-east (Costa orientale degli Stati Uniti). Ping tra le virtual machine tramite tunnel 24 ms, il che non è male.

Abbiamo anche creato una zona di test in Alibaba Cloud DNS. Dopo aver delegato la zona a NS Ali, il tempo di risoluzione è sceso da 470 ms a 50 ms. Prima di ciò, la zona era anch'essa su Cloudflare.

Parallelamente al tunnel verso asia-east1 abbiamo creato un altro tunnel da Shenzhen direttamente in us-east4. Lì abbiamo creato ulteriori virtual machine proxy e iniziato a misurare entrambe le soluzioni, instradando il traffico di test tramite Cookies o DNS. Schema del banco di test è descritto nella figura successiva:

La latenza per i tunnel è stata la seguente:
Ali cn-shenzhen <—> GCP asia-east1 — 24 ms
Ali cn-shenzhen GCP us-east4 — 200ms

I test del browser di Catchpoint hanno riportato un'eccellente miglioramento delle prestazioni.

Confronta i risultati dei test per le due soluzioni:

Soluzione
Tempo di attività
Mediana
75° Percentile
95° Percentile

Cloudflare
86.6
18s
30s
60s

IPsec
99.79
18s
21s
30s

Questi sono i dati della soluzione che utilizza tunneling IPSEC tramite asia-east1. Tramite us-east4 i risultati erano peggiori e ci sono stati più errori, quindi non fornirò i dati.

Dai risultati di questo test di due tunnel, uno dei quali termina nella regione più vicina alla Cina e l'altro nella destinazione finale, è emerso chiaramente che è fondamentale "emergere" rapidamente dal firewall cinese e poi utilizzare reti veloci (fornitori CDN, fornitori di cloud, ecc.). Non bisogna cercare di attraversare il firewall in un colpo solo e arrivare alla destinazione. Quella non è la via più veloce.

In generale, i risultati sono buoni, tuttavia, su semrush.com la mediana è di 8.8s e il 75° percentile è di 9.4s (nello stesso test).
E prima di proseguire, vorrei fare una piccola digressione.

Divagazione lirica

Dopo che l'utente accede al sito www.semrushchina.cn, che viene risolto tramite server DNS cinesi "veloci", la richiesta HTTP passa attraverso la nostra soluzione veloce. La risposta torna lungo lo stesso percorso, ma in tutti gli script JS, nelle pagine HTML e in altri elementi della pagina web è indicato il dominio semrush.com per risorse aggiuntive che devono essere caricate durante il rendering della pagina. Quindi il cliente risolve il record A "principale" www.semrushchina.cn e va nel tunnel veloce, ricevendo rapidamente la risposta — la pagina HTML che indica:

  • 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 collegarsi a Internet "esterno" per queste risorse, passando ogni volta attraverso un firewall che consuma tempo di risposta.

Ma nel test precedente sono stati presentati i risultati quando sulla pagina non ci sono risorse semrush.com, solo semrushchina.cn, mentre *.semrushchina.cn si risolve in un indirizzo virtuale a Shenzhen, per poi passare attraverso il tunnel.

Solo in questo modo, massimizzando tutto il traffico possibile attraverso la nostra soluzione per il passaggio rapido del firewall cinese, è possibile ottenere velocità e metriche di disponibilità accettabili, nonché risultati onesti nei test delle soluzioni.
Abbiamo realizzato questo senza alcuna modifica del codice da parte dei team di prodotto.

Subfilter

La soluzione è emersa praticamente subito dopo che è emerso questo problema. Avevamo bisogno di un PoC (Proof of Concept), che le nostre soluzioni per il passaggio del firewall funzionassero davvero bene. Per questo è necessario massimizzare il totale del traffico del sito in questa soluzione. E abbiamo applicato subfilter in nginx.

Subfilter — è un modulo piuttosto semplice in nginx che permette di sostituire una riga nel corpo della risposta con un'altra riga. Abbiamo sostituito tutte le occorrenze semrush.com con semrushchina.cn in tutte le risposte.

E… non ha funzionato, perché ricevevamo contenuti compressed dai backend, quindi il subfilter non trovava la riga necessaria. Abbiamo dovuto aggiungere un altro server locale in nginx, che decomprimesse la risposta e la inoltrasse al successivo server locale, che si occupava della sostituzione della riga, della compressione e della trasmissione al prossimo server proxy nella catena.

Alla fine, dove il cliente riceveva .semrush.com, riceveva .semrushchina.cn e passava attraverso la nostra soluzione.

Tuttavia, non è sufficiente semplicemente cambiare il dominio in un'unica direzione, poiché i backend si aspettano ancora semrush.com nelle richieste successive dal cliente. Pertanto, sullo stesso server dove avviene il cambio in una direzione, utilizzando una semplice espressione regolare, otteniamo 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 i singoli domini che richiedono una logica diversa, è sufficiente creare i propri blocchi server e fare una configurazione separata. Di seguito sono riportate configurazioni nginx abbreviate per chiarezza e dimostrazione di questo schema.

La seguente configurazione gestisce tutte le richieste dalla Cina su .semrushchina.cn:

    listen 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;
    }
}

Questa configurazione fa proxy su localhost sulla porta 83, dove aspetta la seguente configurazione:

    listen 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, queste sono configurazioni abbreviate.

Circa così. Può sembrare complesso, ma è solo a parole. In realtà, è tutto più semplice di quanto si possa pensare 🙂

Fine della digressione

Per un certo periodo abbiamo vissuto felici, perché il mito dei tunnel IPSEC che cadevano non si era avverato. Ma poi i tunnel hanno iniziato a cadere. Diverse volte al giorno per alcuni minuti. Poco, ma non ci soddisfaceva. 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 il backup della regione.

L'abbiamo attivato. I tunnel hanno iniziato a cadere in momenti diversi, ma il failover a livello upstream in nginx funzionava perfettamente. Poi i tunnel hanno cominciato a cadere quasi simultaneamente 🙂 E sono riprese le 502 e 504. L'uptime ha iniziato a peggiorare, quindi abbiamo iniziato a considerare la soluzione con Alibaba CEN (Cloud Enterprise Network).

CEN

CEN è la connettività di due VPC di diverse regioni all'interno di Alibaba Cloud, il che significa che è possibile collegare le reti private di qualsiasi regione all'interno del cloud tra loro. E la cosa più importante: questo canale ha requisiti piuttosto severi SLA. È molto stabile sia in termini di velocità che di uptime. Ma non è mai tutto così semplice:

  • è MOLTO difficile ottenerlo, se non si è cittadini o entità legali cinesi,
  • e bisogna pagare per ogni megabit di larghezza di banda del canale.

Ottenendo la possibilità di connettere Mainland China e Overseas, abbiamo creato CEN tra due regioni Ali: cn-shenzhen e us-east-1 (il punto più vicino a us-east4). In Ali us-east-1 abbiamo sollevato un'altra virtual machine, in modo da avere un'altra hop.

Ecco cosa è successo:

I risultati dei test del browser sono riportati sotto:

Soluzione
Tempo di attività
Mediana
75° Percentile
95° Percentile

Cloudflare
86.6
18s
30s
60s

IPsec
99.79
18s
21s
30s

CEN
99.75
16s
21s
27s

Le prestazioni sono leggermente migliori rispetto a IPSEC. Ma tramite IPSEC è potenzialmente possibile scaricare a una velocità di 100 Mbit/s, mentre tramite CEN solo a 5 Mbit/s e a un costo maggiore.

Sembra un ibrido, giusto? Unire la velocità di IPSEC e la stabilità di CEN.

Così abbiamo fatto, indirizzando il traffico sia attraverso IPSEC che attraverso CEN in caso di caduta del tunnel IPSEC. L'uptime è diventato molto più elevato, 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 un po' di GCP a questo schema, in particolare GLB.

GLB

GLB — rappresenta Global Load Balancer (o Google Cloud Load Balancer). Ha un vantaggio importante per noi: nel contesto del CDN ha IP anycast, che consente di instradare il traffico nel data center più vicino al cliente, grazie al quale il traffico ottiene più rapidamente l'accesso alla rapida rete Google e percorre meno “internet normale”.

Senza pensarci su, abbiamo attivato HTTP/HTTPS LB in GCP e abbiamo impostato i nostri VM come backend con subfilter.

Ci sono stati diversi schemi:

  • Usa Cloudflare China Network, ma questa volta specificare a livello globale con Origin IP GLB.
  • Terminare i clienti in cn-shenzhen, e da lì indirizzare il traffico direttamente a GLB.
  • Andare direttamente dalla Cina a GLB.
  • Terminare i clienti in cn-shenzhen, da lì inoltrare a asia-east1 attraverso IPSEC (in us-east4 attraverso CEN), da lì già andare a GLB (tranquillo, in basso ci sarà un'immagine e una spiegazione)

Abbiamo testato tutte queste opzioni e anche alcune ibride:

  • Cloudflare + GLB

Questo schema non ci ha soddisfatto per uptime e errori DNS. Ma il test è stato effettuato prima della correzione del bug da parte di CF, quindi potrebbe essere migliorato adesso (tuttavia, ciò non esclude i timeout HTTP).

  • Ali + GLB

Anche questo schema non ci ha soddisfatto per uptime, poiché GLB cadeva spesso dall'upstream a causa dell'impossibilità di connettersi in tempo utile o di timeout, visto che per il server all'interno della Cina l'indirizzo GLB rimane all'esterno, quindi dietro il firewall cinese. Non è successa alcuna magia.

  • Solo GLB

Opzione simile alla precedente, solo che non utilizzava server in Cina: il traffico andava direttamente a GLB (abbiamo modificato i record DNS). Di conseguenza, i risultati non sono stati soddisfacenti, poiché per i normali clienti cinesi che utilizzano fornitori di servizi internet comuni, la situazione con l'attraversamento 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
  • una rete 'veloce' di Google e il suo anycast.

Lo schema appare più o meno così: il traffico degli utenti termina su una macchina virtuale in ch-shenzhen. Lì sono configurati gli upstream di nginx, alcuni dei quali rimandano a server IP privati situati all'estremità opposta del tunnel IPSEC, mentre altri upstream rimandano a indirizzi privati di server dall'altra parte di CEN. L'IPSEC è stato configurato fino alla regione asia-east1 in GCP (era la regione più vicina alla Cina al momento della creazione della soluzione. Adesso GCP ha anche una presenza a Hong Kong). CEN — fino alla regione us-east1 in Ali Cloud.

Successivamente, il traffico da entrambe le estremità veniva diretto a anycast IP GLB, cioè al punto di presenza più vicino di Google, e usciva attraverso le sue reti nella regione us-east4 in GCP, dove si trovavano le macchine virtuali sostitutive (con subfilter in nginx).

Questa soluzione ibrida, come ci aspettavamo, ha permesso di sfruttare i vantaggi di ciascuna tecnologia. In generale, il traffico passa attraverso un veloce IPSEC, ma se sorgono problemi, rimuoviamo rapidamente e per alcuni minuti questi server dagli upstream e inviamo il traffico solo attraverso CEN, finché il tunnel non si stabilizza.

Implementando la quarta soluzione dalla lista sopra, abbiamo raggiunto ciò che volevamo e ciò che ci richiedeva il business in quel momento.

Risultati dei test del browser per la nuova soluzione rispetto alle precedenti:

Soluzione
Tempo di attività
Mediana
75° Percentile
95° Percentile

Cloudflare
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

fornitore di CDN). Monitorano il loro

Nella soluzione che abbiamo implementato va tutto bene, solo che manca un CDN che possa accelerare il traffico a livello regionale e persino cittadino. In teoria, questo dovrebbe velocizzare il funzionamento del sito per gli utenti finali utilizzando canali di comunicazione rapidi del fornitore di CDN. E noi ci abbiamo sempre pensato. Ed ecco, è arrivato il momento della prossima iterazione del progetto: ricerca e test di fornitori di CDN in Cina.

E di questo parlerò nella prossima, conclusiva parte 🙂

Fonte: habr.com

Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server 🔥 Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server | ProHoster