El protocolo QUIC en acción: cómo lo implementó Uber para optimizar el rendimiento

Es extremadamente interesante observar el protocolo QUIC, por eso nos encanta escribir sobre él. Pero si las publicaciones anteriores sobre QUIC eran más de naturaleza histórica (historia local, si se quiere) y hardware, hoy nos complace publicar una traducción de un tipo diferente: hablaremos sobre la aplicación real del protocolo en 2019. Además, no estamos hablando de una pequeña infraestructura basada en un llamado garaje, sino de Uber, que opera en casi todo el mundo. Cómo los ingenieros de la empresa tomaron la decisión de utilizar QUIC en producción, cómo realizaron las pruebas y qué vieron después de implementarlo en producción: debajo del corte.

Se puede hacer clic en las imágenes. ¡Disfruta leyendo!

El protocolo QUIC en acción: cómo lo implementó Uber para optimizar el rendimiento

Uber tiene una escala global, es decir, 600 ciudades con presencia, en cada una de las cuales la aplicación se basa completamente en Internet inalámbrico de más de 4500 operadores de telefonía móvil. Los usuarios esperan que la aplicación no sólo sea rápida, sino que funcione en tiempo real; para lograrlo, la aplicación Uber necesita baja latencia y una conexión muy confiable. Ay, pero la pila HTTP / 2 no funciona bien en redes inalámbricas dinámicas y propensas a pérdidas. Nos dimos cuenta de que en este caso el bajo rendimiento está directamente relacionado con las implementaciones de TCP en los núcleos del sistema operativo.

Para resolver el problema aplicamos QUIC, un protocolo de multiplexación de canales moderno que nos brinda más control sobre el rendimiento del protocolo de transporte. Actualmente el grupo de trabajo IETF estandariza QUIC como HTTP / 3.

Después de pruebas exhaustivas, llegamos a la conclusión de que implementar QUIC en nuestra aplicación daría como resultado latencias de cola más bajas en comparación con TCP. Observamos una reducción en el rango del 10 al 30 % para el tráfico HTTPS en las aplicaciones de conductor y pasajero. QUIC también nos brindó control de un extremo a otro sobre los paquetes de los usuarios.

En este artículo, compartimos nuestra experiencia en la optimización de TCP para aplicaciones Uber utilizando una pila que admita QUIC.

La última tecnología: TCP

Hoy en día, TCP es el protocolo de transporte más utilizado para entregar tráfico HTTPS en Internet. TCP proporciona un flujo confiable de bytes, lo que hace frente a la congestión de la red y las pérdidas de la capa de enlace. El uso generalizado de TCP para el tráfico HTTPS se debe a la ubicuidad del primero (casi todos los sistemas operativos contienen TCP), la disponibilidad en la mayoría de la infraestructura (como balanceadores de carga, servidores proxy HTTPS y CDN) y la funcionalidad lista para usar que está disponible. en casi la mayoría de plataformas y redes.

La mayoría de los usuarios usan nuestra aplicación mientras viajan, y las latencias de cola de TCP no estaban ni cerca de las demandas de nuestro tráfico HTTPS en tiempo real. En pocas palabras, los usuarios de todo el mundo han experimentado esto: la Figura 1 muestra retrasos en las principales ciudades:

El protocolo QUIC en acción: cómo lo implementó Uber para optimizar el rendimiento
Figura 1: La latencia de cola varía en las principales ciudades de Uber.

Aunque la latencia en las redes indias y brasileñas fue mayor que en los EE. UU. y el Reino Unido, la latencia de cola es significativamente mayor que la latencia promedio. Y esto es válido incluso para Estados Unidos y el Reino Unido.

TCP sobre el rendimiento del aire

TCP fue creado para cableado redes, es decir, con énfasis en enlaces altamente predecibles. Sin embargo, inalámbrico Las redes tienen sus propias características y dificultades. En primer lugar, las redes inalámbricas son susceptibles a pérdidas debido a interferencias y atenuación de la señal. Por ejemplo, las redes Wi-Fi son sensibles a las microondas, el bluetooth y otras ondas de radio. Las redes celulares sufren pérdida de señal (camino perdido) debido a la reflexión/absorción de la señal por objetos y edificios, así como por interferencia de vecino torres de telefonía celular. Esto conduce a resultados más significativos (de 4 a 10 veces) y más diversos. Tiempo de ida y vuelta (RTT) y pérdida de paquetes en comparación con una conexión por cable.

Para combatir las fluctuaciones y pérdidas del ancho de banda, las redes celulares suelen utilizar grandes buffers para las ráfagas de tráfico. Esto puede provocar colas excesivas, lo que se traduce en retrasos más prolongados. Muy a menudo, TCP trata esta cola como un desperdicio debido a un tiempo de espera prolongado, por lo que TCP tiende a retransmitir y, por lo tanto, a llenar el búfer. Este problema se conoce como hinchar el búfer (almacenamiento en búfer de red excesivo, hinchazón del búfer), y esto es muy problema serio Internet moderno.

Finalmente, el rendimiento de la red celular varía según el operador, la región y la hora. En la Figura 2, recopilamos los retrasos medios del tráfico HTTPS entre celdas dentro de un rango de 2 kilómetros. Datos recopilados para dos importantes operadores de telefonía móvil en Delhi, India. Como puede ver, el rendimiento varía de una celda a otra. Además, la productividad de un operador difiere de la productividad del segundo. Esto está influenciado por factores como los patrones de entrada a la red, teniendo en cuenta el tiempo y la ubicación, la movilidad de los usuarios, así como la infraestructura de la red, teniendo en cuenta la densidad de las torres y la proporción de tipos de redes (LTE, 3G, etc.).

El protocolo QUIC en acción: cómo lo implementó Uber para optimizar el rendimiento
Figura 2. Retrasos tomando como ejemplo un radio de 2 km. Delhi, India.

Además, el rendimiento de las redes celulares varía con el tiempo. La Figura 3 muestra la latencia media por día de la semana. También observamos diferencias a menor escala, en un solo día y hora.

El protocolo QUIC en acción: cómo lo implementó Uber para optimizar el rendimiento
Figura 3. Los retrasos en la cola pueden variar significativamente entre días, pero para el mismo operador.

Todo lo anterior hace que el rendimiento de TCP sea ineficaz en las redes inalámbricas. Sin embargo, antes de buscar alternativas a TCP, queríamos desarrollar una comprensión precisa sobre los siguientes puntos:

  • ¿Es TCP el principal culpable de las latencias de cola en nuestras aplicaciones?
  • ¿Las redes modernas tienen retrasos de ida y vuelta (RTT) significativos y variados?
  • ¿Cuál es el impacto del RTT y la pérdida en el rendimiento de TCP?

Análisis de rendimiento de TCP

Para comprender cómo analizamos el rendimiento de TCP, echemos un vistazo rápido a cómo TCP transfiere datos de un remitente a un receptor. Primero, el remitente establece una conexión TCP, realizando una conexión de tres vías. apretón de manos: El remitente envía un paquete SYN, espera un paquete SYN-ACK del receptor y luego envía un paquete ACK. Se dedica un segundo y tercer paso adicionales a establecer la conexión TCP. El destinatario acusa recibo de cada paquete (ACK) para garantizar una entrega confiable.

Si se pierde un paquete o ACK, el remitente lo retransmite después de un tiempo de espera (RTO, tiempo de espera de retransmisión). El RTO se calcula dinámicamente en función de varios factores, como el retraso RTT esperado entre el remitente y el destinatario.

El protocolo QUIC en acción: cómo lo implementó Uber para optimizar el rendimiento
Figura 4. El intercambio de paquetes a través de TCP/TLS incluye un mecanismo de retransmisión.

Para determinar cómo se desempeñó TCP en nuestras aplicaciones, monitoreamos los paquetes TCP usando tcpdump durante una semana sobre el tráfico de combate procedente de servidores indios. Luego analizamos las conexiones TCP usando tcptraza. Además, creamos una aplicación para Android que envía tráfico emulado a un servidor de prueba, imitando al máximo el tráfico real. Se distribuyeron teléfonos inteligentes con esta aplicación a varios empleados, quienes recogieron registros durante varios días.

Los resultados de ambos experimentos fueron consistentes entre sí. Vimos latencias RTT altas; los valores de la cola fueron casi 6 veces superiores al valor medio; la media aritmética de los retrasos es superior a 1 segundo. Muchas conexiones tuvieron pérdidas, lo que provocó que TCP retransmitiera el 3,5% de todos los paquetes. En zonas congestionadas como aeropuertos y estaciones de tren, vimos pérdidas del 7%. Estos resultados arrojan dudas sobre la sabiduría convencional de que los utilizados en redes celulares circuitos de retransmisión avanzados reducir significativamente las pérdidas a nivel de transporte. A continuación se muestran los resultados de las pruebas de la aplicación "simulador":

Métricas de red
Significados

RTT, milisegundos [50%,75%, 95%,99%]
[350, 425, 725, 2300]

Divergencia RTT, segundos
En promedio ~1,2 s

Pérdida de paquetes en conexiones inestables
Promedio ~3.5% (7% en áreas sobrecargadas)

Casi la mitad de estas conexiones tuvieron al menos una pérdida de paquete, la mayoría de ellos paquetes SYN y SYN-ACK. La mayoría de las implementaciones de TCP utilizan un valor RTO de 1 segundo para paquetes SYN, que aumenta exponencialmente para pérdidas posteriores. Los tiempos de carga de las aplicaciones pueden aumentar debido a que TCP tarda más en establecer conexiones.

En el caso de los paquetes de datos, los valores altos de RTO reducen en gran medida la utilización útil de la red en presencia de pérdidas transitorias en las redes inalámbricas. Descubrimos que el tiempo medio de retransmisión es de aproximadamente 1 segundo con un retraso de cola de casi 30 segundos. Estas altas latencias a nivel de TCP provocaron tiempos de espera de HTTPS y nuevas solicitudes, lo que aumentó aún más la latencia y la ineficiencia de la red.

Mientras que el percentil 75 del RTT medido fue de alrededor de 425 ms, el percentil 75 para TCP fue de casi 3 segundos. Esto sugiere que la pérdida hizo que TCP necesitara entre 7 y 10 pasadas para transmitir datos con éxito. Esto puede ser consecuencia de un cálculo ineficiente del RTO y de la incapacidad de TCP para responder rápidamente a las pérdidas. últimos paquetes en la ventana y la ineficiencia del algoritmo de control de congestión, que no distingue entre pérdidas inalámbricas y pérdidas por congestión de la red. A continuación se muestran los resultados de las pruebas de pérdida de TCP:

Estadísticas de pérdida de paquetes TCP
Valor

Porcentaje de conexiones con al menos 1 paquete perdido
45%

Porcentaje de conexiones con pérdidas durante el establecimiento de la conexión
30%

Porcentaje de conexiones con pérdidas durante el intercambio de datos
76%

Distribución de retrasos en la retransmisión, segundos [50%, 75%, 95%,99%] [1, 2.8, 15, 28]

Distribución del número de retransmisiones para un paquete o segmento TCP
[ 1,3,6,7 ]

Aplicación de QUIC

QUIC, desarrollado originalmente por Google, es un protocolo de transporte moderno de subprocesos múltiples que se ejecuta sobre UDP. Actualmente QUIC está en proceso de estandarización (ya escribimos que hay, por así decirlo, dos versiones de QUIC, curioso puede seguir el enlace – aprox. traductor). Como se muestra en la Figura 5, QUIC se coloca debajo de HTTP/3 (de hecho, HTTP/2 encima de QUIC es HTTP/3, que ahora se está estandarizando intensamente). Reemplaza parcialmente las capas HTTPS y TCP mediante el uso de UDP para formar paquetes. QUIC solo admite la transferencia segura de datos ya que TLS está completamente integrado en QUIC.

El protocolo QUIC en acción: cómo lo implementó Uber para optimizar el rendimiento
Figura 5: QUIC se ejecuta bajo HTTP/3, reemplazando a TLS, que anteriormente se ejecutaba bajo HTTP/2.

A continuación se detallan las razones que nos convencieron de utilizar QUIC para la amplificación de TCP:

  • Establecimiento de conexión 0-RTT. QUIC permite la reutilización de autorizaciones de conexiones anteriores, reduciendo la cantidad de apretones de manos de seguridad. En el futuro TLS1.3 admitirá 0-RTT, pero aún será necesario un protocolo de enlace TCP de tres vías.
  • superar el bloqueo de HoL. HTTP/2 utiliza una conexión TCP por cliente para mejorar el rendimiento, pero esto puede provocar un bloqueo HoL (cabeza de línea). QUIC simplifica la multiplexación y entrega solicitudes a la aplicación de forma independiente.
  • control de congestión. QUIC reside en la capa de aplicación, lo que facilita la actualización del algoritmo de transporte principal que controla el envío en función de los parámetros de la red (número de pérdidas o RTT). La mayoría de las implementaciones de TCP utilizan el algoritmo. CÚBICO, que no es óptimo para el tráfico sensible a la latencia. Algoritmos desarrollados recientemente como BBR, modela con mayor precisión la red y optimiza la latencia. QUIC le permite usar BBR y actualizar este algoritmo a medida que se usa. perfección.
  • reposición de pérdidas. QUIC llama a dos TLP (sonda de pérdida de cola) antes de que se active el RTO, incluso cuando las pérdidas sean muy notables. Esto es diferente de las implementaciones de TCP. TLP retransmite principalmente el último paquete (o el nuevo, si lo hay) para activar un reabastecimiento rápido. Manejar los retrasos finales es particularmente útil para la forma en que Uber opera su red, es decir, para transferencias de datos breves, esporádicas y sensibles a la latencia.
  • ACK optimizado. Dado que cada paquete tiene un número de secuencia único, no hay problema distinciones paquetes cuando se retransmiten. Los paquetes ACK también contienen tiempo para procesar el paquete y generar un ACK en el lado del cliente. Estas características garantizan que QUIC calcule el RTT con mayor precisión. ACK en QUIC admite hasta 256 bandas NACK, lo que ayuda al remitente a ser más resistente a la mezcla de paquetes y a utilizar menos bytes en el proceso. ACK selectivo (SACO) en TCP no resuelve este problema en todos los casos.
  • migración de conexión. Las conexiones QUIC se identifican mediante una ID de 64 bits, por lo que si un cliente cambia de dirección IP, la ID de conexión anterior puede seguir utilizándose en la nueva dirección IP sin interrupción. Esta es una práctica muy común para aplicaciones móviles donde el usuario cambia entre conexiones Wi-Fi y celulares.

Alternativas a QUIC

Consideramos enfoques alternativos para resolver el problema antes de elegir QUIC.

Lo primero que intentamos fue implementar TPC PoP (puntos de presencia) para terminar las conexiones TCP más cerca de los usuarios. Básicamente, los PoP terminan una conexión TCP con un dispositivo móvil más cercano a la red celular y envían el tráfico a la infraestructura original. Al terminar TCP más cerca, podemos reducir potencialmente el RTT y garantizar que TCP responda mejor a un entorno inalámbrico dinámico. Sin embargo, nuestros experimentos han demostrado que la mayor parte del RTT y la pérdida provienen de redes celulares y el uso de PoP no proporciona una mejora significativa del rendimiento.

También analizamos el ajuste de los parámetros TCP. Configurar una pila TCP en nuestros heterogéneos servidores perimetrales fue difícil porque TCP tiene implementaciones dispares en diferentes versiones del sistema operativo. Fue difícil implementar esto y probar diferentes configuraciones de red. No fue posible configurar TCP directamente en dispositivos móviles debido a la falta de permisos. Más importante aún, características como las conexiones 0-RTT y la predicción RTT mejorada son críticas para la arquitectura del protocolo y, por lo tanto, es imposible lograr beneficios significativos ajustando TCP únicamente.

Finalmente, evaluamos varios protocolos basados ​​en UDP que solucionan problemas de transmisión de video; queríamos ver si estos protocolos ayudarían en nuestro caso. Desafortunadamente, carecían gravemente de muchas configuraciones de seguridad y también requerían una conexión TCP adicional para los metadatos y la información de control.

Nuestra investigación ha demostrado que QUIC es quizás el único protocolo que puede ayudar con el problema del tráfico de Internet, teniendo en cuenta tanto la seguridad como el rendimiento.

Integración de QUIC en la plataforma.

Para integrar QUIC con éxito y mejorar el rendimiento de las aplicaciones en entornos de conectividad deficiente, reemplazamos la pila anterior (HTTP/2 sobre TLS/TCP) con el protocolo QUIC. Usamos la biblioteca de la red. cronet de Proyectos de cromo, que contiene la versión original de Google del protocolo: gQUIC. Esta implementación también se mejora constantemente para seguir la última especificación del IETF.

Primero integramos Cronet en nuestras aplicaciones de Android para agregar soporte para QUIC. La integración se llevó a cabo de tal manera que se redujeran al máximo los costos de migración. En lugar de reemplazar completamente la antigua pila de redes que usaba la biblioteca OkHTTP, hemos integrado Cronet BAJO el marco API OkHttp. Al hacer la integración de esta manera, evitamos cambios en nuestras llamadas de red (que son utilizadas por reequipamiento) a nivel de API.

De manera similar al enfoque para dispositivos Android, implementamos Cronet en aplicaciones de Uber en iOS, interceptando el tráfico HTTP de la red. APIUso NSURLProtocolo. Esta abstracción, proporcionada por la Fundación iOS, maneja datos de URL específicos del protocolo y garantiza que podamos integrar Cronet en nuestras aplicaciones iOS sin costos de migración significativos.

Completar QUIC en Google Cloud Balancers

En el lado backend, la finalización de QUIC la proporciona la infraestructura de equilibrio de carga de Google Cloud, que utiliza servicio alternativo encabezados en respuestas para soportar QUIC. En general, el equilibrador agrega un encabezado alt-svc a cada solicitud HTTP y esto ya valida la compatibilidad con QUIC para el dominio. Cuando un cliente Cronet recibe una respuesta HTTP con este encabezado, utiliza QUIC para solicitudes HTTP posteriores a ese dominio. Una vez que el equilibrador completa el QUIC, nuestra infraestructura envía explícitamente esta acción a través de HTTP2/TCP a nuestros centros de datos.

Desempeño: Resultados

El rendimiento de salida es el motivo principal de nuestra búsqueda de un mejor protocolo. Para empezar, creamos un stand con emulación de redpara descubrir cómo se comportará QUIC en diferentes perfiles de red. Para probar el rendimiento de QUIC en redes del mundo real, realizamos experimentos mientras conducíamos por Nueva Delhi utilizando tráfico de red emulado muy similar a las llamadas HTTP en la aplicación del pasajero.

experimento 1

Equipo para el experimento:

  • probar dispositivos Android con pilas OkHttp y Cronet para asegurarnos de que permitimos el tráfico HTTPS a través de TCP y QUIC respectivamente;
  • un servidor de emulación basado en Java que envía el mismo tipo de encabezados HTTPS en las respuestas y carga los dispositivos cliente para recibir sus solicitudes;
  • servidores proxy en la nube que están ubicados físicamente cerca de la India para terminar las conexiones TCP y QUIC. Mientras que para la terminación TCP utilizamos un proxy inverso en Nginx, fue difícil encontrar un proxy inverso de código abierto para QUIC. Nosotros mismos creamos un proxy inverso para QUIC utilizando la pila QUIC básica de Chromium y publicado convertirlo en cromo como código abierto.

El protocolo QUIC en acción: cómo lo implementó Uber para optimizar el rendimientoEl protocolo QUIC en acción: cómo lo implementó Uber para optimizar el rendimiento
Figura 6. El conjunto de pruebas prácticas de TCP frente a QUIC constaba de dispositivos Android con OkHttp y Cronet, servidores proxy en la nube para terminar conexiones y un servidor de emulación.

experimento 2

Cuando Google puso a disposición QUIC con Balanceo de carga de Google Cloud, utilizamos el mismo inventario, pero con una modificación: en lugar de NGINX, utilizamos los balanceadores de carga de Google para terminar las conexiones TCP y QUIC de los dispositivos, así como para enrutar el tráfico HTTPS al servidor de emulación. Los balanceadores se distribuyen por todo el mundo, pero utilizan el servidor PoP más cercano al dispositivo (gracias a la geolocalización).

El protocolo QUIC en acción: cómo lo implementó Uber para optimizar el rendimiento
Figura 7. En el segundo experimento, queríamos comparar la latencia de finalización de TCP y QUIC: usando Google Cloud y usando nuestro proxy en la nube.

Como resultado, nos esperaban varias revelaciones:

  • la terminación a través de PoP mejoró el rendimiento de TCP. Dado que los equilibradores terminan las conexiones TCP más cerca de los usuarios y están altamente optimizados, esto da como resultado RTT más bajos, lo que mejora el rendimiento de TCP. Y aunque QUIC se vio menos afectado, aún superó a TCP en términos de reducción de la latencia de cola (entre un 10 y un 30 por ciento).
  • las colas están afectadas saltos de red. Aunque nuestro proxy QUIC estaba más alejado de los dispositivos (aproximadamente 50 ms de latencia más alta) que los balanceadores de carga de Google, ofreció un rendimiento similar: una reducción del 15 % en la latencia frente a una reducción del 20 % en el percentil 99 para TCP. Esto sugiere que la transición de la última milla es un cuello de botella en la red.

El protocolo QUIC en acción: cómo lo implementó Uber para optimizar el rendimientoEl protocolo QUIC en acción: cómo lo implementó Uber para optimizar el rendimiento
Figura 8: Los resultados de dos experimentos muestran que QUIC supera significativamente a TCP.

Combatir el tráfico

Inspirados por la experimentación, hemos implementado soporte QUIC en nuestras aplicaciones de Android e iOS. Realizamos pruebas A/B para determinar el impacto de QUIC en las ciudades donde opera Uber. En general, vimos una reducción significativa en los retrasos de cola en ambas regiones, operadores de telecomunicaciones y tipo de red.

Los gráficos a continuación muestran las mejoras porcentuales en las colas (percentiles 95 y 99) por macrorregión y diferentes tipos de redes: LTE, 3G, 2G.
El protocolo QUIC en acción: cómo lo implementó Uber para optimizar el rendimientoEl protocolo QUIC en acción: cómo lo implementó Uber para optimizar el rendimiento
Figura 9. En las pruebas de batalla, QUIC superó a TCP en términos de latencia.

Solo hacia adelante

Quizás esto sea solo el comienzo: el lanzamiento de QUIC en producción ha brindado oportunidades increíbles para mejorar el rendimiento de las aplicaciones tanto en redes estables como inestables, a saber:

Mayor cobertura

Después de analizar el rendimiento del protocolo en tráfico real, vimos que aproximadamente el 80% de las sesiones utilizaron con éxito QUIC para todos solicitudes, mientras que el 15% de las sesiones utilizaron una combinación de QUIC y TCP. Suponemos que la combinación se debe a que la biblioteca Cronet vuelve al tiempo de espera de TCP, ya que no puede distinguir entre fallas reales de UDP y malas condiciones de la red. Actualmente estamos buscando una solución a este problema mientras trabajamos hacia la implementación posterior de QUIC.

optimización QUIC

El tráfico de las aplicaciones móviles es sensible a la latencia, pero no al ancho de banda. Además, nuestras aplicaciones se utilizan principalmente en redes celulares. Según los experimentos, las latencias de cola siguen siendo altas a pesar de que se utiliza un proxy para terminar TCP y QUIC cerca de los usuarios. Estamos buscando activamente formas de mejorar la gestión de la congestión y mejorar la eficiencia de los algoritmos de recuperación de pérdidas QUIC.

Con estas y varias otras mejoras, planeamos mejorar la experiencia del usuario independientemente de la red y la región, haciendo que el transporte de paquetes conveniente y fluido sea más accesible en todo el mundo.

Fuente: habr.com

Añadir un comentario