Volver

Building Exten: el motor de OVHcloud para Block Storage NVMe

Tristan Groléat06/08/20267 minutos de lectura

Building Exten: el motor de OVHcloud para Block Storage NVMe

Fiable y perfectamente integrado con OpenStack, Ceph ha sido nuestra solución de Block Storage durante años, pero, para ofrecer un mayor rendimiento a un coste más bajo, adquirimos Exten. Ahora podemos desarrollar nuestra propia solución de Block Storage NVMe con C++ y Go. Nuestros principales objetivos de desarrollo son:

  • utilizar unidades NVMe para ofrecer volúmenes de alto rendimiento;
  • utilizar algoritmos de codificación avanzados para reducir el espacio necesario en las unidades (codificación Reed-Solomon y compresión);
  • mantener clústeres pequeños y fáciles de gestionar.

Exten lleva ya más de un año en producción. En este artículo explicamos en detalle cómo funciona y qué nuevas posibilidades permitirá su arquitectura.

Al final del artículo encontrarás un enlace para compartir tus comentarios y ayudarnos a definir el futuro de Exten.

GRPC RAFT CONSENSUS

Anatomía de un clúster

Cada clúster Exten está compuesto por seis servidores. Estos servidores se encuentran lo suficientemente cerca entre sí para mantener una latencia baja, pero no tanto como para aumentar el riesgo de que varios fallen simultáneamente. Los servidores cuentan con varias decenas de unidades NVMe para almacenar los datos de los usuarios.

Exten se basa en el protocolo NVMe. Utiliza unidades NVMe, pero también el protocolo NVMe over Fabrics (NVMe-oF) para exponer los volúmenes de los usuarios y comunicarse entre hosts. Los volúmenes son unidades virtuales que los clientes pueden conectar a sus máquinas virtuales (VM). Este protocolo utiliza los mismos comandos que las unidades NVMe, pero a través de una conexión de red (TCP o RDMA), y está diseñado para ofrecer un alto rendimiento y una baja latencia.

Una de las ventajas de NVMe over Fabrics (NVMe-oF) es que el kernel de Linux lo admite de forma nativa. Conectar un volumen Exten a un host Linux es tan sencillo como ejecutar el comando nvme connect con los parámetros correctos: el volumen aparece como cualquier otro disco NVMe local. Como cliente de Public Cloud, no tienes que preocuparte por nada de esto: el volumen simplemente se conecta a tu instancia, igual que ocurre con Ceph.

Exten se divide en un plano de datos, desarrollado en C++, y un plano de control, desarrollado en Go. Ambos se comunican mediante gRPC. El plano de datos recibe las operaciones de I/O a través de NVMe over Fabrics y las dirige a las unidades NVMe. El plano de control proporciona una API para crear y eliminar volúmenes, así como para gestionar el clúster.

Cómo proteger tus datos

Garantizar la seguridad de los datos de los clientes es una de las principales responsabilidades de un clúster Exten, y lo gestionamos en varios niveles.

En el plano de control, utilizamos el conocido algoritmo de consenso Raft para garantizar la integridad del clúster de forma tolerante a fallos. Para ello, se elige un líder y se registra cada dato nuevo (como la creación de un volumen o la activación de una unidad) en un registro que se replica en todos los hosts. Si un host falla, los demás siguen funcionando. La única condición es que la mayoría de los hosts permanezca operativa para evitar problemas de «split-brain» (cerebro dividido). Por eso, un clúster de seis nodos puede perder dos hosts y seguir funcionando.

Los datos de los usuarios, es decir, las operaciones de I/O que se realizan sobre los volúmenes, no pasan por Raft, ya que esto supondría una latencia demasiado elevada. En su lugar, utilizamos otro algoritmo conocido: la codificación Reed-Solomon.

Este código de corrección de errores es conceptualmente bastante sencillo. Tomemos como ejemplo RS 4+2: dividimos los datos en cuatro partes del mismo tamaño y, a continuación, calculamos otras dos partes del mismo tamaño. Si podemos leer cuatro de esas seis partes, podemos recuperar los datos originales: el código permite reconstruir las dos partes que faltan. Esto da una relación de 1,5 (datos almacenados / datos recibidos), por lo que podemos perder dos unidades sin perder ningún dato. Es una forma muy eficiente de añadir redundancia. La alternativa más sencilla —habitualmente denominada mirroring o replicación, que consiste simplemente en copiar todos los datos varias veces en distintas unidades— necesitaría tres copias para poder soportar la pérdida de dos unidades. Con Reed-Solomon, almacenamos la mitad de datos para el mismo nivel de redundancia.

Los fallos de una unidad pueden detectarse de dos formas: porque una operación de lectura falla directamente o porque la unidad devuelve datos corruptos. Esto se comprueba gracias a un «checksum» que se añade a cada sector. Cuando se detecta un fallo, un proceso automático reconstruye los datos que faltan y los almacena en una unidad que funciona correctamente, evitando así el riesgo de pérdida de datos.

I/O de alto rendimiento

A medida que las CPU y la RAM son cada vez más rápidas, el almacenamiento también tiene que seguirles el ritmo. El objetivo de Exten es aprovechar al máximo el hardware sobre el que se ejecuta y ofrecer a los clientes un rendimiento de I/O elevado. Elegir el protocolo NVMe over Fabrics es un primer paso para minimizar la sobrecarga de las operaciones de I/O, pero todo el stack de software está diseñado pensando en el rendimiento.

El modelo de procesamiento está centrado en los datos. En el nivel de la tarjeta de interfaz de red (NIC), recibimos y enviamos datos mediante una lista de buffers de tamaño fijo almacenados en RAM. Una CPU determinada procesa cada buffer con dos objetivos: evitar copias de datos y evitar cambios de contexto.

Para evitar las copias de datos, el código manipula buffers preasignados mediante punteros desde la NIC hasta la unidad de almacenamiento, y solo se modifican los datos cuando es inevitable (compresión, codificación Reed-Solomon, etc.). Asimismo, para impedir los cambios de contexto, gestionamos las operaciones de I/O mediante métodos totalmente asíncronos que trabajan con pequeñas cantidades de datos. Una determinada CPU procesa un buffer tanto como sea posible antes de pasar al siguiente, pero hay que encontrar un equilibrio: el siguiente buffer no puede esperar demasiado y el procesamiento debe seguir siendo equitativo. Para responder a estas necesidades, desarrollamos todo un framework en C++ diseñado específicamente para este propósito, que permite mantener el código claro y fácil de mantener.

Más allá del propio código, hay otros factores que también contribuyen a mejorar el rendimiento:

  • La elección del algoritmo de compresión (a veces la mejor opción es no comprimir, por ejemplo, en el tráfico cifrado)
  • La elección del protocolo de red: RDMA es más rápido que TCP, pero implica más restricciones de implementación
  • La forma en que asignamos núcleos de CPU a los volúmenes

En nuestras ofertas de Public Cloud, también aplicamos reglas de QoS para garantizar un reparto equitativo de los recursos entre todos los volúmenes.

Próximos pasos para Exten

Exten ya está en producción y actualmente proporciona volúmenes a clientes de Public Cloud. Es transparente para los clientes y, por ahora, ofrece las mismas prestaciones que Ceph, pero se basa en un stack de software que controlamos por completo y que está diseñado en torno a NVMe para ofrecer un alto rendimiento.

Seguimos mejorando de forma constante, con el objetivo de ofrecer a nuestros clientes volúmenes de mayor rendimiento, más flexibilidad y mayor fiabilidad. Por ejemplo, estamos estudiando el uso de RDMA para mejorar el rendimiento (actualmente utilizamos TCP).

El primer paso en el recorrido de Exten fue ofrecer una solución fiable que sustituyera a Ceph. Ahora que controlamos todo el stack, estamos preparados para añadir nuevas funcionalidades y adaptar este servicio a las necesidades de nuestros clientes.

¿Qué casos de uso de Block Storage crees que deberíamos conocer? ¿Hay alguna funcionalidad que eches en falta? Cuéntanoslo en Discord o en la lista de correo de cloud. Tu feedback nos ayuda a marcar el rumbo de Exten.


Compartir en: