1 puntos por GN⁺ 2024-07-14 | 1 comentarios | Compartir por WhatsApp
  • Lichess cambió la verificación periódica de RAID de su servidor de tablebases Syzygy de 7 piezas a una verificación de integridad al leer, porque la carga de solicitudes impedía completar las revisiones periódicas
  • Para migrar una tablebase de 17 TiB sin un downtime prolongado, preparó un servidor nuevo y lo validó reproduciendo logs de solicitudes reales en un entorno con 32 GiB de RAM, 2×201 GiB NVMe y 6×5.46 TiB HDD
  • Al reproducir 1 millón de solicitudes registradas en producción con 12 clientes paralelos, se vio que el cuello de botella clave no era la respuesta promedio, sino la latencia de cola percibida por los usuarios
  • En la implementación, pread(2) resultó mejor que mmap para el manejo de errores y la latencia de cola, mientras que hints de acceso aleatorio como POSIX_FADV_RANDOM y MADV_RANDOM fueron mayormente contraproducentes
  • En los SSD limitados se colocaron prefijos de tablas y se paralelizaron los probes dentro de cada solicitud para reducir los accesos a discos lentos; luego se verificó que las mejoras de benchmark también se reflejaran en los tiempos de respuesta en producción

Cambio de verificación completa de RAID a verificación al leer

  • El servidor de tablebases Syzygy de 7 piezas de Lichess tenía dificultades para terminar las verificaciones periódicas de integridad de RAID mientras recibía muchas solicitudes de tablebase
  • La nueva configuración usa dm-integrity sobre LVM para no revisar periódicamente todos los bloques de datos, sino verificar cada bloque cuando se lee
  • Para migrar la tablebase de 17 TiB sin varias horas de downtime, se configuró un servidor nuevo por separado
    • Antes del cambio real, pudieron ejecutar benchmarks controlados sobre la tablebase completa
    • Luego cambiaron al servidor nuevo y retiraron el servidor anterior

Configuración del servidor nuevo

  • La RAM se mantuvo igual que antes: 32 GiB
  • En almacenamiento se agregaron 2×201 GiB NVMe, que no existían en el servidor anterior, y el espacio restante de los discos de 476 GiB se reservó para el SO y el espacio de trabajo
  • Los HDD aumentaron de 5 unidades a 6×5.46 TiB HDD
  • El sistema operativo es Debian bookworm, con un kernel de la serie Linux 6.1.0-21-amd64
  • El planificador de I/O predeterminado era none para NVMe y mq-deadline para HDD

Configuración de RAID 5 y monitoreo

  • RAID 5 se ajusta bien a un servidor de tablebases porque puede recuperarse ante la falla de un solo disco y distribuir lecturas aleatorias entre varios discos
  • La configuración inicial fue la siguiente
lvcreate --type raid5 --raidintegrity y --raidintegrityblocksize 512 --name tables --size 21T vg-hdd
  • El rendimiento de las pruebas iniciales fue aceptable, pero sin monitoreo podrían haber pasado por alto que algunos discos no participaban al mismo nivel
  • Si se omite --stripes, no se usan de forma predeterminada todos los volúmenes físicos
  • El monitoreo de la actividad de lectura por disco fue necesario para detectar una configuración RAID incorrecta

Cuellos de botella vistos con logs de solicitudes reales

  • En condiciones normales, el servidor recibe entre 10 y 35 solicitudes por segundo
  • Se registraron 1 millón de solicitudes en producción y, en el escenario elegido, 12 clientes paralelos las enviaron secuencialmente
  • Las tablas se abren de forma diferida y las cachés de la aplicación y del SO se llenan gradualmente
    • Los primeros 800 mil tiempos de respuesta se excluyeron como warm-up
    • Después se analizaron los tiempos de respuesta de 200 mil solicitudes
  • El tiempo de respuesta promedio era lo suficientemente rápido, pero la latencia de cola era alta y se convirtió en el foco de la optimización
  • El gráfico ECDF muestra el porcentaje de solicitudes más rápidas que cada tiempo de respuesta, con el eje x en escala logarítmica
  • En el gráfico se sumaron 30 ms a cada tiempo de respuesta para reflejar el ping time de 30 ms del cliente
    • Esto se hizo para que el eje x logarítmico no exagerara diferencias de unos pocos milisegundos en el tramo bajo

pread(2) resultó mejor que mmap

  • shakmaty-syzygy, la implementación de las tablebases Syzygy, ofrece interfaces para cambiar la forma de abrir y leer archivos de tablas
  • Había dos candidatos principales
    • mmap: mapea el archivo de la tabla en memoria, y las lecturas de disco ocurren de forma transparente al acceder a esa región de memoria
    • pread(2): hace una llamada al sistema en cada lectura y reporta errores de lectura mediante el valor de retorno
  • mmap no requiere llamadas al sistema adicionales después del mapeo, pero como las lecturas parecen accesos normales a memoria, los errores deben manejarse mediante mecanismos out-of-band como señales
  • En la implementación del servidor, el manejo de errores más robusto ya bastaba para justificar el uso de pread, y en los benchmarks pread también tuvo mejor rendimiento en los escenarios de interés
  • Una posible causa es que el acceso a un único bloque de datos mapeado en memoria puede cruzar un límite de página y terminar provocando dos lecturas de disco
  • No hace falta aplicar pread de inmediato a motores de ajedrez
    • El uso de tablebases en partidas entre motores suele ocurrir cuando todas las tablas WDL pueden estar en almacenamiento lo bastante rápido
    • En ese caso, los tiempos de respuesta típicos ni siquiera aparecerían en ese gráfico, y el mapeo de memoria es mejor para reducir el overhead de llamadas al sistema

Efectos contraproducentes de los hints de acceso aleatorio

  • posix_fadvise(fd, 0, 0, POSIX_FADV_RANDOM) y el hint equivalente para mapas de memoria terminaron siendo mayormente contraproducentes
  • POSIX_FADV_RANDOM le indica al SO que el acceso al archivo es aleatorio y que el read-ahead automático probablemente no será útil, como hint para reducir la presión sobre la page cache
  • Los patrones de acceso a tablebases cuando las personas analizan finales pueden no ser tan aleatorios como se esperaba
  • En motores de ajedrez, los probes pueden estar más dispersos entre distintos finales posibles, por lo que el resultado podría cambiar

Prefijos de tablas para colocar en SSD limitado

  • Un table probe primero codifica la posición como un índice entero usando la información de codificación del header de la tabla
  • Luego debe encontrar el bloque de datos comprimido que contiene el resultado de ese índice
  • Syzygy proporciona una sparse block length list que apunta cerca de la entrada correcta, y después se usa la block length list para encontrar el bloque de datos correspondiente
  • Los tamaños de las secciones de tablas son los siguientes
Table section WDL DTZ Total
Headers and sparse block length lists 38 GiB 9 GiB 47 GiB
Block length lists 274 GiB 64 GiB 339 GiB
Compressed data blocks 8433 GiB 8458 GiB 16891 GiB
  • También podría usarse el espacio SSD como una capa de caché adaptativa para cachear entradas hot de listas y bloques de datos
  • Con el objetivo de reducir la latencia de cola, y considerando el peor caso, resultó adecuado colocar en SSD la sparse block length list y la block length list
  • Esta disposición puede limitar a un máximo de 1 lectura desde discos lentos por cada table probe, sin importar si los datos son hot o cold
  • En ese servidor no había suficiente espacio SSD para hacer espejado RAID 1 y, al ser una optimización selectiva, se renunció a la redundancia y se usó RAID 0

Paralelización de probes dentro de una solicitud

  • Una solicitud típica de tablebase desde un motor de ajedrez pide un único valor WDL
  • En la interfaz de usuario se busca mostrar los valores DTZ para todos los movimientos
  • Incluyendo la resolución de capturas dentro de Syzygy, una solicitud promedio genera 23 probes WDL y 70 probes DTZ
  • La implementación inicial paralelizaba el procesamiento de solicitudes, pero ejecutaba secuencialmente los probes dentro de cada solicitud
  • Una paralelización más fina genera overhead en los tramos de baja latencia, pero reduce mucho la latencia de cola
  • Aunque el disco no pueda procesar físicamente muchas lecturas paralelas, aumenta la probabilidad de que el planificador de I/O organice las lecturas para terminar antes cada solicitud
  • Este enfoque permite planificar mejor el orden de los accesos relacionados al disco, reduciendo el tiempo hasta que el cabezal llega al sector de la siguiente solicitud

Verificación en producción y datos originales

  • Se verificó mediante gráficos de tiempo de respuesta que las optimizaciones del escenario de benchmark también ayudaran en producción
  • Los datos originales están publicados en lila-tablebase-bench

1 comentarios

 
GN⁺ 2024-07-14
Opiniones en Hacker News
  • Lichess es un servicio que uno no puede evitar admirar en silencio, como un buen vino. Es realmente excelente para la comunidad de ajedrez, y al usarlo todos los días me siguen impresionando sus funciones y su rendimiento.
    Es aún más sorprendente si se sabe que es un equipo de 1 a 2 personas con un presupuesto limitado.

    • No hay que olvidar que es gratis y de código abierto, que no pide dinero y que nunca lo hará. Mucha gente dona, sus gastos son públicos y también tiene app.
    • Ojalá más software de código abierto para usuarios finales fuera tan amigable, bien diseñado y bien mantenido como Lichess.
    • Yo también lo siento así. La nueva app móvil beta reciente es más limpia e incluso tiene respuesta háptica, está genial.
    • Algún día me gustaría crear algo tan valioso y genial como Lichess.
  • Me pareció interesante la parte donde mostraban la ECDF sumando 30 ms a cada tiempo de respuesta.
    Agregar una constante puede parecer artificial, pero en la práctica es una forma de ver los resultados desde la perspectiva de un cliente con 30 ms de ping, y hace que el eje x en escala logarítmica no exagere diferencias de unos pocos ms en el rango bajo. Quizá sea una técnica estándar, pero me pareció un truco bastante inteligente.

  • Me pregunto si realmente era necesario reducir costos, o si había alguna otra razón por la que no podían simplemente poner un SSD de 20 TB en una sola máquina y listo. Un SSD de 4 TB ronda los 300 dólares, y las unidades SFF de HP o Dell tampoco son mucho más caras.
    Probablemente les interesaban las pruebas y la optimización en sí; desde una perspectiva de producto, yo habría usado ese tiempo limitado en otros proyectos.

    • Lichess es una organización sin fines de lucro y tiene muchos voluntarios, así que es probable que el equilibrio entre tiempo y costo de hardware sea distinto al de la mayoría de las empresas con fines de lucro.
    • Lichess es una organización sin fines de lucro operada solo con donaciones y trabajo voluntario. El único empleado es la persona que creó la organización sin fines de lucro, y parece que cobra muchísimo menos de lo que podría ganar en otro trabajo dada su capacidad.
      También vale la pena mencionar que la organización está basada en Francia, aunque no sé cómo influye eso en los costos.
    • Con este trabajo redujeron el tiempo máximo de respuesta en un orden de magnitud. Si el proyecto tomó una semana, o como mucho dos, y el tiempo de respuesta para algunos usuarios bajó de 15 s a 1.5 s, vale totalmente la pena.
      Para justificar mejor una inversión de tiempo que esa, tendría que haber proyectos con una experiencia de usuario aún peor, o tratarse de una organización con fines de lucro con oportunidades de ganar dinero en otro lado y que admita que no le importa demasiado el dolor de sus clientes.
    • Creo que casi no hay ingenieros en otras industrias fuera de IT que piensen en “pruebas y optimización por diversión”.
      Esto parece más bien el resultado de combinar hardware demasiado potente y barato con gente floja que solo quiere decir “hasta aquí por hoy”. También existe eso de sentir orgullo por el propio trabajo, ¿no?
    • Desde una perspectiva de producto tiene sentido, pero Lichess no es una empresa con fines de lucro que tenga un producto; en realidad funciona como una organización sin fines de lucro, así que hay que cambiar de perspectiva para entender sus decisiones.
  • Hay varias decisiones cuestionables en esta optimización. La razón para optimizar era que había demasiada actividad de entrada/salida y la verificación RAID no lograba completarse.
    Por lo que dice el artículo, no queda claro si alguna vez terminó realmente la verificación RAID sobre los 17 TiB de datos. En su lugar desactivaron la verificación RAID periódica y cambiaron a verificar errores por página al leer los datos, pero ambos métodos no son equivalentes, y si los datos son importantes deberían usarse ambos.
    Si uno descubre la corrupción solo cuando intenta leer los datos, la corrupción antigua puede permanecer ahí y quizá ya se haya superado el período de retención de backups, haciendo imposible recuperar el original. A esto se suma el cambio a RAID 0: aunque sea la opción más rápida, implica confiar bastante en que esa configuración NVMe soporte esa carga.
    Espero que tengan buenos backups. Una buena solución sería levantar un servidor temporal, restaurar el backup y hacer una verificación completa de los datos; si funciona, también se validan el procedimiento de backup/restauración y la integridad de los archivos. Aun así, deberían asegurar margen para terminar la verificación RAID en el servidor principal, y sería mejor no usar RAID 0 por rendimiento.

    • Es cierto que los dos métodos no son equivalentes, pero para este caso de uso es suficiente. Si detectan corrupción de datos, pueden descartar el archivo y volver a descargarlo o regenerarlo.
      Es un dataset disponible libremente, solo que bastante grande. https://en.wikipedia.org/wiki/Endgame_tablebase lo explica mejor. Por eso tampoco hacen backups.
  • También existe lishogi, pero todavía es pequeño y no está en una escala que requiera este tipo de optimización.
    Entre las variantes de ajedrez, el shogi es la más divertida; el xiangqi no tanto.

  • Me pregunto si se puede interpretar lichess como una lich femenina, algo como baron/baroness.

    • Los títulos nobiliarios no son una buena comparación. Son un raro ejemplo donde realmente existe una raíz exclusiva masculina; la mayoría de las palabras tienen raíces neutras y, aunque haya formas masculinas o femeninas, requieren afijos.
      Estrictamente, un lich masculino sería “werlich”, uno femenino sería “wiflich”, y el plural llevaría “-en”. Pero para los no muertos el género suele ser irrelevante, así que la forma neutra se usa abrumadoramente más.
      “lichess” es una combinación extraña de raíces alemanas y francesas, por lo que naturalmente no se distingue de otras palabras del inglés.
    • Significa Libre chess, es decir, ajedrez libre y de código abierto.
  • No es una comparación justa, pero la calidad de ingeniería del equipo de Lichess realmente impresiona. Su principal competidor presume su migración a GCP, pero sufrió caídas repetidas a medida que creció su popularidad, y calculo que tiene unas 100 veces más personal.
    El punto débil de Lichess era la app móvil, pero la v2 rehecha en Flutter ya está bastante buena aunque todavía esté en beta.
    Y también hay que recordar que Thibault ni siquiera cobra 60 mil dólares al año como remuneración.

    • No creo que deba sentirse culpable por subirse el sueldo. Si lo sube a 200 mil dólares al año y hace su vida más cómoda, a largo plazo eso solo puede ser bueno para el proyecto.
    • Lichess es un servicio excelente para jugadores casuales de ajedrez como yo que quieren jugar una partida rápida contra otra persona. Casi nunca hay que esperar.
      Eso sí, me da curiosidad cómo se pronuncia Lichess: ¿Lie chess, Le chess o League chess?
    • Lichess parece un buen ejemplo de lo eficiente que Wikipedia podría haber sido tanto en código como en organización.
    • Creo que estás sobreestimando bastante cuántos desarrolladores tiene Chess.com.