Mostrando entradas con la etiqueta transaccionalidad. Mostrar todas las entradas
Mostrando entradas con la etiqueta transaccionalidad. Mostrar todas las entradas

jueves, mayo 07, 2009

De BetFair a TradeFair. Historia de un motor transaccional.

jueves, mayo 07, 2009 por Martín


He estado viendo esta charla publicada hace unos días en InfoQ en la que el CTO de BetFair.com comenta como fue evolucionando su sistema de gestión de transacciones y como construyeron un motor capaz de funcionar tanto para apuestas deportivas como para mercados financieros.

El contenido de la charla es bastante interesante, aunque la charla en sí no es nada amena, así que no sabría si recomendárosla. Creo que sólo si os gusta el tema.

Uno de los comentarios interesantes de la charla es que parece que Oracle les comentó que BetFair puede ser una de las cinco aplicaciones más "calientes" del mundo en cuanto a contención de recursos.

En su caso el problema no es tanto la escalabilidad sino más bien el mantener el rendimiento del servidor durante determinadas ventanas de tiempo. En su web normalmente la mayoría de usuarios se concentran únicamente en torno a determinados eventos 'live'. Una vez que esos eventos terminan, los usuarios se mueven a otro evento. Un ejemplo es una carrera de caballos. La carrera empieza, se va sucediendo, termina y los usuarios se mueven a la siguiente carrera.

Todo esto los deja con que el problema pasa a ser un problema de optimización. ¿Cómo conseguir que el sistema se mantenga ejecutándose con un buen rendimiento de manera continua?

La gestión del riesgo y gestión de apuestas es mucho más sencilla ya que se puede dividir en clientes o cuentas, lo que permite fácilmente particionar y procesar en paralelo. La actividad de cada cuenta en estos sistemas suele ser pequeña, es decir, ningún usuario está ahí sentado en su ordenador ejecutando 50.000 apuestas por segundo.

La vista de mercado es read-only lo que les permite una serie de optimizaciones. El multi-casting es común para enviar el estado de las apuestas a diferentes clientes. Eso funciona para sus clientes de escritorio pero en la web tienen problemas. Ahora mismo utilizan polling. Están intentando migrar a una aproximación basada en streaming y comet pero todavía no estaba acabado.

En cuanto a la transaccionalidad, ahí es donde las cosas se tornan complejas. El objetivo de BetFair era pasar de las 500 TPS a las 50000 TPS. Para ello mantuvieron diferentes rondas de entrevistas con equipos y empresas clave, como puedan ser las compañías que desarrollan los mercados de valor por ejemplo. Pero aparentemente ninguna solución se ajustaba exactamente al modelo de BetFair. Les propusieron una especie de competición para conseguir el motor más rápido (asumo que o bien les pagaron o bien compartiron la propiedad intelectual), y BetFair salió ganando.

Todo el modelo de transaccionalidad se basa en el control programático de las transacciones, lo que muchas veces les obliga a compensar transacciones cuando hay que hacer algún rollback; en el uso de mensajería; y finalmente en el mantener enormes registros de auditoría con todas las operaciones. De modo que si algún servidor o algún agente se cae, puedan replicar todas las acciones que había pendientes.

Respecto a la alta disponibilidad, su reto era que si se caia un agente, tener otro listo para continuar sirviendo peticiones. Básicamente una estrategia activo/pasivo. Sólo uno está ejecutando el mercado en un momento dado, pero si algo falla, el segundo tomará el relevo. Evaluaron numerosas posibilidades (relatadas en la charla), pero al final se quedaron con el log tailing, que básicamente viene siendo que el agente pasivo lee los logs del activo y va replicando todas sus acciones.

Ya al final de la charla dedican unos quince minutos a hablar de como evolucionaron de BetFair a TradeFair y los retos que eso suponía. Partían de su motor, FlyWheel, capaz de ejecutar decenas de miles de transacciones por segundo, pero que sin embargo tenía unos niveles de latencia altos y no consistentes, algo no aceptable para los mercados financieros. Ese fue básicamente su principal reto. Entre las soluciones pues básicamente el intentar evitar la escritura a disco, controlar la recolección de basura y la instanciación de objetos, y también regular sus tasas de transferencia (throttling throughput).

sábado, julio 26, 2008

Mensajería, escalabilidad, transacciones y tolerancia a fallos

sábado, julio 26, 2008 por Martín


Uno de los principios más importantes de la escalabilidad es el procesado asíncrono de datos. En una llamada síncrona, todo punto de integración constituye un nuevo riesgo, una nueva dependencia, un nuevo riesgo de quedarse bloqueado esperando por un recurso que nunca llegará o por un hueco en ese ansiado pool de conexiones que se nos ha quedado pequeño.

Por otra parte, uno de los principios más importantes de la integridad de datos es la transaccionabilidad. Si juntamos ambos conceptos, mensajería y transaccionabilidad, entramos en un nuevo mundo de retos y problemas, que unas veces serán sencillos de solucionar y que otras veces requerirán otra serie de artimañas más avanzadas para la gestión de errores.

Es sobre esto último de lo que trata un excelente artículo de Udi Dahan publicado en la MSDN. El autor recorre los problemas más comunes que nos encontramos en la integración de sistemas utilizando mensajería y como afrontarlos y resolverlos de manera robusta. Entre los temas tratados:


  • Persistencia de mensajes: Es decir el configurar nuestro broker de mensajería para que almacene, normalmente en base de datos, los mensajes de modo que se puedan reenviar posterioremente en caso de algún problema.

  • Consistencia transaccional: ¿Qué pasa si enviamos un mensaje y avisamos a un tercer sistema de ese cambio pero de pronto se hace un rollback del mensaje? El soporte de transacciones en los brokers y el uso del commit en dos fases resuelve este problema, pero a veces es overkilling.

  • Uso de colas de errores: Enviamos un mensaje ... y falla; lo volvemos a enviar ... y falla; probamos otra vez... vuelve a fallar. ¿Qué hacemos? Podemos seguir y seguir (y en el 99.99% de los casos seguirá y seguirá fallando) lo que consumirá importantes recursos de nuestro sistema, podemos lavarnos las manos e imprimir la traza de error, o podemos enviarlo a una cola de errores, donde más tarde los revisaremos, lo cual parece una muy buena opción.

  • Tamaño de los mensajes: Aquí el autor hace un excelente análisis sobre la diferencia entre procesar miles de mensajes pequeños y unos cuantos cientos de mensajes enormes.
    TimeToProcess(BigMessage) >> N x TimeToProcess(SmallMessage) where
    Size(BigMessage) == N x Size(SmallMessage)

    Los requisitos del procesado de mensajes grandes en cuanto a validación (CPU, memoria), almacenamiento en caso de mensajería duradera(CPU, disco), o congestión de red (optimización de paquetes) son mucho más exigentes y a menudo la única solución es el partir el mensaje original en mensajes mucho más pequeños y sencillos de procesar.



En resumen, en mi opinión excelente artículo para el que le gusten los temas de mensajería, procesado asíncrono de datos y transacciones, y lectura recomendada.

miércoles, julio 02, 2008

Tuneando transacciones con Spring

miércoles, julio 02, 2008 por Martín



Hace unos días escribía sobre la disponibilidad de las charlas de la SpringOne 2008. Una que he leido recientemente es la de Jurgen Holler, Transaction Choices for Performance, y en la que se entra en detalle sobre los diferentes tipos de transacciones en Spring y sobre como evitar las transacciones XA en la medida de lo posible.

Muchos de los que leen este blog sabrán lo que es XA, aunque supongo que otros no. Básicamente es una especificación que define como sincronizar el acceso a recursos totalmente diferentes dentro de una misma transacción, para lo que se utilizar un gestor de transacciones global. Un ejemplo sería el realizar desde un mismo método un acceso a base de datos y enviar un mensaje a algún broker de mensajería. XA te garantiza que el método se ejecutará preservando las propiedades ACID entre las diferentes llamadas.



En el screencast de arriba( y esto es una prueba y una excusa para probar este servicio ) os muestro un caso muy típico en el que se necesitaría sincronizar una base de datos y un servidor de mensajería. El método A actualiza la base de datos, envía un mensaje a una cola, realiza un proceso y termina su ejecución. Mientras tanto, en otra parte del sistema, un consumidor lee asíncronamente el mensaje en B y consulta la base de datos. ¿Cuál es el problema? Pues que como la cola de mensajería y la base de datos tienen sus propios gestores de transacciones, resulta que es muy probable que el mensaje llegue a B cuando la transacción en A todavía no se ha persistido en la base de datos, con lo que el consumidor estaría leyendo un valor incorrecto (ver phantom reads si no se es familiar con este concepto).

Utilizar XA soluciona este problema ya que un gestor de transacciones global se encargá de sincronizar todos los recursos de forma que por ejemplo el mensaje no se envie hasta que no se haya hecho commit de la transacción (aunque en realidad dependería de la implementación del gestor transaccional). A simple vista utilizar XA parece claramente una buena idea. Sin embargo, hay un problema muy importante, XA es enormemente lento. Muchísimo más lento que utilizar transacciones simples ( o que no usar transacciones ). Jurgen desmonta unos cuantos mitos sobre las transacciones XA en su presentación:

Me permito traducir los puntos:

  • Una aplicación empresarial crítica y seria necesita transacciones XA: No es cierto, muchas aplicaciones empresariales no utilizan para nada transacciones XA.

  • Una mapeo objeto-relacional correcto requiere el uso de XA: No es cierto, los mapeadores objeto-relacional normalmente operan con JDBC más un sistema de caché propio.

  • Para combinar JDBC y JMS las transacciones XA son obligatorias: No es cierto, muchas aplicaciones empresariales utilizan JMS con transacciones nativas o ACKs.

  • Los gestores de transacciones modernos están optimizados para ofrecer el mejor rendimiento: No es cierto, las garantías que XA exige son costosas y no pueden ser optimizadas de forma tan sencilla.



Siguiendo con la presentación, la principal recomendación de Jürgen es que una de las formas para solucionar el problema planteado arriba es sincronizar de manera nativa la cola de Spring con el gestor transaccional que utiliza el DataSource de forma que el mensaje sólo se enviará cuando se termine la ejecución del primer método y se haga commit de la transacción lo que tiene la ventaja de no usar XA y tener un mayor throughput.

Es curioso además que hoy hablando con alguien, me comentaba que algunos bancos no estaba interesados en absoluto en utilizar XA, y aconsejaban a sus proveedores el no incurrir en este tipo de transacciones ya que eran demasiado costosas para sus servidores que albergan tantas y tan heterogéneas aplicaciones. No estoy muy seguro de lo que hay de cierto en esto, pero puede que tenga sentido :)

viernes, abril 27, 2007

La reina de las transacciones

viernes, abril 27, 2007 por Martín

Curioseando por blogs relacionados con mi trabajo, he llegado a esta entrada de Chris Skinner, donde explica algunos detalles sobre lo que podríamos llamar la compañía reina de las transacciones.... Visa.

Algunos datos que quitan el hipo:

  • 1.6 billones de tarjetas en circulación.
  • 6.803 transacciones por segundo en hora punta.
  • 56.3 billones de transacciones en el 2006.
  • 4.5 trillones de dólares en volumen transaccional el pasado año.
  • Su red se ha construido sobre 9 millones de millas de cable que se extienden a lo largo de todo el mundo.


Por último, siguiendo las cuentas de Mr. Skinner parece que Visa procesa... ¡más transacciones en un minuto en hora punta que todas las bolsas del mundo!

Bueno, esto habría que corroborarlo la verdad, porque la cifra de transacciones por segundo con la que se hace el cálculo es en la hora punta del año, es decir en Navidad. Pero vamos, que desde luego las cifras marean.

Sería muy interesante encontrar material donde explique las arquitecturas para manejar este monstruo transaccional. Si alguien lo tiene... ya sabe :)