Aviso desde el principio: trabajo para croit, que ha escrito FlashStore. Todo lo que sigue está leído del código fuente y la documentación de Ceph en v21.2.0 y de la instantánea publicada de ceph-rust de croit, todo enlazado al pie de la página. Donde el razonamiento propio de croit está en un lado de un argumento, digo de quién es.

Dos reescrituras del mismo daemon

El OSD clásico de Ceph es un servidor C++ de hilos que se crió sobre discos giratorios. Con NVMe rápido y redes rápidas, gasta buena parte de su CPU en cosas que no son guardar tus datos: pasar operaciones entre pools de hilos, coger locks, esperar a otros hilos. Dos proyectos se han propuesto arreglarlo reescribiendo el OSD de arriba abajo.

Uno es Crimson, el del propio Ceph. La documentación de Umbrella lo llama «the next generation ceph-osd», construido «to deliver enhanced performance on fast network and storage devices»1. El otro es el OSD FlashStore de croit, del proyecto ceph-rust, en vista previa pública desde el 9 de noviembre de 20262.

Los dos dicen ser sustitutos directos. Los dos dicen ser para NVMe. Los dos están en vista previa, y ninguno debería guardar datos de producción hoy. Así que si tienes Ceph sobre NVMe y te preguntas a cuál seguirle la pista, merece la pena saber dónde se diferencian de verdad, porque no es donde sugieren los titulares.

Aquí se comparan tal como los encontrarías en Ceph 21.2.0, Umbrella: Crimson tal como esa versión lo documenta y lo distribuye, frente a FlashStore, que se compila y se prueba contra esa misma versión2. Sigue a FlashStore frente a BlueStore de Umbrella, y todo lo que allí ya se contó sobre FlashStore se da por sabido.

Dos reescrituras de un mismo daemonceph-osd clásicoC++, hilosCrimsonCeph upstream, C++ sobre Seastarcroit-flashstore-osdcroit, Rust, runtime propioBlueStorepor defectoSeaStorenativoCyanStoresin datosFlashStoreel único almacén
Dos reescrituras del OSD clásico. Crimson mantiene tres almacenes para elegir, y BlueStore es el predeterminado; FlashStore tiene uno.

De dónde sale cada uno

La primera diferencia es quién lo construye y cómo.

CrimsonFlashStore
Lo construyeCeph upstream, en el árbol principalcroit
LenguajeC++Rust
FrameworkSeastarexecutor monohilo propio de croit
Códigoen ceph/cephreescritura en sala limpia, sin código de Ceph enlazado
Desarrolloupstream, abiertoinstantáneas de solo lectura en la vista previa; abierto tras la primera versión de producción
Licenciala de Cephdaemon LGPL-3.0, clientes MPL-2.0
Estado, en sus propias palabras«not suitable for production use»«not yet recommended for production data»
GA previstano indicadaT1 2027

Crimson vive en el repositorio del propio Ceph y lo construyen los propios desarrolladores de Ceph. Está escrito sobre Seastar, un framework en C++ para servidores de un hilo por núcleo que salió de ScyllaDB3. La documentación de Umbrella dice sin rodeos que «is in a tech-preview stage and is not suitable for production use»1.

FlashStore está escrito desde cero en Rust y no enlaza nada de código de Ceph; el C++ de Ceph se lee como referencia y se vuelve a implementar a partir de las especificaciones propias de croit4. Su README dice que es para pruebas y evaluación y «not yet recommended for production data», con la disponibilidad general prevista para el primer trimestre de 20272. El repositorio público es una instantánea de solo lectura: «no issue tracker, no contribution workflow»2.

Esa fila merece una lectura atenta. Crimson se desarrolla a la vista, y cualquiera puede leer los pull requests y discutir en ellos. FlashStore, de momento, llega como instantáneas terminadas de una sola empresa: puedes leer cada línea, pero todavía no puedes mandarle un parche. Eso es la fase de vista previa, no el plan. La vista previa está ahí para recoger las opiniones de la comunidad mientras croit pasa internamente sus casos de prueba de producción, antes de marcar el OSD como seguro para su uso. El desarrollo abierto llega tras esa primera versión de producción, el mismo camino que siguen la mayoría de los proyectos de código abierto respaldados por una empresa. Eso viene de dentro de croit y no de una hoja de ruta publicada, así que exígeles que lo cumplan.

croit sí se planteó hacer un fork de Crimson, y dejó por escrito por qué no lo hizo. Su ADR dice que Crimson «tries to support everything (HDD, alienstore/BlueStore, all pool types)», y añade «Complex code is never fast»4. Esa es la opinión de croit sobre Crimson, no una medición, y yo la trataría como tal. El mismo ADR también rechazó el fork en parte por la LGPL4, y croit licenció después su propio daemon como LGPL-3.0 ocho días más tarde5. Así que la licencia nunca fue de verdad el motivo.

Seguridad de memoria: Rust frente a C++

Un OSD es el código que guarda tus datos. Un use-after-free o un desbordamiento de búfer ahí dentro no es un fallo del que te recuperas reiniciando; son datos corruptos en el disco, copiados a cada réplica. Esa es exactamente la clase de error que las agencias de ciberseguridad occidentales llevan tres años diciéndole a la industria que elimine desde el diseño.

GuíaQuién la firmaQué dice
The Case for Memory Safe Roadmaps, diciembre de 2023CISA, NSA y FBI (EE. UU.), ASD’s ACSC (Australia), CCCS (Canadá), NCSC-UK, NCSC-NZ, CERT-NZC y C++ no son seguros en memoria; publica una hoja de ruta para dejarlos
Product Security Bad Practices v2.0, enero de 2025CISA y FBIlas líneas de producto nuevas para infraestructura crítica en C o C++ son «dangerous» donde haya lenguajes seguros en memoria disponibles

La guía conjunta lo dice sin rodeos: «Programming languages such as C and C++ are examples of memory unsafe programming languages»6. CISA y el FBI van más allá, y llaman peligroso a «the development of new product lines for use in service of critical infrastructure or NCFs in a memory-unsafe language (e.g., C or C++)» cuando se podría usar una alternativa segura en memoria7. Es una guía, no una ley. Pero el almacenamiento bajo servicios críticos es justo el código al que apunta, y los dos son OSD de nueva generación que se van a juzgar con ella.

FlashStore la cumple. Está escrito en Rust, y el ADR de croit da el motivo en una línea: «Storage = correctness-critical; memory-safety bugs = data loss»8. El compilador comprueba la seguridad de memoria en todas partes salvo en el código marcado como unsafe, y el mismo ADR lo limita a los módulos de FFI, DMA, NVMe y drivers de red, cada uno con un comentario SAFETY8. Lo conté en la instantánea: 1.216 líneas que mencionan unsafe de 696.125 líneas de Rust, más o menos un 0,17 %, y están en los crates de RDMA, runtime, NVMe y almacén, donde el código habla con el hardware. La guía conjunta nombra ella misma esa vía de escape, al señalar que Rust «can contain the ‘unsafe’ keyword»6, así que esa es la medida honrada: no es cero, pero es poco, está acotado y está donde cabría esperar. El C al que sí llama, SPDK y DPDK, queda detrás de esas mismas fronteras8.

Crimson no. Es un OSD nuevo escrito en C++ sobre un framework en C++13, que es el lenguaje que las agencias de arriba señalan como no seguro en memoria. Ninguna de sus líneas está dentro de lo que un compilador puede comprobar en cuanto a seguridad de memoria, y en su configuración por defecto le pasa el almacén a BlueStore, que también es C++.

CrimsonFlashStore
LenguajeC++Rust
Seguridad de memoria comprobada por el compiladornosí, fuera de unsafe
Código sin comprobartodomás o menos el 0,17 % de las líneas, código de drivers y FFI
Almacén por defectoBlueStore, C++FlashStore, Rust
Cumple la guía de seguridad de memoria de los Five Eyesnosí

Los desarrolladores de Ceph no eligieron C++ a la ligera; Crimson salió de una base de código en C++, y reescribir donde está significaba quedarse en ella. Es un camino de ingeniería razonable. Aun así deja el OSD de nueva generación de Ceph escrito en el único tipo de lenguaje que las agencias de cinco países han pedido que el código crítico nuevo deje atrás.

Cómo entra cada uno en un clúster

Esta es la mayor diferencia práctica entre los dos, y no tiene nada que ver con el rendimiento.

Un OSD FlashStore entra en los pools que ya tienes. Se coloca en los mismos placement groups junto a los OSD BlueStore clásicos, y cambias un disco cada vez2.

Un OSD Crimson no. Ni de lejos. La documentación de Umbrella dice: «Crimson OSD won’t instantiate PGs from non-Crimson pools»1. El código hace exactamente eso. Cuando el monitor le pide a un OSD Crimson que cree un PG en un pool sin el flag crimson, registra «pool lacks crimson flag» y cancela la creación9.

Qué pools sirve cada unotu pool existentesin flag crimsonOSD clásicoBlueStoreOSD FlashStoremismos PGOSD Crimsonsolo pools crimsonPG ignoradospool nuevo, --crimsonautoscale off
FlashStore toma PG en tus pools existentes. Crimson solo sirve pools creados con el flag crimson, así que necesita pools nuevos y los datos copiados a ellos.

Así que probar Crimson significa pools nuevos, creados con el flag crimson, y tus datos movidos a ellos. Y esos pools vienen con condiciones que el monitor hace cumplir:

Regla de pool de Crimson (Umbrella)Dónde
El autoescalado de PG debe estar desactivado al crear el poolOSDMonitor, creación del pool10
Fusión de PG (reducir pg_num) rechazadaOSDMonitor, cambio de pg_num11
División de PG permitida solo mientras crimson_allow_pg_split sea truelo mismo, y la opción12
Los pools EC deben ser del tipo EC optimizado, sin excepcionesOSDMonitor, creación del pool13
Sin OMAP en pools EClo mismo13

FlashStore sirve pools clásicos, tanto replicados como con erasure coding, y declina las configuraciones EC que no soporta en lugar de rechazarlas en el monitor14. Ninguno de los dos enfoques está mal. Pero uno te deja probar sobre una copia de tu disposición real de pools, y el otro te obliga a montar una aparte primero.

No hay paso para los pools que ya tienes

Entonces, ¿puedes convertir un pool existente en un pool de Crimson y pasarlo de disco en disco? No.

La documentación de Umbrella dice que Crimson está «aiming to allow seamless migration from existing ceph-osd deployments»1. Aiming: aspira a ello. La versión no lo hace, y el código muestra por qué no puede. El flag crimson es una opción de ceph osd pool create y de ningún otro sitio15. ceph osd pool set no tiene ninguna variable crimson que poner en un pool que ya existe16. Y un OSD Crimson ignora todos los PG de un pool sin el flag, como se vio arriba9. No encontré ninguna herramienta de conversión ni en el código ni en la documentación.

Mover un pool existenteCrimson (Umbrella)FlashStore, hoy
Conservar el mismo poolno, hace falta un pool nuevosí
Poner el flag al pool despuésno, solo al crearlono hace falta
Cómo se mueven los datoslos copias tú, de pool a poolel clúster hace backfill
Redirigir los clientessí, al pool nuevono
Un disco cada veznosí

Eso convierte el paso a Crimson en una copia de datos que haces tú: las imágenes RBD se pueden migrar en caliente «between different pools»17, y los datos de objetos o de ficheros necesitan lo que usen tus aplicaciones para copiarlos. Después hay que apuntar cada cliente al pool nuevo.

FlashStore es compatible con los pools que usas hoy. Lo preparas en un disco, el clúster hace backfill de los placement groups que se le asignan, y tus clientes nunca notan que el pool haya cambiado debajo de ellos, porque no ha cambiado18. Esa es toda la diferencia entre una reescritura que se une a tu clúster y una que se queda a su lado.

Qué le dice cada uno al monitor

Crimson se presenta. Al arrancar envía osd_type=crimson19, y el monitor se niega a dejarlo entrar salvo que esté puesto el flag allow_crimson del OSDMap, con una línea de log que dice que crimson-osd «is considered unstable and may result in crashes or data loss»20. Llegar hasta ahí lleva cuatro comandos de la documentación, y el primero activa una opción llamada enable_experimental_unrecoverable_data_corrupting_features1.

FlashStore hace lo contrario. No envía ningún osd_type y declara osd_objectstore=bluestore, así que el monitor ve un OSD clásico y no hace preguntas21. El artículo anterior cuenta por qué: el monitor de Umbrella condiciona funciones como las sobrescrituras EC a que todos los OSD de un pool declaren BlueStore21. Eso es para los monitores y managers estándar que hay hoy en producción. En las compilaciones de Ceph de la propia croit, parcheadas para reconocerlo, FlashStore se declara como flashstore21.

Qué comprueba el monitor al arrancarOSD Crimsonosd_type=crimsonmon: ¿allow_crimson puesto?set-allow-crimsonno: arranque rechazado"crashes or data loss"OSD FlashStoresin osd_typemon: un OSD clásicoobjectstore=bluestorearranca, sin flagsirve pools existentes
A Crimson hay que dejarlo entrar, por su nombre, tras un flag sobre el que el monitor avisa. FlashStore entra como un OSD clásico.

Yo prefiero que el software me diga lo que es. Crimson lo dice. Su manera es la honrada, y el nombre del flag no te deja ninguna duda de a qué estás diciendo que sí. La manera de FlashStore es lo que hace que la sustitución directa funcione en los monitores y managers estándar que la gente ejecuta hoy, y es una medida de compatibilidad, no el estado final. Las dos son deliberadas, y las dos están por escrito. Solo ten claro con cuál estás tratando cuando cuentes tus OSD.

Núcleos: reactores frente a hilos fijados que hacen polling

Los dos proyectos tiraron los pools de hilos. Bien. Los dos ejecutan un hilo por núcleo y reparten su trabajo por núcleo. La diferencia está en cuánto le piden al operador y en con cuánta fuerza se agarran al núcleo.

CrimsonFlashStore
Unidad de trabajoun reactor Seastar por núcleoun hilo fijado por núcleo
Número de núcleoscrimson_cpu_num, sin valor por defecto, obligatorioflashstore_cores, 8 por defecto
Fijado a núcleossolo con crimson_cpu_setsí, flashstore_lcores
En reposopolling 200 µs, luego duermepolling, reposo adaptativo
Busy-poll completoopcional, crimson_poll_modeel diseño, con retroceso en reposo
Cambio tras desplegarnoshards del almacén fijados en prepare

En Crimson, crimson_cpu_num «does not have a default value», hay que fijarlo antes de desplegar los OSD, y «cannot be changed after deployment»1. No fija los hilos salvo que también pongas crimson_cpu_set, que la documentación describe como «generally less recommended due to its complexity»1. El reactor hace polling durante 200 µs en reposo antes de volver a dormir, y existe un modo de polling completo «at the expense of 100% cpu usage», desactivado por defecto22. SeaStore además rechaza un cambio en el número de reactores después de mkfs23.

FlashStore fija por diseño, hace polling por diseño y retrocede en reposo2425. Su número de shards del almacén se fija cuando se prepara el almacén, la misma restricción en otro sitio26.

En la práctica, los dos quieren núcleos enteros y los dos quieren que los dimensiones antes de desplegar. Crimson convierte el polling en una opción que activas tú. FlashStore lo hace lo predeterminado y deja que la lógica de reposo recupere algo de CPU.

El almacén por defecto de Crimson es BlueStore

Esta es la parte que me sorprendió. No debería haberlo hecho.

Crimson tiene dos clases de almacén de objetos. Los nativos corren dentro del reactor Seastar; los no nativos corren a través de «a thread pool proxy» hacia «alien threads: worker threads not managed by Seastar»1. SeaStore es el nativo. BlueStore es no nativo. Y BlueStore es el predeterminado.

La documentación lo dice a las claras. SeaStore «is the primary native object store for Crimson OSD, though it is not the default as the support is in early stages»1. Cephadm despliega Crimson con --objectstore bluestore salvo que se le diga otra cosa, y aun así SeaStore no se puede desplegar con --method raw; te dicen que uses LVM1.

El almacén por defecto de Crimson, frente a FlashStoreCrimson, almacén por defectoreactores Seastarcrimson_cpu_numproxy de pool de hilossalida del reactoralien threadscrimson_bluestore_num_threadsBlueStoreRocksDB sobre BlueFSFlashStorenúcleo dueño del PGfijado, con pollingshard del almacén, mismo núcleosin traspasocola NVMe, mismo núcleoSPDK o io_uring
Un OSD Crimson por defecto saca cada operación del almacén de su reactor y se la pasa a un pool de hilos normales que ejecutan BlueStore. FlashStore mantiene todo el camino en el núcleo dueño del PG.

Así que un OSD Crimson desplegado hoy con los valores por defecto ejecuta un frontal Seastar encima del mismo BlueStore, RocksDB y BlueFS que usa el OSD clásico, con crimson_bluestore_num_threads hilos reservados para ello22. En el lado del almacén, nada ha cambiado respecto al OSD clásico. Es una manera sensata de construir un camino de migración. También es la razón de que comparar «Crimson» con FlashStore en rendimiento signifique muy poco si no dices qué almacén ejecutaba Crimson.

La comparación justa para el almacén es SeaStore frente a FlashStore. Eso es el resto del artículo.

SeaStore y FlashStore: dónde viven los metadatos

Los dos almacenes se escribieron para NVMe desde el principio, los dos se reparten por núcleo, y los dos guardan sus metadatos en B-trees propios en lugar de en RocksDB. Aun así, su disposición es muy distinta.

SeaStore da a cada reactor su propia raíz27. Debajo cuelgan un árbol de onodes, un árbol LBA y un árbol backref. El onode de cada objeto apunta entonces a su propio B-tree de OMAP y a su propio B-tree de XATTR, y a extents de datos con direcciones lógicas27. El árbol LBA traduce esas direcciones lógicas a físicas, así que un bloque puede moverse en el disco sin que cambien los árboles del propio objeto; la documentación dice que esa indirección es el motivo de que la mayoría de los extents «can be relocated freely»27.

FlashStore lo pone todo en un único B+tree copy-on-write por shard: onodes, xattrs, OMAP, mapas de extents con un crc32c por cada bloque de 4 KiB, el PG log y el bitmap del asignador28. Los mapas de extents apuntan directamente a bloques físicos. No hay capa lógica en medio.

Dónde viven los metadatosSeaStoreraízárbol de onodesárbol LBAárbol backrefonodeOMAPB-tree propioXATTRB-tree propiodatosdir. lógicadirección lógica, luego árbol LBA, luego discoFlashStoreun B+tree COW por shardonodes, xattrsOMAPmapas de extents + crc32cPG log, PG infobitmap del asignadormapa de extents, luego disco
SeaStore: un árbol por cada tipo de cosa, un B-tree por objeto para OMAP y xattrs, y un árbol LBA para encontrar los datos. FlashStore: un árbol por shard, que apunta directamente al disco.

Las dos decisiones tienen su motivo. La indirección de SeaStore es lo que abarata su limpiador: puede mover datos vivos sin reescribir cada árbol que apunta a ellos. FlashStore no la necesita, porque no tiene limpiador, como se ve más abajo. Su ADR incluye «Per-object omap subtree/root» entre las alternativas que consideró y descartó28.

Una diferencia en los checksums que conviene conocer: SeaStore calcula su crc32c sobre un extent entero en caché29, mientras que FlashStore guarda uno por cada bloque de 4 KiB28.

El orden en que se hace commit de una escritura

El tipo de dispositivo por defecto de SeaStore es SSD, que usa el backend segmentado30. En ese backend, una transacción es un registro de journal que lleva deltas, y con los datos pueden pasar dos cosas.

Los extents pequeños y de vida corta pueden ir en línea dentro del registro de journal, y entonces el registro es todo el commit27. Los extents más grandes o de vida más larga van a segmentos aparte, fuera de línea, y entonces la documentación fija el orden: el «final record with the deltas should be written only once the other blocks are persisted»27. Son dos escrituras en serie, la misma forma que el commit de BlueStore de datos y luego RocksDB.

FlashStore escribe el extent de datos y la unidad de WAL a la vez, mete el crc32c de los datos nuevos en el registro del WAL para que el replay pueda comprobarlo, y confirma cuando los dos son duraderos28. Un viaje al dispositivo, sea cual sea el tamaño.

Cuándo puede salir el commitSeaStoreextent pequeñoregistro de journalextent en línea + deltasack1 viajeSeaStorefuera de líneaextent a segmento OOLespera a persistirregistro de journaldeltasack2 viajesFlashStoredatos, 4 KiB nuevosunidad WAL, crc datosack1 viajetiempo
SeaStore en su dispositivo segmentado por defecto: un viaje cuando el extent cabe en el registro de journal, dos en serie cuando va fuera de línea. FlashStore: datos y registro de log a la vez.

Cuánto importa eso depende de tu carga, exactamente igual que en la comparación con BlueStore. Con poca profundidad de cola, donde los clientes esperan cada escritura, un segundo viaje es latencia real. Bajo carga, la agrupación esconde casi todo.

Recuperar espacio

La otra mitad de un diseño con estructura de log es la limpieza.

SeaStore en el backend segmentado solo escribe en segmentos abiertos. Antes de poder reutilizar un segmento, hay que reescribir sus bloques vivos en otro sitio, y el documento de diseño dice lo que cuesta: «we must ‘clean’ one byte of an existing segment for every byte written at steady state»27. Mezcla parte de esa limpieza con las escrituras en curso, para evitar picos, y hace el resto en segundo plano cuando el disco está más tranquilo27. El tamaño de segmento es de 64 MiB por defecto31.

SeaStore sí tiene un segundo backend para NVMe, el random block manager, que según la documentación es «Preferred for fast NVMe devices where overwrites are efficient enough that log structured updates aren’t worth the overhead»27. No es el predeterminado. Lo eliges con seastore_main_device_type30.

FlashStore no tiene limpiador de segmentos. Ninguno. Un bloque sustituido vuelve al asignador del shard en cuanto lo ha pasado un checkpoint, lo que ocurre cada cinco segundos mientras haya trabajo sin persistir, o antes cuando el anillo del WAL llega a la mitad28. Su documento de diseño rechazó de plano una disposición con estructura de log28. Eso no quiere decir que no tenga trabajo en segundo plano: sigue fusionando y compactando páginas del árbol y desfragmentando el espacio libre, a un ritmo por debajo de la E/S de los clientes28. Pero nunca copia tus datos vivos para hacer sitio.

Recuperar espacioSeaStore, segmentado (por defecto)segmento cerradobloques vivos + muertosel limpiador reescribelos vivos en otro abiertosegmento vacíodiscard, reutilizarrégimen estable: limpiar más o menos un byte por cada byte escritoFlashStorebloque sustituidopor un extent nuevoretenido hasta checkpointcada 5 s o WAL a la mitadde vuelta en el bitmapsin mover datos vivos
El backend por defecto de SeaStore paga las escrituras secuenciales con un limpiador que mueve datos vivos. FlashStore libera en su sitio los bloques sustituidos tras un checkpoint y no mueve nada.

En flash, que ya hace su propia recolección de basura dentro del disco, prefiero que el OSD no ejecute una segunda encima. La propia documentación de SeaStore parece estar de acuerdo, a juzgar por lo que dice del backend RBM. La diferencia es que FlashStore lo convirtió en la única opción y SeaStore lo dejó como la no predeterminada.

En qué funciona cada uno

Crimson (Umbrella)FlashStore
HDDsí, con BlueStore; SeaStore tiene un tipo de segmento para HDDno
NVMesísí, el único objetivo
Protección ante cortes de corrienteningún requisito indicadoobligatoria, mkfs se niega sin ella
Disposición de dispositivosLVM para SeaStore vía cephadmnamespaces enteros, sin particiones
Protocolo de redsolo msgr2solo msgr2
Backend de E/Sio_uring por defecto; linux-aio, epollSPDK por defecto, nivel io_uring
Poolspools nuevos con el flag crimsonpools clásicos existentes
Mover datos existentescopiarlos a un pool nuevobackfill en el mismo pool
Se despliega concephadm, --osd-type crimsonpaquetes, croit-flashstore-tool
Compilación recomendadala última compilación de CI de maininstantáneas de versión

Crimson mantiene la amplitud. La documentación dice que SeaStore «may not be suitable for traditional HDDs», pero que «Crimson will continue to support BlueStore ensuring compatibility with HDDs and slower SSDs»1, y el documento de diseño de SeaStore sigue mencionando interés en los HDD27. Su messenger rechaza v1 de plano, «ProtocolV1 is no longer supported»32, la misma decisión que tomó FlashStore33. Su documentación recomienda «one of the latest available builds, as Crimson evolves rapidly», lo que en la práctica significa imágenes de CI de main1.

FlashStore lo reduce todo a NVMe con protección ante cortes de corriente, y de ahí saca su sencillez34. Que es exactamente el compromiso que describe el ADR de croit, visto desde el otro lado.

Dos respuestas a la misma pregunta

Los dos proyectos partieron de la misma observación: el OSD clásico desperdicia el hardware rápido. Dieron respuestas muy distintas.

La respuesta de Crimson es la de la comunidad. Reescribir el OSD donde está, dentro de Ceph, mantener funcionando cada almacén viejo y cada disco viejo mientras madura el almacén nuevo, y dejar que todo el mundo vea el trabajo según se hace. Eso es lento, y se nota. En Umbrella, el OSD Crimson por defecto sigue ejecutando BlueStore a través de un pool de hilos, sus propios pools están vallados aparte de los tuyos, y activarlo significa teclear las palabras «unrecoverable data corrupting». Pero pertenece a todo el que ejecuta Ceph, y nadie te lo puede quitar.

La respuesta de FlashStore es la de un proveedor. Elegir un objetivo más estrecho, NVMe con protección ante cortes de corriente, tirar todo lo que solo existía por otro hardware, y entregar un almacén que entra en los pools que ya tienes. Eso es más rápido, y también se nota. Pero viene de una sola empresa, como instantáneas de solo lectura hasta su primera versión de producción, y en un clúster estándar entra diciéndole al monitor que es BlueStore.

Trabajo para esa empresa, así que pesa lo que sigue en consecuencia. croit hizo la apuesta técnica correcta para clústeres all-flash. Crimson hizo la apuesta correcta para Ceph como proyecto. No son lo mismo. Un proyecto que sirve a todo el mundo no puede dejar los HDD. Un proveedor sí puede, y debe, si eso es lo que compran sus clientes.

Lo que yo no haría es elegir entre los dos por un gráfico de benchmark de cualquiera de los lados. Los números de Crimson dependen de cuál de sus tres almacenes estaba en marcha; los de FlashStore salen del propio laboratorio de croit. Los dos proyectos publican sus documentos de diseño. Léelos, y luego pon los dos en los discos que de verdad desplegarías y ejecuta tu propia carga. El que siga haciendo lo que dicen sus documentos cuando son tus datos los que están en juego es el que merece la espera.


  1. Ceph Umbrella, Crimson (Tech Preview) — «the next generation ceph-osd», «not suitable for production use», los flags necesarios, crimson_cpu_num, backends nativos y no nativos, SeaStore «not the default», --method raw no soportado. Fuente: doc/crimson/crimson.rst en v21.2.0. ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎

  2. croit ceph-rust, README en la instantánea 48f9014 — promesa de sustitución directa, vista previa desde el 9 de noviembre de 2026, GA en el T1 de 2027, «not yet recommended for production data», «no issue tracker, no contribution workflow». ↩︎ ↩︎ ↩︎ ↩︎ ↩︎

  3. Seastar — el framework en C++ sobre el que está construido Crimson. ↩︎ ↩︎

  4. ceph-rust ADR 0003, desde cero, sin fork de Crimson — «Crimson = C++/seastar, tries to support everything (HDD, alienstore/BlueStore, all pool types) -> complexity. Complex code is never fast.»; fork rechazado por «C++, complexity, LGPL». ↩︎ ↩︎ ↩︎

  5. ceph-rust ADR 0164, licencias — fechado el 2026-10-17; daemon LGPL-3.0-only. ↩︎

  6. CISA, NSA, FBI, ASD’s ACSC, CCCS, NCSC-UK, NCSC-NZ, CERT-NZ: The Case for Memory Safe Roadmaps (December 2023) — «Programming languages such as C and C++ are examples of memory unsafe programming languages»; Rust «can contain the ‘unsafe’ keyword». ↩︎ ↩︎

  7. CISA and FBI: Product Security Bad Practices, v2.0 (January 2025) — líneas de producto nuevas para infraestructura crítica «in a memory-unsafe language (e.g., C or C++) where readily available alternative memory-safe languages could be used is dangerous». ↩︎

  8. ceph-rust ADR 0002, language: Rust — «Storage = correctness-critical; memory-safety bugs = data loss»; unsafe «confined to ffi/dma/nvme/net-driver modules with SAFETY comments»; SPDK y DPDK vía FFI. ↩︎ ↩︎ ↩︎

  9. Ceph v21.2.0, crimson/osd/shard_services.cc — «ignoring pgid {}, pool lacks crimson flag». ↩︎ ↩︎

  10. Ceph v21.2.0, OSDMonitor.cc, creación de pools de crimson — «crimson-osd does not support changing pg_num or pgp_num, pg_autoscale_mode must be set to ‘off’». ↩︎

  11. Ceph v21.2.0, OSDMonitor.cc, cambios de pg_num en crimson — «pg merging is not yet supported in Crimson». ↩︎

  12. Ceph v21.2.0, crimson_allow_pg_split — «Allow Crimson pools to increase their PG count (split)», true por defecto. ↩︎

  13. Ceph v21.2.0, OSDMonitor.cc, pools EC para Crimson — «For Crimson - only EC-optimized pools are supported», «Omap is not supported by EC pools in crimson». ↩︎ ↩︎

  14. ceph-rust docs, pools con erasure coding — EC heredado y optimizado servidos por defecto; el OSD declina los pools no soportados. ↩︎

  15. Ceph v21.2.0, MonCommands.h, osd pool create — name=crimson,type=CephBool,req=false, el único sitio donde se acepta el flag. ↩︎

  16. Ceph v21.2.0, MonCommands.h, osd pool set — las variables que se pueden poner; crimson no está entre ellas. ↩︎

  17. Ceph Umbrella, migración en caliente de imágenes RBD — «RBD images can be live-migrated between different pools». ↩︎

  18. ceph-rust docs, migrar desde el OSD clásico — añadir o liberar un disco, preparar FlashStore, dejar que el backfill mueva los datos. ↩︎

  19. Ceph v21.2.0, crimson/osd/osd.cc — m->metadata["osd_type"] = "crimson". ↩︎

  20. Ceph v21.2.0, OSDMonitor.cc, comprobación al arrancar — «Disallowing boot of crimson-osd without allow_crimson OSDMap flag», «considered unstable and may result in crashes or data loss». ↩︎

  21. ceph-rust ADR 0019, declarar osd_objectstore=bluestore — sin clave osd_type, los controles de funciones de BlueStore del monitor. ↩︎ ↩︎ ↩︎

  22. Ceph v21.2.0, crimson.yaml.in — crimson_reactor_idle_poll_time_us 200, crimson_poll_mode «at the expense of 100% cpu usage» false por defecto, crimson_bluestore_num_threads. ↩︎ ↩︎

  23. Ceph v21.2.0, seastore_require_partition_count_match_reactor_count — «disable osd shards changes upon restart», true por defecto. ↩︎

  24. ceph-rust ADR 0006, runtime de un hilo por núcleo — un hilo fijado con busy-polling por núcleo, cada PG pertenece a un núcleo. ↩︎

  25. ceph-rust ADR 0004, E/S de almacenamiento — SPDK y el nivel io_uring, reposo temporizado al dispositivo. ↩︎

  26. ceph-rust docs, referencia de configuración — flashstore_cores 8 por defecto, flashstore_lcores, flashstore_store_shards fijado en prepare. ↩︎

  27. Ceph Umbrella, documentación de desarrollo de SeaStore — raíz por reactor, árboles de onodes, OMAP, LBA y backref, «clean» un byte por cada byte escrito, el orden del registro de journal, el backend RBM. Fuente: doc/dev/crimson/seastore.rst en v21.2.0. ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎

  28. ceph-rust ADR 0021, motor de almacenamiento — un B+tree COW por shard, commit en paralelo, checkpoints, mantenimiento en segundo plano, alternativas descartadas, entre ellas la estructura de log y «Per-object omap subtree/root». ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎

  29. Ceph v21.2.0, crimson/os/seastore/cached_extent.h — «Returns crc32c of buffer». ↩︎

  30. Ceph v21.2.0, seastore_main_device_type — «The main device type seastore uses (SSD or RANDOM_BLOCK_SSD)», SSD por defecto. ↩︎ ↩︎

  31. Ceph v21.2.0, seastore_segment_size — 64 MiB por defecto. ↩︎

  32. Ceph v21.2.0, crimson/net/SocketMessenger.cc — «ProtocolV1 is no longer supported». ↩︎

  33. ceph-rust ADR 0168, fuera de alcance — msgr1 fuera, solo v2. ↩︎

  34. ceph-rust docs, requisitos de hardware y del host — PLP obligatoria, namespaces enteros. ↩︎