Здравейте!
Отново с вас е Никита — системен инженер от компанията SEMrush. С тази статия продължавам историята за това как измислихме решение за заобикаляне на Китайската стена на защита за нашия сервис semrush.com.
В Разказах:
- какви проблеми възникват след като бъде взето решението „Трябва да направим така, че нашият сервис да работи в Китай“
- какви проблеми има китайският интернет
- защо е нужна ICP лицензия
- как и защо решихме да тестваме нашите тестови среди с помощта на Catchpoint
- какъв резултат даде първият ни вариант на решение, базиран на Cloudflare China Network
- как открихме бъг в DNS на Cloudflare
Тази част е най-интригуваща, по мое мнение, защото се фокусира върху конкретни технически реализации на стейджингите. И ще започнем, или по-скоро ще продължим, с Alibaba Cloud.
Alibaba Cloud
Alibaba Cloud — доста голям облачен доставчик, който предлага всички услуги, позволяващи му честно да се нарича облачен доставчик. Добре е, че имат възможност чуждестранни потребители да се регистрират и че голяма част от сайта е преведена на английски (за Китай това е лукс). В това облако може да се работи с множество региони по света, континентален Китай, както и Тихоокеанска Азия (Хонконг, Тайван и т.н.).
IPSEC
Започнахме с географията. Тъй като тестовият сайт се намираше в Google Cloud, трябваше да “свържем” Alibaba Cloud с GCP, затова отворихме списък с локации, в които присъства Google. В онзи момент те все още нямахме свой дата център в Хонконг.
Най-близкият регион се оказа asia-east1 (Тайван). Най-близкият регион на Ali към континентален Китай, близо до Тайван, се оказа cn-shenzhen (Шенжен).
С помощта на terraform описахме и изградихме цялата инфраструктура в GCP и Ali. Тунел с капацитет 100 мбит/с между облаците беше създаден почти моментално. От страната на Шенжен и Тайван бяха изградени проксирующие виртуални машини. В Шенжен потребителският трафик се завършва, проксирова се през тунела до Тайван, откъдето вече отива директно до външния IP на нашия сервис в us-east (Източно крайбрежие на САЩ). Пингът между виртуалките по тунела е 24ms, което не е чак толкова зле.
В същото време създадохме тестова зона в Alibaba Cloud DNS. След делегирането на зоната на NS Ali, времето за резолвинг спадна от 470 ms на 50 ms. Преди това зоната също беше в Cloudlfare.
В паралел с тунела до asia-east1 изградихме още един тунел от Шенжен направо до us-east4. Там създадоха още прокси виртуални машини и започнаха да измерват и двете решения, маршрутизирайки тестовия трафик чрез Cookies или DNS. Схематично тестовият стенд е описан на следната рисунка:
Latencyn за тунелите е следната:
Ali cn-shenzhen GCP asia-east1 — 24ms
Ali cn-shenzhen GCP us-east4 — 200ms
Браузърните тестове Catchpoint съобщиха за отлично подобрение на показателите.
Сравнете резултатите от тестовете за двете решения:
Решение
Uptime
Медии
75 Перцентил
95 Перцентил
Cloudflare
86.6
18s
30s
60s
IPsec
99.79
18s
21s
30s
Това са данни от решението, използващо IPSEC тунел през asia-east1. През us-east4 резултатите бяха по-лоши, а грешките бяха повече, затова няма да предавам резултатите.
От резултатите на този тест на два тунела, един от които приключва в най-близкия регион до Китай, а другият в крайната дестинация, стана ясно, че е важно да „изкочим“ от китайската защитна стена възможно най-бързо и след това да използваме бързи мрежи (CDN доставчици, облачни доставчици и т.н.). Не трябва да се опитвате да преминете защитната стена и да достигнете дестинацията на едно движение. Това не е най-бързият път.
В общи линии, резултатите са добри, обаче, semrush.com има медиана 8.8s, а 75-ти процентил 9.4s (на същия тест).
И преди да продължим напред, бих искал да направя малко лирично отклонение.
Лирично отклонение
След като потребителят влезе в сайта www.semrushchina.cn, който се резолвира чрез „бързите“ китайски DNS сървъри, HTTP заявката минава през нашето бързо решение. Отговорът се връща по същия път, но във всичките JS скриптове, HTML страници и други елементи на уеб страницата е посочен домейнът semrush.com за допълнителни ресурси, които следва да бъдат заредени при рендериране на страницата. Тоест клиентът резолвира „главната“ А-запис www.semrushchina.cn и влиза в бърз тунел, бързо получава отговор — HTML страница, в която е посочено:
- свали такъв js от sso.semrush.com,
- CSS файлове вземи от cdn.semrush.com,
- и още вземи картинки от dab.semrush.com
- и така нататък.
Браузърът започва да търси в „външния“ интернет за тези ресурси, преминавайки всеки път през бавещата времето защитна стена.
Но в предишния тест са представени резултати, когато на страницата няма ресурси semrush.com, само semrushchina.cn, а *.semrushchina.cn се резолвира в адреса на виртуалната машина в Шенжен, за да попадне после в тунела.
Само така, максимално изпращайки целия възможен трафик през нашето решение за бързо преминаване на китайския фаервол, можем да получим приемливи скорости и показатели за достъпност на сайта, както и честни резултати от тестовете на решенията.
Направихме го без нито една корекция на кода отстрани на продуктите на екипите.
Subfilter
Решението се роди почти веднага след като възникна този проблем. Нуждаехме се от PoC (Доказателство за концепция), че нашите решения за преминаване през фаервола наистина работят добре. За това е нужно максимално да насочим целия трафик на сайта в това решение. И ние приложихме в nginx.
Subfilter — това е доста прост модул в nginx, който позволява да се замени една линия в тялото на отговора с друга линия. Ето защо ние заменихме всички срещания semrush.com на semrushchina.cn във всички отговори.
И… това не сработи, защото от бекендовете получавахме компресиран съдържание, следователно subfilter не намери нужната линия. Приключи се, че трябваше да добавим още един локален сървър в nginx, който раз comprimираше отговора и го предаваше на следващия локален сървър, който вече се занимаваше със замяната на линията, компресирането и предаването ѝ на следващия в веригата прокси-сървър.
В крайна сметка, където клиентът би получил .semrush.com, той получаваше .semrushchina.cn и внимателно преминаваше през нашето решение.
Обаче не е достатъчно просто да смените домейна в една посока, тъй като бекендовете все още очакват semrush.com в последващите заявки от клиента. Следователно, на същия сървър, където се извършва замяната в една посока, с помощта на простичко регулярно изразяване ние получаваме поддомейна от заявката, а след това правим proxy_pass с променливата $host, зададена на $subdomain.semrush.com. Може да изглежда объркващо, но това работи. И работи добре. За отделни домейни, изискващи друга логика, просто се създават свои сървърни блокове и се прави отделна конфигурация. По-долу са представени съкратени nginx конфигурации за ясност и демонстрация на тази схема.
Следващата конфигурация обработва всички заявки от Китай на .semrushchina.cn:
слушай 80;
server_name ~^(?[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;
}
}Тази конфигурация проксирва на localhost порт 83, а там поджида следната конфигурация:
слушай 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;
}
}Повтарям, това са съкратени конфигурации.
Приблизително така. Може да изглежда сложно, но на думи. На практика всичко е по-просто от парен зеле 🙂
Край на поетичната отсечка
Няколко време бяхме щастливи, защото мита за падащите IPSEC тунели не се потвърди. Но след това тунелите започнаха да падат. Няколко пъти на ден за няколко минути. Малко, но не ни удовлетворяваше. Тъй като и двата тунела се терминираха на страната на Ali на един рутер, решихме, че може би това е регионален проблем и трябва да активираме резервен регион.
Активирахме. Тунелите започнаха да падат по различно време, но фейловерът на нивото на upstream в nginx работеше прекрасно. Но след това тунелите започнаха да падат почти едновременно 🙂 И отново започнаха 502 и 504. Uptime стана по-лош, затова започнахме да работим над опцията с Alibaba CEN (Cloud Enterprise Network).
CEN
CEN — това е свързаността на две VPC от различни региони в рамките на Alibaba Cloud, което означава, че можете да свържете частни мрежи от всякакви региони в облака помежду си. И най-важното: този канал има доста строг SLA. Той е много стабилен както по скорост, така и по uptime. Но никога не е толкова просто:
- много е трудно да се получи, ако не сте китайски граждани или юридически лица,
- трябва да плащате за всеки мегабит пропускателна способност на канала.
Получавайки възможността да свържем Континентален Китай и Зад граница, създадохме CEN между два региона на Ali: cn-shenzhen и us-east-1 (най-близката точка до us-east4). В Ali us-east-1 създадохме още една виртуалка, за да има още едно hop.
Получиха се следните резултати:
Резултатите от тестовете в браузърите са по-долу:
Решение
Uptime
Медии
75 Перцентил
95 Перцентил
Cloudflare
86.6
18s
30s
60s
IPsec
99.79
18s
21s
30s
CEN
99.75
16s
21s
27s
Показателите са малко по-добри от тези на IPSEC. Но чрез IPSEC потенциално може да преминавате със скорост 100 мбит/с, а чрез CEN само със скорост 5 мбит/с и е по-скъпо.
Налага се хибрид, нали? Да съчетаем скоростта на IPSEC и стабилността на CEN.
Така и направихме, пускайки трафика както през IPSEC, така и през CEN в случай на падение на IPSEC тунела. Uptime стана значително по-висок, но скоростта на зареждане на сайта все още беше на приемливо ниво. Тогава нарисувах всички схеми, които вече използвахме и тествали, и реших да опитам да добавя в тази схема още малко GCP, а именно GLB.
GLB
GLB — това е (или Google Cloud Load Balancer). Той има важно предимство за нас: в контекста на CDN той anycast IP, което позволява маршрутизиране на трафика в най-близкия до клиента дата център, благодарение на което трафикът по-бързо достига до бързата мрежа на Google и по-малко преминава през "обикновения" интернет.
След кратко обмисляне, вдигнахме HTTP/HTTPS LB в GCP и в бекенда поставихме нашите виртуални сървъри с subfilter.
Имаше няколко схеми:
- Използвайте Cloudflare China Network, но този път Origin’ът трябваше да зададе глобалния IP GLB.
- Да терминираме клиентите в cn-shenzhen, а оттам да проксираме трафика директно в GLB.
- Да идем директно от Китай до GLB.
- Да терминираме клиентите в cn-shenzhen, оттам да проксираме в asia-east1 през IPSEC (в us-east4 през CEN), оттам вече да идем в GLB (не се притеснявайте, по-долу ще има изображение и обяснение)
Тестахме всички тези варианти и още няколко хибридни:
- Cloudflare + GLB
Тази схема не ни удовлетворяваше по uptime и DNS грешки. Но тестът беше проведен преди корекцията на бъга от страна на CF, възможно е сега да е по-добре (въпреки това, това не изключва HTTP таймаутите).
- Ali + GLB
Тази схема също не ни удовлетворяваше по uptime, тъй като GLB често изпадал от апстрима заради невъзможността за свързване в приемливо време или таймаут, тъй като за сървъра в Китай адресът на GLB остава извън него, а следователно зад китайския фаервол. Нямаше никаква магия.
- GLB only
Вариант, подобен на предишния, само че в него не се използваха сървъри в самия Китай: трафикът отиваше директно в GLB (сменихме DNS записките). Следователно, резултатите не удовлетворяваха, тъй като обикновените китайски клиенти, които ползват услугите на обикновени интернет провайдъри, имат много по-лоша ситуация с преминаването на фаервола в сравнение с Ali Cloud.
- Shenzhen -> (CEN/IPSEC) -> Прокси -> GLB
Тук решихме да използваме най-доброто от всички решения:
- стабилност и гарантиран SLA от CEN
- висока скорост от IPSEC
- "бързата" мрежа на Google и неговия anycast.
Схемата изглежда така: трафикът на потребителите се терминира на виртуалката в ch-shenzhen. Там са настроени upstream-и nginx, част от които сочат към частни IP-сървъри, намиращи се на другия край на IPSEC тунела, а част от upstream-ите — към частни адреси на сървъри от другата страна на CEN. IPSEC беше настроен до региона asia-east1 в GCP (това беше най-близкият регион до Китай по време на създаването на решението. В момента GCP също има присъствие в Хонг Конг). CEN — до региона us-east1 в Ali Cloud.
След това трафикът от двата края беше насочен към anycast IP GLB, тоест в най-близката точка на присъствие на Google, и потегли по неговите мрежи към региона us-east4 в GCP, където стояха заменящи виртуалки (с subfilter в nginx).
Това хибридно решение, както очаквахме, ни позволи да се възползваме от предимствата на всяка технология. В общи линии, трафикът минава през бърз IPSEC, но ако възникнат проблеми, бързо изключваме тези сървъри от upstream-ите и изпращаме трафика само през CEN, докато тунелът не се стабилизира.
Внедрявайки четвъртото решение от списъка по-горе, постигнахме това, което желаехме, и което бизнесът на този етап изискваше от нас.
Резултатите от тестовете в браузър за новото решение в сравнение с предишните:
Решение
Uptime
Медии
75 Перцентил
95 Перцентил
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
В реализираното от нас решение всичко е наред, само че няма CDN, който да може да ускори трафика на регионално и дори градско ниво. По идеята, това трябва да ускори работата на сайта за крайните потребители чрез използване на бързи връзки на доставчика на CDN. И ние все време мислехме за това. И ето, дойде времето за следващата итерация по проекта: търсене и тестване на доставчици на CDN в Китай.
И за това ще ви разкажа в следващата, заключителна част 🙂
Източник: habr.com
