Hur vi bröt igenom Kinas stora brandvägg (del 2)

Hälsningar!

Nikita är med dig igen, en systemingenjör från företaget SEMrush. Och med den här artikeln fortsätter jag historien om hur vi kom fram till en lösning Kinesisk brandvägg för vår tjänst semrush.com.

В föregående del Jag sade:

  • vilka problem uppstår efter beslutet "Vi måste få vår service att fungera i Kina"
  • Vilka problem har det kinesiska Internet?
  • varför behöver du en ICP-licens?
  • hur och varför vi bestämde oss för att testa våra testbäddar med Catchpoint
  • vad var resultatet av vår första lösning baserad på Cloudflare China Network
  • Hur vi hittade en bugg i Cloudflare DNS

Den här delen är den mest intressanta, enligt min mening, eftersom den fokuserar på specifika tekniska implementeringar av iscensättning. Och vi kommer att börja, eller snarare fortsätta, med Alibaba Cloud.

Alibaba Cloud

Alibaba Cloud är en ganska stor molnleverantör, som har alla tjänster som gör att den ärligt talat kan kalla sig en molnleverantör. Det är bra att de har möjlighet att registrera sig för utländska användare, och att det mesta av sajten är översatt till engelska (för Kina är detta en lyx). I detta moln kan du arbeta med många regioner i världen, Kina, såväl som Oceanic Asien (Hong Kong, Taiwan, etc.).

IPSEC

Vi började med geografi. Eftersom vår testsida fanns på Google Cloud behövde vi "länka" Alibaba Cloud till GCP, så vi öppnade en lista över platser där Google finns. I det ögonblicket hade de ännu inte ett eget datacenter i Hong Kong.
Den närmaste regionen visade sig vara asien-öst 1 (Taiwan). Ali visade sig vara den region på det kinesiska fastlandet som ligger närmast Taiwan cn-shenzhen (Shenzhen).

Med terraform beskrev och höjde hela infrastrukturen i GCP och Ali. En 100 Mbit/s tunnel mellan molnen gick upp nästan omedelbart. På sidan av Shenzhen och Taiwan togs upp virtuella maskiner med proxy. I Shenzhen avslutas användartrafiken, proxias genom en tunnel till Taiwan, och därifrån går den direkt till vår tjänsts externa IP i oss-öst (USA:s östkust). Pinga mellan virtuella maskiner via tunnel 24ms, vilket inte är så illa.

Samtidigt placerade vi ett testområde i Alibaba Cloud DNS. Efter att ha delegerat zonen till NS Ali minskade upplösningstiden från 470 ms till 50 ms. Innan detta låg zonen även på Cloudlfare.

Parallellt med tunneln till asien-öst 1 höjde ytterligare en tunnel från Shenzhen direkt till oss-öst4. Där skapade de fler virtuella proxymaskiner och började testa båda lösningarna, dirigera testtrafik med hjälp av cookies eller DNS. Testbänken beskrivs schematiskt i följande figur:

Latensen för tunnlar visade sig vara följande:
Ali cn-shenzhen <—> GCP asia-east1 — 24ms
Ali cn-shenzhen <—> GCP us-east4 — 200ms

Catchpoint webbläsartester rapporterade utmärkta förbättringar.

Jämför testresultat för två lösningar:

beslutet
Uptime
median
75 Percentil
95 Percentil

CloudFlare
86.6
18s
30s
60s

IPsec
99.79
18s
21s
30s

Detta är data från en lösning som använder en IPSEC-tunnel via asien-öst 1. Genom us-east4 var resultaten sämre, och det fanns fler fel, så jag kommer inte att ge resultaten.

Baserat på resultaten av detta test av två tunnlar, varav den ena avslutas i den närmaste regionen till Kina, och den andra vid slutdestinationen, blev det klart att det är viktigt att "uppstå" under den kinesiska brandväggen så snabbt som möjligt, och använd sedan snabba nätverk (CDN-leverantörer, molnleverantörer, etc.). Det finns ingen anledning att försöka ta sig igenom brandväggen och ta sig till din destination i ett svep. Detta är inte det snabbaste sättet.

Generellt sett är resultaten inte dåliga, men semrush.com har en median på 8.8 s och 75 Percentile 9.4 s (på samma test).
Och innan jag går vidare vill jag göra en kort lyrisk utvikning.

Lyrisk utvikning

Efter att användaren går in på webbplatsen www.semrushchina.cn, som löser sig genom "snabba" kinesiska DNS-servrar, går HTTP-förfrågan genom vår snabba lösning. Svaret returneras längs samma väg, men domänen anges i alla JS-skript, HTML-sidor och andra element på webbsidan semrush.com för ytterligare resurser som måste laddas när sidan renderas. Det vill säga, klienten löser den "huvudsakliga" A-posten www.semrushchina.cn och går in i den snabba tunneln, får snabbt ett svar - en HTML-sida som säger:

  • ladda ner sådana och sådana js från sso.semrush.com,
  • Hämta CSS-filerna från cdn.semrush.com,
  • och ta även några bilder från dab.semrush.com
  • och så vidare.

Webbläsaren börjar gå till det "externa" Internet för dessa resurser, varje gång den passerar genom en brandvägg som äter upp svarstiden.

Men det tidigare testet visar resultaten när det inte finns några resurser på sidan semrush.combara semrushchina.cn, och *.semrushchina.cn löser sig till adressen till den virtuella maskinen i Shenzhen för att sedan komma in i tunneln.

Endast på detta sätt, genom att driva all möjlig trafik till det maximala genom din lösning för att snabbt passera den kinesiska brandväggen, kan du få acceptabla hastigheter och webbplatstillgänglighetsindikatorer, såväl som ärliga resultat av lösningstester.
Vi gjorde detta utan en enda kodredigering på teamets produktsida.

Subfilter

Lösningen föddes nästan omedelbart efter att detta problem uppstod. Vi behövde PoC (Proof of Concept) att våra lösningar för brandväggspenetration verkligen fungerar bra. För att göra detta måste du lägga in all webbplatstrafik i den här lösningen så mycket som möjligt. Och vi ansökte underfilter i nginx.

Subfilter är en ganska enkel modul i nginx som låter dig ändra en rad i svarskroppen till en annan rad. Så vi ändrade alla händelser semrush.comsemrushchina.cn i alla svar.

Och... det fungerade inte eftersom vi fick komprimerat innehåll från backends, så underfiltret hittade inte den önskade raden. Jag var tvungen att lägga till en annan lokal server till nginx, som dekomprimerade svaret och skickade det vidare till nästa lokala server, som redan var upptagen med att ersätta strängen, komprimera den och skicka den till nästa proxyserver i kedjan.

Som ett resultat, var skulle kunden ta emot .semrush.com, han fick .semrushchina.cn och gick lydigt igenom vårt beslut.

Det räcker dock inte att bara byta domän på ett sätt, eftersom backends fortfarande förväntar sig semrush.com i efterföljande förfrågningar från klienten. Följaktligen, på samma server där envägsersättningen görs, med ett enkelt reguljärt uttryck får vi subdomänen från begäran, och sedan gör vi proxy_pass med variabel $ värd, utställd i $subdomain.semrush.com. Det kan verka förvirrande, men det fungerar. Och det fungerar bra. För enskilda domäner som kräver annan logik, skapa helt enkelt dina egna serverblock och gör en separat konfiguration. Nedan finns förkortade nginx-konfigurationer för klarhet och demonstration av detta schema.

Följande konfiguration behandlar alla förfrågningar från Kina till .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;
    }
}

Denna konfiguration proxar till lokalvärd till port 83, och följande konfiguration väntar där:

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

Jag upprepar, dessa är beskurna konfigurationer.

Sådär. Det kan se komplicerat ut, men det är i ord. Faktum är att allt är enklare än ångad kålrot :)

Slutet på utvikningen

Ett tag var vi glada eftersom myten om fallande IPSEC-tunnlar inte bekräftades. Men sedan började tunnlarna falla. Flera gånger om dagen i några minuter. Lite, men det passade inte oss. Eftersom båda tunnlarna avslutades på Ali-sidan på samma router bestämde vi oss för att detta kanske var ett regionalt problem och vi behövde höja reservregionen.

De plockade upp den. Tunnlarna började misslyckas vid olika tidpunkter, men failoveren fungerade bra för oss på uppströmsnivå i nginx. Men så började tunnlarna falla ungefär samtidigt 🙂 Och 502 och 504 började igen. Upptiden började försämras, så vi började jobba på alternativet med Alibaba CEN (Cloud Enterprise Network).

CEN

CEN - det här är anslutningen av två VPC:er från olika regioner inom Alibaba Cloud, det vill säga du kan ansluta privata nätverk i alla regioner i molnet med varandra. Och viktigast av allt: den här kanalen har en ganska strikt SLA. Den är väldigt stabil både i hastighet och drifttid. Men det är aldrig så enkelt:

  • det är MYCKET svårt att få om du inte är kinesisk medborgare eller en juridisk person,
  • Du måste betala för varje megabit kanalbandbredd.

Att ha möjlighet att ansluta Kinesiska fastlandet и Utomlands, skapade vi ett CEN mellan två Ali-regioner: cn-shenzhen и us-öst-1 (närmast punkt till us-east4). I Ali us-öst-1 höjt en annan virtuell maskin så att det finns en till hop.

Det blev så här:

Webbläsartestresultaten är nedan:

beslutet
Uptime
median
75 Percentil
95 Percentil

CloudFlare
86.6
18s
30s
60s

IPsec
99.79
18s
21s
30s

CEN
99.75
16s
21s
27s

Prestandan är något bättre än IPSEC. Men genom IPSEC kan du potentiellt ladda ner med en hastighet av 100 Mbit/s, och genom CEN endast med en hastighet av 5 Mbit/s och mer.

Låter som en hybrid, eller hur? Kombinera IPSEC-hastighet och CEN-stabilitet.

Detta är vad vi gjorde, och tillåtit trafik genom både IPSEC och CEN i händelse av ett fel på IPSEC-tunneln. Drifttiden har blivit mycket högre, men sajtens laddningshastighet lämnar fortfarande mycket övrigt att önska. Sedan ritade jag alla kretsar som vi redan använt och testat, och bestämde mig för att försöka lägga till lite mer GCP till denna krets, nämligen keps.

keps

keps - Är Global Load Balancer (eller Google Cloud Load Balancer). Det har en viktig fördel för oss: i samband med ett CDN har det anycast IP, vilket gör att du kan dirigera trafik till datacentret närmast klienten, så att trafik snabbt kommer in i Googles snabba nätverk och mindre går via det "vanliga" internet.

Utan att tänka två gånger höjde vi HTTP/HTTPS LB Vi installerade våra virtuella maskiner med subfilter i GCP och som backend.

Det fanns flera scheman:

  • Använd Cloudflare China Network, men den här gången bör Origin ange global IP GLB.
  • Avsluta kunder kl cn-shenzhen, och därifrån proxy trafiken direkt till keps.
  • Åk direkt från Kina till keps.
  • Avsluta kunder kl cn-shenzhen, därifrån proxy till asien-öst 1 via IPSEC (in oss-öst4 via CEN), därifrån gå till GLB (lugnt, det kommer en bild och förklaring nedan)

Vi testade alla dessa alternativ och flera fler hybrider:

  • Cloudflare + GLB

Detta schema passade inte oss på grund av drifttid och DNS-fel. Men testet utfördes innan buggen fixades på CF-sidan, kanske är det bättre nu (däremot utesluter detta inte HTTP-timeouts).

  • Ali + GLB

Detta schema passade inte heller oss när det gäller drifttid, eftersom GLB ofta föll utanför uppströmsströmmen på grund av omöjligheten att ansluta inom en acceptabel tid eller timeout, eftersom för en server i Kina förblir GLB-adressen utanför, och därför bakom Kinesisk brandvägg. Magin hände inte.

  • Endast GLB

Ett alternativ som liknar det tidigare, bara det använde inte servrar i själva Kina: trafiken gick direkt till GLB (DNS-posterna ändrades). Följaktligen var resultaten inte tillfredsställande, eftersom vanliga kinesiska kunder som använder tjänster från vanliga internetleverantörer har en mycket värre situation med att passera brandväggen än Ali Cloud.

  • Shenzhen -> (CEN/IPSEC) -> Proxy -> GLB

Här bestämde vi oss för att använda den bästa av alla lösningar:

  • stabilitet och garanterad SLA från CEN
  • hög hastighet från IPSEC
  • Googles "snabba" nätverk och dess anycast.

Schemat ser ut ungefär så här: användartrafik avslutas på en virtuell maskin i ch-shenzhen. Nginx uppströms konfigureras där, av vilka några pekar på privata IP-servrar som finns i andra änden av IPSEC-tunneln, och några uppströms pekar på privata adresser till servrar på andra sidan av CEN. IPSEC konfigurerad till region asien-öst 1 i GCP (var den region som låg närmast Kina vid den tidpunkt då lösningen skapades. GCP finns nu även i Hong Kong). CEN - till region oss-öst1 i Ali Cloud.

Då dirigerades trafik från båda ändarna till anycast IP GLB, det vill säga till närmaste närvaropunkt för Google, och gick genom dess nätverk till regionen oss-öst4 i GCP, där det fanns virtuella ersättningsmaskiner (med subfilter i nginx).

Denna hybridlösning utnyttjade, som vi förväntade oss, fördelarna med varje teknik. I allmänhet går trafiken genom snabba IPSEC, men om problem uppstår sparkar vi snabbt och under några minuter dessa servrar ut ur uppströmsströmmen och skickar trafik endast genom CEN tills tunneln stabiliseras.

Genom att implementera den fjärde lösningen från listan ovan uppnådde vi vad vi ville och vad verksamheten krävde av oss vid den tidpunkten.

Webbläsartestresultat för den nya lösningen jämfört med tidigare:

beslutet
Uptime
median
75 Percentil
95 Percentil

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

CDN

Allt är bra i den lösning vi implementerade, men det finns inget CDN som skulle kunna accelerera trafiken på regional och till och med stadsnivå. I teorin borde detta påskynda webbplatsen för slutanvändare genom att använda CDN-leverantörens snabba kommunikationskanaler. Och vi tänkte på det hela tiden. Och nu är det dags för nästa iteration av projektet: att söka och testa CDN-leverantörer i Kina.

Och jag kommer att berätta om detta i nästa, sista del :)

Källa: will.com

Lägg en kommentar