Hola
Nikita está contigo otra vez, un ingeniero de sistemas de SEMrush . Y con este artículo, continúo la historia de cómo se nos ocurrió una solución para evitar el Firewall chino para nuestro servicio semrush.com.
En la parte anterior dije:
- qué problemas aparecen después de tomar una decisión "Necesitamos hacer que nuestro servicio funcione en China"
- ¿Qué problemas tiene Internet en China?
- ¿Por qué necesito una licencia ICP?
- cómo y por qué decidimos probar nuestros bancos de prueba usando el punto de captura
- ¿Cuál fue el resultado de nuestra primera solución basada en Cloudflare China Network?
- cómo encontramos un error en DNS Cloudflare

Esta parte es la más interesante, en mi opinión, porque se centra en implementaciones técnicas específicas de puesta en escena. Y comenzaremos, o más bien continuaremos, con Alibaba Cloud .
Nube de Alibaba
Alibaba Cloud es un proveedor de nube bastante grande, que tiene todos los servicios que le permiten llamarse honestamente un proveedor de nube. Es bueno que tengan la oportunidad de registrarse con usuarios extranjeros y que la mayor parte del sitio se haya traducido al inglés (para China es un lujo). En esta nube, puede trabajar con muchas regiones del mundo, China continental, así como con Ocean Asia (Hong Kong, Taiwán, etc.).
IPSEC
Comenzó con la geografía. Como nuestro sitio de prueba estaba ubicado en Google Cloud, tuvimos que "vincular" Alibaba Cloud con GCP, por lo que abrimos una lista de ubicaciones donde Google está presente. En ese momento, aún no tenían su propio centro de datos en Hong Kong.
La región más cercana era asia-east1 (Taiwán). Ali tenía cn-shenzhen (Shenzhen) como la región más cercana de China continental a Taiwán.
Usando terraform, describieron y plantearon toda la infraestructura en GCP y Ali. El túnel de 100 Mbps entre las nubes se levantó casi al instante. Del lado de Shenzhen y Taiwán, plantearon máquinas virtuales proxy. En Shenzhen, el tráfico de usuarios finaliza, se aproxima a través de un túnel a Taiwán, y desde allí se dirige directamente a la IP externa de nuestro servicio en la costa este de los EE. UU. Haga ping entre virtuales en el túnel de 24 ms , que no es tan malo.
Al mismo tiempo, colocamos una zona de prueba en Alibaba Cloud DNS . Después de delegar la zona a NS Ali, el tiempo de resolución disminuyó de 470 ms a 50 ms . Antes de esto, la zona también estaba en Cloudlfare.
En paralelo con el túnel hacia asia-este1 , se levantó otro túnel desde Shenzhen directamente hacia nosotros-este4 . Allí crearon más máquinas virtuales proxy y comenzaron a medir ambas soluciones, enrutando el tráfico de prueba usando Cookies o DNS. El banco de pruebas se describe esquemáticamente en la siguiente figura:

La latencia para túneles es la siguiente:
Ali cn-shenzhen <--> GCP asia-east1 - 24ms
Ali cn-shenzhen <--> GCP us-east4 - 200ms
Las pruebas del navegador Catchpoint han reportado excelentes mejoras de rendimiento.

Compare los resultados de la prueba para las dos soluciones:
Estos son los datos de la solución que utilizan el túnel IPSEC a través de asia-east1 . A través de us-east4, los resultados fueron peores y hubo más errores, por lo que no daré los resultados.
Según los resultados de esta prueba, dos túneles, uno de los cuales termina en la región más cercana a China, y el otro en el destino final, quedó claro que es importante "salir" del cortafuegos chino lo antes posible, y luego usar redes rápidas (proveedores CDN) , proveedores de la nube, etc.). No es necesario intentar de un solo golpe para atravesar el firewall y llegar al destino. Esta no es la forma más rápida.
En general, los resultados no son malos, sin embargo, semrush.com tiene una mediana de 8.8s y 75 percentil de 9.4s (en la misma prueba).
Y antes de continuar, me gustaría hacer una digresión.
Digresión lírica
Después de que el usuario visita el sitio www.semrushchina.cn , que se resuelve a través de los servidores DNS chinos "rápidos", la solicitud HTTP pasa por nuestra solución rápida. La respuesta se devuelve de la misma manera, pero en todos los scripts JS, páginas HTML y otros elementos de la página web, el dominio semrush.com está indicado para recursos adicionales que deben cargarse al representar la página. Es decir, el cliente resuelve el registro "principal" A de www.semrushchina.c n y entra en el túnel rápido, recibe rápidamente una respuesta, una página HTML que dice:
- descargue tal y tal js de sso.semrush.com,
- Tome archivos CSS de cdn.semrush.com,
- y tome más fotos de dab.semrush.com
- Y así sucesivamente.
El navegador comienza a ir a Internet "externo" para obtener estos recursos, cada vez que pasa a través de un firewall que devora el tiempo de respuesta.
Pero en la prueba anterior, los resultados se presentan cuando no hay recursos de semrush.com en la página, solo semrushchina.cn , y * .semrushchina.cn se resuelve en la dirección de la máquina virtual en Shenzhen para ingresar al túnel más tarde.
Solo de esta manera, lanzando todo el tráfico posible a través de su decisión de pasar rápidamente por el firewall chino, puede obtener velocidades aceptables e indicadores de disponibilidad del sitio, así como resultados honestos de las soluciones de prueba.
Lo hicimos sin una sola edición de código en el lado de los productos del equipo.
Subfiltro
La solución nació casi inmediatamente después de que surgió este problema. Necesitábamos PoC (Prueba de concepto) para que nuestras soluciones de paso de firewall realmente funcionen bien. Para hacer esto, debe maximizar todo el tráfico al sitio en esta solución. Y aplicamos subfiltro en nginx.
Subfilter es un módulo bastante simple en nginx que le permite cambiar una línea en el cuerpo de una respuesta a otra línea. Así que cambiamos todas las apariciones de semrush.com a semrushchina.cn en todas las respuestas.
Y ... esto no funcionó, porque recibimos contenido comprimido de los backends, por lo que el subfiltro no pudo encontrar la línea necesaria. Tuve que agregar otro servidor local a nginx, que amplió la respuesta y la transmitió al siguiente servidor local, que ya estaba involucrado en la sustitución de línea, compresión y entrega a la siguiente cadena de servidores proxy.

Como resultado, donde el cliente recibiría <subdominio> .semrush.com , recibiría <subdominio> .semrushchina.cn y obedientemente pasaría por nuestra decisión.
Sin embargo, no es suficiente solo cambiar el dominio en una dirección, porque los servidores aún esperan semrush.com en las solicitudes posteriores del cliente. En consecuencia, en el mismo servidor donde el reemplazo se realiza de una manera, usando una expresión regular simple obtenemos el subdominio de la solicitud y luego hacemos proxy_pass con la variable $ host establecida en $ subdomain.semrush.com . Puede parecer confuso, pero funciona. Y funciona bien. Para dominios individuales que requieren una lógica diferente, simplemente crean sus bloques de servidor y hacen una configuración separada. A continuación se detallan las configuraciones nginx abreviadas para mayor claridad y demostración de este esquema.
La siguiente configuración procesa todas las solicitudes de China a .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; } }
Esta configuración se envía por proxy a localhost en el puerto 83, y allí espera la siguiente configuración:
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; } }
De nuevo, estas son configuraciones recortadas.
Algo asi. Puede parecer complicado, pero está en palabras. De hecho, todo es más fácil que el nabo al vapor :)
El fin de la digresión lírica
Por un tiempo, estuvimos felices porque el mito de la caída de túneles IPSEC no ha sido confirmado. Pero entonces los túneles comenzaron a caer. Varias veces al día durante varios minutos. Un poco, pero no nos convenía. Dado que ambos túneles se terminaron en el lado Ali en el mismo enrutador, decidimos que quizás este sea un problema regional y que necesitamos elevar la región de respaldo.
Recogido Los túneles comenzaron a caer en diferentes momentos, pero tuvimos una conmutación por error ajustada a nivel ascendente en nginx. Pero luego los túneles comenzaron a caer aproximadamente al mismo tiempo :) Y nuevamente, 502 y 504. El tiempo de actividad comenzó a deteriorarse, así que comenzamos a encontrar la opción con Alibaba CEN (Cloud Enterprise Network).
Cen
CEN es la conectividad de dos VPC de diferentes regiones dentro de la nube de Alibaba, es decir, puede conectar redes privadas de cualquier región dentro de la nube entre sí. Y lo más importante: este canal tiene un SLA bastante estricto. Es muy estable tanto en velocidad como en tiempo de actividad. Pero nunca es tan simple:
- es MUY difícil de conseguir si no son ciudadanos chinos o personas jurídicas,
- debe pagar por cada megabit de ancho de banda.
Al tener la oportunidad de conectar China continental y el extranjero , creamos un CEN entre dos regiones de Ali: cn-shenzhen y us-east-1 (el punto más cercano a us-east4). En Ali us-east-1, plantearon otra máquina virtual para tener otro salto .
Resultó así:

Resultados de la prueba del navegador a continuación:

El rendimiento es ligeramente mejor que IPSEC. Pero a través de IPSEC puede potencialmente descargar a una velocidad de 100 Mbps, y a través de CEN solo a una velocidad de 5 Mbps y más costosa.
Híbrido suplica, ¿verdad? Combine la velocidad IPSEC y la estabilidad CEN.
Esto es lo que hicimos al permitir el tráfico a través de IPSEC y CEN en el caso de un bloqueo del túnel IPSEC. El tiempo de actividad se ha vuelto mucho más alto, pero la velocidad de carga del sitio es baja. Luego dibujé todos los esquemas que ya usamos y probamos, y decidí intentar agregar un poco más de GCP a este esquema, a saber, GLB .
GLB
GLB es el Global Load Balancer (o Google Cloud Load Balancer). Tiene una ventaja importante para nosotros: en el contexto de CDN, tiene IP de difusión ilimitada , que le permite enrutar el tráfico al centro de datos más cercano al cliente, gracias a lo cual el tráfico llega a la red rápida de Google más rápido y menos a través de Internet "normal".
Sin pensarlo dos veces, elevamos HTTP / HTTPS LB a GCP y colocamos nuestras máquinas virtuales con backend de subfiltro.
Hubo varios esquemas:
- Use Cloudflare China Network , pero esta vez Origin especifique IP GLB global.
- Termine a los clientes en cn-shenzhen , y desde allí envíe el tráfico de inmediato a GLB .
- Ir directamente de China al GLB .
- Termine a los clientes en cn-shenzhen , desde allí proxy a asia-east1 a través de IPSEC (en us-east4 a través de CEN), desde allí vaya a GLB (con calma, habrá una imagen y una explicación a continuación)
Probamos todas estas opciones y algunas más híbridas:

Este esquema no nos convenía para el tiempo de actividad y los errores de DNS. Pero la prueba se realizó antes de corregir el error por parte de CF, quizás ahora sea mejor (sin embargo, esto no excluye los tiempos de espera HTTP).

Este esquema tampoco nos convenía para el tiempo de actividad, ya que GLB a menudo se retiraba del flujo ascendente debido a la imposibilidad de conectarse en un tiempo o tiempo de espera aceptable, porque para un servidor dentro de China, la dirección GLB permanece fuera y, por lo tanto, detrás del firewall chino. La magia no sucedió.

Una variante similar a la anterior, solo que no usaba servidores en China: el tráfico fue inmediatamente a GLB (registros DNS modificados). En consecuencia, los resultados no fueron satisfactorios, ya que los clientes chinos comunes que utilizan los servicios de proveedores de Internet comunes tienen una situación mucho peor al pasar a través del firewall que Ali Cloud.
- Shenzhen -> (CEN / IPSEC) -> Proxy -> GLB

Aquí decidimos usar la mejor de todas las soluciones:
- estabilidad y SLA garantizado de CEN
- alta velocidad de IPSEC
- La red "rápida" de Google y su difusión ilimitada.
El esquema se parece a esto: el tráfico de usuarios termina en una máquina virtual en ch-shenzhen . Allí se configuran los ajustes ascendentes de Nginx, algunos de los cuales se refieren a servidores IP privados ubicados en el otro extremo del túnel IPSEC, y algunas conexiones ascendentes a direcciones de servidores privados en el otro lado del CEN. IPSEC se configuró para la región asia-este1 en GCP (era la región más cercana a China en el momento en que se creó la solución. Ahora GCP también tiene presencia en Hong Kong). CEN - a la región us-east1 en Ali Cloud.
Además, el tráfico de ambos extremos se dirigió a IPBB de difusión ilimitada , es decir, al punto de presencia de Google más cercano, y atravesó sus redes hasta la región us-east4 en GCP, en la que había máquinas virtuales sustitutas (con subfiltro en nginx).
Esta solución híbrida, como esperábamos, nos permitió aprovechar cada tecnología. En general, el tráfico pasa por IPSEC rápido, pero si comienzan los problemas, rápidamente y durante varios minutos arrojamos estos servidores fuera de la corriente ascendente y enviamos el tráfico a través de CEN solo hasta que el túnel se estabilice.
Habiendo implementado la cuarta solución de la lista anterior, logramos lo que queríamos y lo que la empresa nos exigía en ese momento.
Resultados de la prueba del navegador para la nueva solución en comparación con los anteriores:
CDN
Todo está bien en la solución que hemos implementado, pero no hay CDN que pueda acelerar el tráfico a nivel de regiones e incluso ciudades. En teoría, esto debería acelerar el sitio para los usuarios finales mediante el uso de canales de comunicación rápidos del proveedor de CDN. Y lo pensamos todo el tiempo. Y ahora, ha llegado el momento de la próxima iteración del proyecto: buscar y probar proveedores de CDN en China.
Y les contaré sobre esto en la próxima parte final :)
Todas las partes
Parte 1
Parte 3