05 feb 2019

Mejoras en el cálculo de ping

¡Hola a todos! Soy Bart Hawthorne, ingeniero de red jefe del equipo de motor aquí en Epic, y quiero hablarles sobre nuestro método a la hora de mostrar los valores de ping en Fortnite, el nuevo método que probamos en la v.7.30 y por qué falló y, finalmente, nuestros planes futuros para mejorar la precisión del ping que les mostramos.

Pero primero, aquí les dejo una rápida introducción de algunos términos que usaré para aquellos que no los conozcan:

Cliente y servidor: cada consola, dispositivo móvil, PC o Mac es un cliente, y los clientes se conectan a un servidor dedicado que sirve de anfitrión para la partida. El servidor mantiene el estado general del juego (la ubicación de los jugadores, el estado del círculo, qué cofres están activos y mucho más). El servidor también es el responsable de actualizar todos los clientes cuando hay cambios en los estados del juego.

Paquete: un paquete es un bloque de datos que se envía a través de la red del cliente al servidor o del servidor al cliente. Así es cómo se comunican los clientes y el servidor entre sí. En Fortnite y UE4, usamos estos paquetes en el método para calcular el ping.

Fotograma: en el servidor, un fotograma indica con qué frecuencia el servidor realizará todos sus deberes: buscar paquetes nuevos, actualizar el estado del juego y enviar actualizaciones a los clientes. En el cliente, un fotograma indica con qué frecuencia se actualiza la imagen en pantalla. Por eso la velocidad de fotogramas, también llamada FPS o fotogramas por segundo, indica cuántos fotogramas se procesarán en el servidor o el cliente en un segundo. Así que cuando decimos que el cliente se ejecuta a 60 FPS, quiere decir que cada segundo contiene 60 fotogramas.

¡Bien, ahora que terminamos con eso, hablemos sobre el ping!

Nuestro antiguo método de cálculo de paquetes de ping

Cuando la mayoría de las personas piensan en "ping", creen que se refiere al tiempo que tarda el cliente en enviar un paquete al servidor y luego al tiempo que tarda el servidor en responder o viceversa. Esto también se conoce como tiempo de ida y vuelta o RTT por sus siglas en inglés. Esto aporta la información que les interesa a la mayoría de los jugadores: la cantidad de tiempo que les tomará recibir actualizaciones del servidor y la cantidad de tiempo que le tomará al servidor recibir sus actualizaciones. Cuanto más alto sea el ping de un jugador, mayor será la probabilidad de ver errores como jugadores teletransportándose, eliminaciones inesperadas o demoras al interactuar con cofres u otros objetos.

Nosotros mostramos el ping en milisegundos y cuanto más bajo sea, mejor. ¡Si por casualidad viven al lado de un centro de datos que aloja nuestros servidores, entonces es posible que su ping sea de un solo dígito! Sin embargo, si están jugando en un servidor ubicado al otro lado del mundo, es posible que tengan un ping de 100 ms o más.

Aunque hay más en la comunicación cliente-servidor que el tiempo que tardan los paquetes en ir y venir. En Fortnite, solemos buscar paquetes nuevos una vez por fotograma desde el inicio tanto en el servidor como en el cliente. Esto significa que hay un retraso potencial de hasta un fotograma completo entre la llegada de un paquete y el momento en que el cliente o el servidor comprueba si un paquete llega justo después de haber comprobado si llegaron paquetes nuevos. Además, también lleva tiempo leer el paquete y actualizar el estado del juego en función de los datos que contiene.

Aquí hay un diagrama para ayudar a que se entienda mejor:

El cliente negro y las flechas del servidor representan el tiempo. En este ejemplo, los servidores están en sincronía y se ejecutan a la misma velocidad de fotogramas. Las líneas negras verticales representan el inicio de cada fotograma, las líneas azules indican cuándo el cliente o el servidor comprueba si hay algún paquete que procesar y las líneas naranjas representan cuándo el cliente o el servidor envían paquetes. Las líneas punteadas púrpuras representan un paquete que viaja por Internet.

Esta es la secuencia de eventos:

  1. El cliente envía un paquete al servidor.
  2. El servidor recibe el paquete que envió el cliente.
  3. El servidor comprueba si hay paquetes nuevos, aquí el servidor ve el paquete que envió el cliente. Nótese que el paquete estuvo ahí quieto durante casi un fotograma completo porque llegó justo después de que el servidor verificara si había paquetes.
  4. El servidor envía su respuesta al cliente y confirma que lo recibió.
  5. La respuesta del servidor llega al cliente.
  6. El cliente lee la respuesta del servidor.
Solo queremos mostrar el tiempo de ida y vuelta, representado por las flechas verdes, y restar el tiempo representado por las rojas. Por lo tanto, hacemos lo mejor que podemos. Cuando enviamos un paquete desde el servidor al cliente, incluye el tiempo de fotogramas del servidor, así que para un paquete específico, restamos ese tiempo de fotogramas del servidor así como el tiempo de fotogramas del cliente hasta el punto en que procesamos el paquete. Nuestro cálculo de ping se ve así:
Ping = tiempo que tarda el paquete en llegar al servidor + tiempo que tarda el paquete en viajar al tiempo de fotogramas del cliente-servidor - tiempo de fotogramas del cliente hasta ahora

Para el valor que mostramos, hacemos un promedio de este valor calculado de los paquetes a lo largo de varios segundos para producir un valor más consistente.

Aunque, en la práctica, no es tan preciso como nos gustaría. No tiene en cuenta el tiempo en que llegaron los paquetes y esperan a ser procesados, por lo que el valor de ping mostrado a menudo es demasiado alto. El problema es que la mayoría de las plataformas no ofrecen una manera de saber cuándo llegó un paquete específico, así que no sabemos exactamente cuánto tiempo restar.

Nuestro método de cálculo de paquetes de ping en la v.7.30

En la v.7.30, teníamos una idea y queríamos probar algo nuevo: ¿qué pasaría si solo utilizáramos los paquetes que tardaron menos tiempo en viajar del cliente al servidor para obtener una respuesta? La teoría era que los paquetes que se demoraban menos tiempo serían los que se procesarían de inmediato, lo cual nos permitiría ignorar cualquier tiempo de espera porque debería ser casi cero. Terminamos usando el 25% de los paquetes más rápidos en el cálculo del valor de ping, porque parecía que elegir los paquetes más rápidos mientras contábamos con suficientes datos para obtener un valor realista nos otorgaría un buen equilibrio.

¿Qué salió mal?

Tras el lanzamiento de la v.7.30, vimos que muchos jugadores enviaron informes en los que estipulaban que tenían valores de ping de un solo dígito, algunos incluso 0, cuando debería ser más alto. ¡De ser así, eso significaría que estábamos enviando paquetes más rápido que la velocidad de la luz y, aunque es cierto que UE4 es increíble, todavía no llegamos tan lejos! Estaba claro que algo iba mal.

El problema tiene que ver con parte de nuestro cálculo de ping. Aquí está otra vez como referencia:
Ping = tiempo que tarda el paquete en llegar al servidor + tiempo que tarda el paquete en viajar al tiempo de fotogramas del cliente-servidor - tiempo de fotogramas del cliente hasta ahora

El problema es restar el tiempo de fotogramas del servidor. Si solo consideramos los paquetes más rápidos, significa que estamos restando demasiado: si un paquete es gestionado en el servidor apenas llega, puede que solo tarde unos milisegundos en procesar su contenido y enviar una respuesta. ¡El tiempo total del servidor puede ser 5 veces mayor!

Aquí tienen un diagrama de cómo es eso:

Este es un cliente que tiene una velocidad de fotogramas mucho mayor que la del servidor. Como solo estamos tomando en cuenta los paquetes verdes, estos llegan justo antes de que el servidor los compruebe. En este caso, el servidor funciona más rápido que la velocidad de fotogramas fija, por lo que duerme (no hace nada por un tiempo) al comienzo del fotograma antes de que empiece a comprobar si hay paquetes.

La línea roja representa lo que restamos como velocidad de fotogramas del servidor, pero lo correcto sería la línea naranja. Esto claramente es demasiado tiempo y así es como algunos clientes empezaron a mostrar 0 de ping.

Al usar el método antiguo consideramos una mayor variedad de paquetes, pero esto sigue siendo un problema. Sin embargo, tenemos una mayor probabilidad de considerar paquetes que llevan mucho tiempo esperando a ser procesados, por lo que pueden anular los paquetes en los que restamos demasiado tiempo.

Planes para el futuro

Vamos a implementar mejoras en el futuro que nos permitirán mostrar un valor de ping más preciso. Como dije antes:

"El problema es que la mayoría de las plataformas no ofrecen una manera de saber cuándo llegó un paquete específico, así que no sabemos cuánto tiempo restar".


¡Afortunadamente, Linux sí que lo hace! Dado que nuestros servidores se ejecutan exclusivamente en Linux, podemos cambiar la fórmula de cálculo de ping a la siguiente:

Ping = tiempo que tarda el paquete en llegar al servidor + tiempo que tarda el paquete en viajar al cliente - tiempo entre la llegada del paquete al servidor y el envío de una respuesta - tiempo de fotogramas del cliente hasta ahora


Esto elimina las suposiciones que intentábamos hacer al restar el tiempo de fotogramas del servidor. Esperamos que esto proporcione valores mucho más precisos, pero todavía quedan muchas pruebas que realizar.

También estamos investigando la posibilidad de comprobar los paquetes con mayor frecuencia en el cliente, lo cual nos permitiría eliminar el "tiempo de fotogramas del cliente hasta ahora" del cálculo.

Esperamos que estos dos cambios proporcionen un valor de ping más preciso.

Conclusión

Espero que esta explicación haya sido útil para saber cómo calculamos el ping y qué estamos haciendo para mejorarlo. Al mostrar este tipo de información, es vital que sea preciso. Mostrar valores incorrectos puede ser incluso peor que no mostrar nada de información. Es importante que los jugadores sepan que fallaron un tiro o que el juego les funciona lento debido a su ping para que puedan solucionarlo.

Estaré atento a las preguntas en los comentarios y con gusto responderé todas las que pueda. ¡Gracias por leer!