La mayoría de los trabajos de programación de baja latencia / alta frecuencia (basados en especificaciones de trabajo) parecen implementarse en plataformas Unix. En muchas de las especificaciones hacen una solicitud particular para las personas con el tipo de experiencia "Linux de baja latencia".
Suponiendo que esto no significa un sistema operativo Linux en tiempo real, ¿podría la gente ayudarme con lo que esto podría referirse? Sé que puedes configurar la afinidad de la CPU a los subprocesos, pero supongo que están pidiendo mucho más que eso.
Kernel tuning? (aunque escuché que fabricantes como solarflare producen tarjetas de red de derivación del núcleo de todos modos)?
¿Qué pasa con DMA o posiblemente memoria compartida entre procesos? Si la gente me pudiera dar ideas breves, puedo ir y hacer la investigación en Google.
(Esta pregunta probablemente requerirá a alguien familiarizado con el comercio de alta frecuencia)
Respuestas:
He realizado una buena cantidad de trabajo apoyando a grupos HFT en entornos de IB y Hedge Fund. Voy a responder desde la vista sysadmin, pero algo de esto también es aplicable a la programación en tales entornos.
Hay un par de cosas que un empleador suele buscar cuando se refieren al soporte de "baja latencia". Algunas de estas son preguntas de "velocidad bruta" (¿sabe qué tipo de tarjeta de 10 g comprar y en qué ranura colocarla?), Pero más de ellas se refieren a las formas en que un entorno de Comercio de alta frecuencia difiere de un tradicional Entorno Unix. Algunos ejemplos:
Unix se ajusta tradicionalmente para admitir la ejecución de una gran cantidad de procesos sin privar a ninguno de ellos de recursos, pero en un entorno HFT, es probable que desee ejecutar una aplicación con un mínimo absoluto de sobrecarga para el cambio de contexto, y así sucesivamente. Como un pequeño ejemplo clásico, activar hyperthreading en una CPU Intel permite que se ejecuten más procesos a la vez, pero tiene un impacto significativo en el rendimiento de la velocidad a la que se ejecuta cada proceso individual. Como programador, también tendrá que mirar el costo de las abstracciones como el enhebrado y RPC, y descubrir dónde una solución más monolítica, aunque menos limpia, evitará gastos generales.
TCP / IP generalmente se ajusta para evitar caídas de conexión y hacer un uso eficiente del ancho de banda disponible. Si su objetivo es obtener la latencia más baja posible de un enlace muy rápido, en lugar de obtener el mayor ancho de banda posible de un enlace más restringido, querrá ajustar el ajuste de la pila de red. Desde el punto de vista de la programación, también querrá ver las opciones de socket disponibles y descubrir cuáles tienen los valores predeterminados más ajustados para el ancho de banda y la confiabilidad que para reducir la latencia.
Al igual que con las redes, con el almacenamiento: querrá saber cómo distinguir un problema de rendimiento de almacenamiento de un problema de aplicación y aprender qué patrones de uso de E / S tienen menos probabilidades de interferir con el rendimiento de su programa (como ejemplo, aprenda dónde la complejidad del uso de IO asíncrono puede ser rentable para usted y cuáles son las desventajas).
Finalmente, y más dolorosamente: los administradores de Unix queremos tanta información sobre el estado de los entornos que monitoreamos como sea posible, por lo que nos gusta ejecutar herramientas como agentes SNMP, herramientas de monitoreo activo como Nagios y herramientas de recopilación de datos como sar (1). Sin embargo, en un entorno donde los cambios de contexto deben ser minimizados y el uso del disco y la red IO estrictamente controlados, tenemos que encontrar la compensación correcta entre el gasto de monitoreo y el rendimiento básico de las cajas monitoreadas. Del mismo modo, ¿qué técnicas está utilizando que facilitan la codificación pero le están costando el rendimiento?
Finalmente, hay otras cosas que simplemente vienen con el tiempo; trucos y detalles que aprendes con experiencia. Pero estos son más especializados (¿cuándo uso epoll? ¿Por qué dos modelos de servidores HP con controladores PCIe teóricamente idénticos funcionan de manera tan diferente?), Más vinculados a lo que esté usando su tienda específica y más probabilidades de cambiar de un año a otro .
fuente
Además de la excelente respuesta de ajuste de hardware / configuración de @jimwise, "Linux de baja latencia" implica:
Muchas de estas técnicas se superponen con el desarrollo de juegos, que es una de las razones por las cuales la industria del software financiero absorbe a los programadores de juegos recientemente redundantes (al menos hasta que pagan sus atrasos en el alquiler).
La necesidad subyacente es poder escuchar un flujo de datos de mercado de gran ancho de banda, como los precios de seguridad (acciones, productos básicos, fx) y luego tomar una decisión muy rápida de compra / venta / no hacer nada basada en la seguridad, el precio y tenencias actuales.
Por supuesto, todo esto también puede salir espectacularmente mal .
Así que explicaré el punto de las matrices de bits . Digamos que tenemos un sistema de comercio de alta frecuencia que opera en una larga lista de pedidos (Buy 5k IBM, Sell 10k DELL, etc.). Digamos que necesitamos determinar rápidamente si se han completado todos los pedidos, para que podamos pasar a la siguiente tarea. En la programación tradicional de OO, esto se verá así:
La complejidad algorítmica de este código será O (N) ya que es un escaneo lineal. Echemos un vistazo al perfil de rendimiento en términos de accesos a la memoria: cada iteración del bucle dentro de std :: any_of () va a llamar a o.isFilled (), que está en línea, por lo que se convierte en un acceso a la memoria de _isFilled, 1 byte (o 4 dependiendo de su arquitectura, compilador y configuración del compilador) en un objeto de digamos 128 bytes en total. Entonces estamos accediendo a 1 byte en cada 128 bytes. Cuando leemos el 1 byte, suponiendo el peor de los casos, obtendremos un error de caché de datos de CPU. Esto provocará una solicitud de lectura a RAM que lee una línea completa de RAM ( consulte aquí para obtener más información ) solo para leer 8 bits. Entonces el perfil de acceso a la memoria es proporcional a N.
Compare esto con:
El perfil de acceso a la memoria de este, suponiendo el peor de los casos nuevamente, es ELEMS dividido por el ancho de una línea RAM (varía, podría ser de doble canal o triple canal, etc.).
Entonces, en efecto, estamos optimizando algoritmos para patrones de acceso a memoria. Ninguna cantidad de RAM ayudará: es el tamaño del caché de datos de la CPU lo que causa esta necesidad.
¿Esto ayuda?
Hay un excelente CPPC sobre todo sobre la programación de baja latencia (para HFT) en YouTube: https://www.youtube.com/watch?v=NH1Tta7purM
fuente
Como no puse uno o dos programas de alta frecuencia en producción, diría las cosas más importantes:
La única persona que realmente hace que el sistema realice operaciones de alta frecuencia es un informático que reúne el código en c ++
Entre los conocimientos utilizados se encuentra
A. Comparar e intercambiar operaciones.
El científico talentoso usará más. Debería encontrar en los nuevos "patrones" recientes uno que apareció primero en Java. Llamado patrón DISRUPTOR. Pliegue en el intercambio de LMAX en Europa explicó a la comunidad de alta frecuencia que la utilización basada en subprocesos en los procesadores modernos perdería el tiempo de procesamiento en la liberación de la memoria caché por parte de la CPU si la cola daya no está alineada con el tamaño de la caché de la CPU moderna = 64
Entonces, para esa lectura, hicieron público un código java que permite que el proceso de subprocesos múltiples use el caché de la CPU del hardware correctamente sin resoluciones de conflicto. Y un buen científico de la computación TIENE que encontrar que ese patrón ya fue portado a c ++ o portarse a sí mismo.
Esta es una forma de competencia más allá de cualquier configuración de administrador. Esto está en el corazón real de alta frecuencia hoy.
Y se sorprenderá al descubrir que la tubería se usa SOLO PARA la notificación del núcleo del mensaje recibido. Puede poner el número de mensaje de 64 bits allí, pero para el contenido, vaya a la cola CAS sin bloqueo. Activado por una
select()
llamada asíncrona del núcleo .Como puede ver, la alta frecuencia es un CAMPO EN DESARROLLO. No puede ser solo un programador de C ++ para tener éxito.
Y cuando digo tener éxito, quiero decir que el fondo de cobertura para el que trabajaría reconocerá los esfuerzos de la gira en compensación anual más allá del número de personas y reclutadores que hablan.
Los tiempos de las preguntas frecuentes de constructor / destructor simples se han ido para siempre. Y c ++ ... migró con nuevos compiladores para liberarlo de la administración de memoria y para forzar la no herencia de gran profundidad en las clases. Pérdida de tiempo. El paradigma de reutilización de código cambió. No se trata solo de cuántas clases hiciste en polimorfo. Se trata del rendimiento del código directamente confirmado en el tiempo que puede reutilizar.
Entonces, es su elección entrar en la curva de aprendizaje allí, o no. Nunca llegará a una señal de stop.
fuente