Desarrolladores de la empresa Cloudflare sobre la realización de trabajos para optimizar el rendimiento del cifrado en disco en el núcleo de Linux. Como resultado, se prepararon para el subsistema y Crypto API, que permitieron aumentar más de dos veces el rendimiento en pruebas sintéticas al leer y escribir, así como reducir las latencias a la mitad. En pruebas con hardware real, los gastos generales del cifrado se redujeron prácticamente al nivel observado al trabajar con discos sin cifrado de datos.
Cloudflare utiliza dm-crypt para cifrar datos en los dispositivos de almacenamiento utilizados para almacenar en caché contenido en la red CDN. Dm-crypt opera a nivel de dispositivo de bloque y realiza el cifrado de las solicitudes de entrada/salida de escritura y la descifrado de las solicitudes de lectura, actuando como una capa entre el dispositivo de bloque y el controlador del sistema de archivos.
Para evaluar el rendimiento de dm-crypt utilizando el paquete se midió la velocidad de operación con particiones cifradas y no cifradas en un disco RAM, ubicado en la RAM para eliminar fluctuaciones en el rendimiento de los discos y enfocarse en el rendimiento del código. Para las particiones no cifradas, el rendimiento de lectura y escritura se mantuvo en 1126 MB/s, pero al activar el cifrado, la velocidad se redujo 7 veces y alcanzó 147 MB/s.
Al principio, surgió la sospecha de que se estaban utilizando algoritmos ineficaces en la criptosistema del núcleo. Pero en las pruebas se utilizó el algoritmo más rápido aes-xts con una clave de 256 bits, cuyo rendimiento en la ejecución de 'cryptsetup benchmark' es más de dos veces superior al resultado obtenido en las pruebas del disco RAM. Los experimentos con las banderas de dm-crypt para ajustar el rendimiento no dieron resultados: al usar la bandera '--perf-same_cpu_crypt', el rendimiento incluso disminuyó a 136 MB/s, y al indicar la bandera '--perf-submit_from_crypt_cpus' solo aumentó a 166 MB/s.
Un análisis más profundo de la lógica de funcionamiento mostró que dm-crypt no es tan simple como parece: al recibir una solicitud de escritura del controlador del sistema de archivos, dm-crypt no la procesa de inmediato, sino que la coloca en la cola 'kcryptd', la cual no se procesa de inmediato, sino cuando se presenta un momento adecuado. Desde la cola, la solicitud se envía a la API de Criptografía de Linux para realizar la encriptación. Pero dado que la API de Criptografía utiliza un modelo de ejecución asíncrono, la encriptación también se realiza no de inmediato, sino eludiendo otra cola. Después de completar la encriptación, dm-crypt puede intentar realizar la ordenación de las solicitudes de escritura pendientes utilizando un árbol de búsqueda. . Al final, un hilo separado del núcleo nuevamente recoge las solicitudes de entrada/salida acumuladas con cierta demora y las envía a la pila del dispositivo de bloques.
Al leer, dm-crypt primero añade a la cola 'kcryptd_io' una solicitud para obtener datos del almacenamiento. Después de un tiempo, los datos se vuelven disponibles y se colocan en la cola 'kcryptd' para su descifrado.
Kcryptd envía la solicitud a la API de Criptografía de Linux, que descifra la información en modo asíncrono. Las solicitudes no siempre pasan por todas las colas, pero en el peor de los casos, una solicitud de escritura puede quedar estancada en las colas hasta 4 veces, y una solicitud de lectura hasta 3 veces. Cada entrada en una cola provoca la aparición de retrasos, que son la causa clave de la significativa reducción del rendimiento de dm-crypt.
La utilización de colas se debe a la necesidad de operar en condiciones de interrupciones. En 2005, cuando se implementó el modelo actual de funcionamiento de dm-crypt basado en colas, el Crypto API aún no era asíncrono. Después de que se trasladó el Crypto API a un modelo asíncrono, se aplicó esencialmente una protección doble. Las colas también se introdujeron para ahorrar el consumo de la pila del núcleo, pero tras su aumento en 2014, estas optimizaciones perdieron relevancia. Se introdujo una cola adicional 'kcryptd_io' para superar el cuello de botella que causaba la espera por la asignación de memoria ante un gran número de solicitudes. En 2015, se añadió una fase de ordenamiento, ya que las solicitudes de cifrado en sistemas multiprocesador podían finalizar sin seguir el orden de envío (en lugar de acceso secuencial al disco, se realizaba acceso aleatorio, y además el programador CFQ no funcionaba de manera eficiente). Actualmente, al utilizar unidades SSD, el ordenamiento ha perdido sentido, y el programador CFQ ya no se utiliza en el núcleo.
Dado que los dispositivos modernos se han vuelto más rápidos e inteligentes, el sistema de distribución de recursos en el núcleo de Linux ha sido revisado y algunos subsistemas han sido reformados, ingenieros de Cloudflare. En dm-crypt, hay un nuevo modo de operación que elimina el uso de colas innecesarias y llamadas asíncronas. Este modo se activa con un flag separado 'force_inline' y convierte a dm-crypt en una forma de proxy simple, cifrando y descifrando las solicitudes entrantes. La interacción con el Crypto API se ha optimizado mediante la selección explícita de algoritmos de cifrado que operan de manera sincrónica y no utilizan colas de solicitudes. Para operar sincrónicamente con el Crypto API, se un módulo que permite usar FPU/AES-NI para acelerar y pasar directamente las solicitudes de cifrado y descifrado.
Como resultado, al probar el disco RAM, se logró más de duplicar el rendimiento de dm-crypt: el rendimiento aumentó de 294 MB/s (2 x 147 MB/s) a 640 MB/s, lo cual está muy cerca del rendimiento del cifrado puro (696 MB/s).
Durante las pruebas de carga en servidores reales, la nueva implementación mostró un rendimiento muy cercano a la configuración que opera sin cifrado, y la activación del cifrado en los servidores con la caché de Cloudflare no afectó la velocidad de respuesta. En el futuro, Cloudflare planea integrar los parches preparados en el núcleo principal de Linux, pero antes de eso, necesitarán ser reestructurados, ya que están optimizados para una carga específica y no cubren todas las aplicaciones, como el cifrado en dispositivos embebidos de bajo rendimiento.
Fuente: opennet.ru
