Con la cada vez mas cercana salida a RTM de la próxima versión de SQL Server 2014, aparece un nuevo motor relacional. Su anterior nombre en clave “Hekaton” ha sido sustituido por uno que no da lugar a dudas “In-Memory OLTP”. Es un nuevo motor relacional optimizado para datos residentes en memoria y cargas de trabajo tipo OLTP. Téngase presente que este motor surge como la motivación en Microsoft, de llegar a aumentar 100 veces el rendimiento de SQL Server en entornos puramente OLTP.

En esta entrada voy a hacer un resumen de este nuevo motor, para que te vayas haciendo al ánimo de que por fín las cosas van a cambiar radicalmente a la hora de hacer soluciones de alto rendimiento :).

El motor en memoria incluido en SQL Server 2014, al contrario de lo que ofrecen otros fabricantes se encuentra completamente integrado en el producto y por tanto no se trata de un sistema distinto. Se trata de un motor relacional completamente transaccional y persistente, que se utiliza exáctamente igual que el motor on-disk (mediante T-SQL) y que a simple vista, se encuentra completamente integrado en el producto, posibilitando una aparente transparencia a la hora de utilizarlo.

Aunque se trata de un motor completa y radicalmente diferente al actual, ambos motores se comunican perfectamente y se permite por ejemplo realizar consultas que toquen objetos (tablas por ejemplo) de tipo on-disk e in-memory de forma transparente.

 

Las razones

Las razones de la aparición de este nuevo motor es que como parte de un proyecto interno de conseguir un aumento de rendimiento de 100X en SQL Server se realizaron investigaciones previas para determinar la mejor forma de hacerlo. Durante esa investigación, el equipo de Microsoft Research llegó a la conclusión de que la única forma de optimizar el rendimiento actual de SQL Server era por estas 3 vias:

  1. Reducir el número de ciclos por instrucción
  2. Mejorar la escalabilidad (uso de recursos HW mejor aprovechados)
  3. Disminuir el número de instrucciones ejecutadas por peticion

De dicho análisis, extrajeron la conclusión de que con los puntos 1 y 2, en el mejor de los casos se podrían llegar a obtener 3-4x rendimiento OLTP y que el punto 3 podia llegar a conseguir un 10X de rendimiento, pero reduciendo un 99% el nº de instrucciones a ejecutar…lo cual aparte de ser complejo hasta cotas insospechadas, dista mucho del ratio de 100X de mejora de rendimiento buscado.

Los principios de diseño con los que se ha creado el nuevo motor In-memory son los siguientes:

  1. Optimización de estructuras en memoria RAM
  2. Eliminar latches y bloqueos
  3. Compilación de codigo nativo maquina

 

Optimización de estructuras en memoria RAM

Los motores relacionales actuales basan su diseño en asumir que los datos se encuentran en disco y se crean estructuras en memoria para mapearlos y que su acceso sea mucho más optimo. En SQL Server conocemos a dicha area como buffer pool, y es donde residen las páginas con las que básicamente opera el motor relacional on-disk. Entonces…si actualmente ya se trabaja en memoria RAM…¿por qué un motor en memoria? Parecería que esto no tiene sentido hasta que entramos al detalle de realmente el funcionamiento de dicho motor on-disk. Al asumir estructuras de disco trasladadas a RAM, se incrementa obviamente la complejidad de los mecanismos de control de los datos. Hay que pensar que cuando se diseñaron la mayoria de motores relacionales se carecía principalmente de memoria RAM y se crearon estructuras como los buffer pool para optimizar utilizando el poco tamaño RAM de que s disponia. Pero esto ha cambiado y nos encontramos en una época donde no es dificil comprar hardware con 1Tb de memoria RAM, donde la mayoria de bases de datos OLTP caben de sobra.

En estos escenarios se pone el foco con el motor in-memory, escenarios donde la RAM ya no es el problema sino la propia arquitectura on-disk del motor relacional tradicional. No quiero entrar en detalles internos porque llevaría mucho tiempo, pero básicamente tenemos que tener en cuenta que tradicionalmente en un entorno con alta concurrencia, el acceso a una página de datos en RAM debe ser protegida por ejemplo de otros hilos mientras es accedida (concepto de latch). En entornos con alto número de CPUs e hilos accediendo simultáneamente a las mismas estructuras, resulta que el mismo proceso de protección de datos se convierte en cuello de botella del sistema (recordemos que se busca un aumento de rendimiento del 100x)

Teniendo esto presente, el motor in-memory oltp que aparece en SQL Server 2014 posee estructuras pensadas para trabajar directamente en RAM, que no tienen equivalencia directa con nada de lo que se ha visto hasta ahora. Estas estructuras se conocen como in-memory indexes y tenemos de dos tipos:

  1. HASH
  2. Bw-tree

NOTA: La durabilidad de los datos se mantiene mediante logging y checkpoints a una estructura parecida al log de transacciones pero altamente optimizado. Esto queda de momento fuera de este artículo

 

Eliminar latches y bloqueos

Dado que hoy por hoy no es dificil tener decenas o cientos de CPU en máquinas de procesamiento OLTP, el problema que salpica como comentamos es que en escenarios de una altísima concurrencia, los propios locks a estructuras de datos de memoria compartida son un cuello de botella importante. Construir un motor OLTP pensando en escalabilidad máxima pasa por tanto por eliminar latches y bloqueos…y es lo que se consigue con el motor In-memory OLTP. En este motor, conceptos como el memory allocator, los índices hash o Bw-tree o los transaction map no se rigen por locks y latches.

El motor in-memory OLTP está basado en:

  1. control de concurrencia optimista
  2. multiversion de filas
  3. estructuras latch-free

NOTA: En este motor no existen muchos de los conceptos a los que estamos acostumbrados: latch, lock, fill-factor,…

 

Compilación de código nativo máquina

Hasta ahora, tal como lo conocemos, un motor OLTP suele basar sus planes de ejecución en un intérprete que evalua en tiempo de ejecución el algoritmo seleccionado de acceso a datos. Este tipo de interpretes poseen una ventaja muy alta debido a su gran flexibilidad pero tienen un problema cuando tenemos puesta la vista en conseguir 100X rendimiento: El número de instrucciones a ejecutar para el acceso mas liviano (un simple lookup) tiene mas de 1000 instrucciones, con lo que el número de instrucciones a ejecutar es realmente elevado.

Si recordais, al principio del post estabamos hablando de que una de las formas de optimizar el rendimiento era precisamente eliminar el 99% de las instrucciones a ejecutar. Pues este motor posee su propio sistema de compilación nativo de instrucciones, para reducir al máximo el nº de ellas y que el rendimiento sea espectacular. El siguiente diagrama (publicado en el paper de microsoft research) nos muestra cómo ha cambiado el proceso de generacion de código para SP en in-memory oltp

Básicamente, lo que se ilustra a grandes rasgos es que una vez mandado a compilar un SP de tipo in-memory, este acaba siendo compilado a código C en forma de .dll y cargado al SQLOS. Por tanto, lo que a priori era una representación de plan de ejecución, ahora contiene el propio algoritmo de acceso a los datos de forma estática.

Lo siguiente es un ejemplo cualquiera de un SP compilado in-memory:

   1:  CREATE PROCEDURE [dbo].test_insert
   2:  WITH
   3:         NATIVE_COMPILATION,
   4:         SCHEMABINDING,
   5:         EXECUTE AS OWNER
   6:  AS
   7:  BEGIN  ATOMIC WITH (TRANSACTION    ISOLATION LEVEL = SNAPSHOT, LANGUAGE = 'us_english')
   8:  
   9:      INSERT INTO dbo.test (id)
  10:      SELECT top 1 id+1 from dbo.test order by id desc
  11:  END

 

Componentes clave

In-memory OLTP engine posee (al menos en esta CTP2 de SQL Server 2014) los siguientes componentes:

  • Metadata

Sus objetos son compatibles con el motor on-disk e incluyen las mismas estructuras como tablas, tipos, procedimientos almacenados…Se diferencian de los objetos on-disk en las restricciones que poseen y las cláusulas para indicar que deben ser creadas en el motor in-memory

  • Query optimization

Si se diseña el código para utilizar únicamente objetos in-memory, el compilador realiza la máxima optimización posible y de puede por tanto obtener el máximo rendimiento de este nuevo motor

  • Query interop

Dado que nada nos limita a realizar consultas T-SQL que toque objetos del motor on-disk e in-memory, el motor query interop se encarga de utilizar el mismo query plan interpretado, pero para acceso a tablas in-memory. De esta forma se pueden acceder a dichas estructuras aunque no se obtenga todo el potencial del motor

  • Transacciones

Se permiten transacciones entre ambos motores

  • Alta disponibilidad

El motor in-memory OLTP está completamente integrado en AlwaysOn, por lo que podemos tener una solución AlwaysOn que haga uso de tablas en memoria

  • Almacenamiento y log

Para mantener la persistencia de los datos en memoria, el motor in-memory OLTP utiliza un sistema de log de transacciones de forma especial. En lugar de escribirlo todo en el log como en un sistema transaccional normal, se utiliza un sistema de checkpoints bajo un grupo de ficheros especial (filestream por ahora) y únicamente se realiza flush al log de transaccciones en el momento de realizar el commit…y además se realiza en bloques, para buscar el máximo rendimiento posible.

 

Comparación de rendimiento

Las siguientes tablas de rendimiento las he extraido del propio paper de microsoft research sobre “Hekaton” y aunque obviamente no estamos en versión RTM, podemos hacernos una idea de lo que podremos conseguir con este nuevo motor OLTP. Sin duda, estamos de enhorabuena en lo que a mejoras OLTP se avecina en esta futura release de SQL Server 2014.

En sucesivos posts, seguro que vamos a ir desubriendo juntos las posibilidades que este nuevo motor nos trae de cara a mejorar el rendimiento en nuestros entornos OLTP con el hardware existente.

 

Bibliografía y documentación interesante

Consulta el paper oficial de microsoft Research sobre “Hekaton

Visiona el keynote del Dr Dewitt para PASS2013: https://www.youtube.com/watch?v=aW3-0G-SEj0&list=WL6AAA223C63D42F15

 

Enrique Catalá