Здравейте!
Отново съм с вас, Никита — системен инженер от компанията SЕMrush. С тази статия продължавам историята за това как измисляхме решение за заобикаляне на Китайския Файървол за нашия сервис 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. Преди това зоната също беше на Cloudflare.
Паралелно с тунела до asia-east1 припомниха още един тунел от Шенжен направо в us-east4. Там бяха създадени още прокси виртуалки и започнаха да измерват и двете решения, маршрутизирайки тестовия трафик с помощта на Cookies или DNS. Схематично тестовият стенд е описан на следната рисунка:
Забавянето за тунелите се оказа следното:
Ali cn-shenzhen GCP asia-east1 — 24ms
Ali cn-shenzhen GCP us-east4 — 200ms
Браузерните тестове на Catchpoint отразиха отлично подобрение на показателите.
Сравнете резултатите от тестовете за двете решения:
Решение
Время безотказной работы
Медиана
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 за допълнителни ресурси, които трябва да бъдат заредени при рендерирането на страницата. Тоест клиентът резолвира "основната" A-запис www.semrushchina.cn и преминава по бързия тунел, бързо получава отговор — HTML страница, в която е указано:
- изтегли този js от sso.semrush.com,
- вземи CSS файловете от cdn.semrush.com,
- и вземи също снимките от dab.semrush.com
- и така нататък.
Браузерът започва да отива в "външния" интернет за тези ресурси, преминавайки всеки път през забавящия времето отговор фаервол.
Но в предишния тест са представени резултатите, когато на страницата няма ресурси semrush.com, само semrushchina.cn, а *.semrushchina.cn резолвира в адреса на виртуалката в Шенжен, за да влезе след това в тунела.
Само по себе, максимальное использование трафика через наше решение для обхода китайского фаервола позволяет получить приемлемые скорости и доступность сайта, а также достоверные результаты тестов решений.
Мы сделали это без единой правки кода на стороне продуктов команды.
Subfilter
Решение было найдено практически сразу после возникновения проблемы. Нам был нужен PoC (Proof of Concept), чтобы подтвердить, что наши решения обхода фаервола действительно работают эффективно. Для этого необходимо максимально маршрутизировать весь трафик сайта через данное решение. Мы применили в nginx.
Subfilter Это довольно простой модуль в nginx, который позволяет заменять одну строку в теле ответа на другую. Мы заменили все вхождения semrush.com на semrushchina.cn во всех ответах.
И… это не сработало, так как от бэкендов мы получали сжатый контент, поэтому subfilter не находил нужную строку. Пришлось добавить еще один локальный сервер в nginx, который разжимал ответ и передавал его следующему локальному серверу, который уже занимался заменой строки, сжатием и отправкой ее следующему по цепочке прокси-серверу.
В результате, где клиент получал <subdomain>.semrush.com, он получал <subdomain>.semrushchina.cn и проходил через наше решение.
Однако недостаточно просто заменить домен в одну сторону, так как бэкенды все еще ожидают semrush.com в последующих запросах от клиента. Соответственно, на том же сервере, где производится замена, с помощью простого регулярного выражения мы извлекаем поддомен из запроса, а затем устанавливаем proxy_pass с переменной $host, выставленной в $subdomain.semrush.com. Это может показаться запутанным, но это работает. И работает хорошо. Для отдельных доменов, требующих другой логики, создаются отдельные server-блоки и настраивается своя конфигурация. Ниже представлены укороченные конфигурации nginx для наглядности и демонстрации данной схемы.
Следующая конфигурация обрабатывает все запросы из Китая на .semrushchina.cn:
слушай 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;
}
}Тази конфигурация проксирова на 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. Но никога не е всичко толкова просто:
- много е трудно да се получи, ако не сте китайски граждани или юридически лица,
- трябва да плащате за всеки мегабит пропускна способност на канала.
След като получихме възможност да свържем Mainland China и Overseas, създадохме CEN между два региона на Ali: cn-shenzhen и us-east-1 (най-близката точка до us-east4). В Ali us-east-1 създадохме още една виртуалка, за да има още един hop.
Получиха се така:
Резултатите от браузърните тестове са по-долу:
Решение
Время безотказной работы
Медиана
75 Перцентил
95 Перцентил
Cloudflare
86.6
18s
30s
60s
IPsec
99.79
18s
21s
30s
CEN
99.75
16s
21s
27s
Показателите са малко по-добри от тези при IPSEC. Но чрез IPSEC потенциално може да се качва със скорост 100 мбит/c, а чрез CEN само със скорост 5 мбит/c и е по-скъпо.
Прави впечатление хибрид, нали? Да комбинираме скоростта на IPSEC и стабилността на CEN.
Така и направихме трафика както през IPSEC, така и през CEN в случай на срив на IPSEC тунела. Надеждността значително се повиши, но скоростта на зареждане на сайта все още не беше на ниво. Тогава нарисувах всички схеми, които вече бяхме използвали и тествали, и реших да добавя малко GCP в схемата, а именно GLB.
GLB
GLB — това е (или Google Cloud Load Balancer). Той има важно предимство за нас: в контекста на CDN, той anycast IP, което позволява маршрутизиране на трафика към най-близкия до клиента дата център, благодарение на което трафикът по-бързо достига до бързата мрежа на Google и по-малко преминава през "обикновения" интернет.
Без да се замисляме дълго, стартирахме HTTP/HTTPS LB в GCP, а за бекенд използвахме нашите виртуални машини с subfilter.
Имаше няколко схеми:
- Да използваме Cloudflare China Network, но този път да укажем глобалния IP GLB.
- Да терминализираме клиентите в cn-shenzhen, а оттам да проксираме трафика директно в GLB.
- Да отидем направо от Китай в GLB.
- Да терминализираме клиентите в cn-shenzhen, после да проксираме в asia-east1 през IPSEC (в us-east4 през CEN), откъдето да отидем в GLB (спокойно, по-долу ще има изображение и обяснение)
Тествахме всички тези варианти и още няколко хибридни:
- Cloudflare + GLB
Тази схема не ни задоволи по отношение на надеждност и DNS грешки. Но тестът беше проведен преди поправката на бъг от страна на CF, възможно е в момента да е по-добре (обаче, това не изключва HTTP таймаутите).
- Ali + GLB
Тази схема също не ни удовлетворяваше по отношение на надеждността, тъй като GLB често отпадаше от апстрийма поради невъзможност за свързване в приемливо време или таймаути, тъй като адресът на GLB остава извън сървъра в Китай, а значи, зад китайската защитна стена. Магия не се случи.
- Само GLB
Вариант, подобен на предишния, само че в него не се използваха сървъри в самия Китай: трафикът преминаваше директно в 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, докато тунелът не се стабилизира.
Внедрявайки 4-то решение от списъка по-горе, постигнахме това, което искахме, и което бизнесът изискваше от нас в този момент.
Резултатите от браузърните тестове за новото решение в сравнение с предишните:
Решение
Время безотказной работы
Медиана
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
