Almacenamiento de Blobs en Couchbase para la gestión de contenidos

Este blog se publicó originalmente en el blog personal de Cecile Le Pape. Para ver la entrada original, haga clic en aquí

 

En mi entrada anteriorEn el artículo de la semana pasada, hablé de cómo configurar un servicio flexible de gestión de contenidos utilizando Couchbase como repositorio de metadatos, sobre un servidor Apache Chemistry. Los blobs en sí (pdf, pptx, docx, etc) se almacenan en un sistema de archivos separado o en un almacén de blobs. Hoy, me gustaría mostrar como Couchbase puede ser usado para almacenar los blobs mismos, usando un gestor de chunk personalizado. La idea es almacenar no sólo los metadatos de un documento (fecha de creación, creador, nombre, etc.) sino además el propio blob.

El objetivo de esta nueva arquitectura es reducir el número de sistemas diferentes (y licencias que pagar) y también beneficiarse directamente de las funciones de replicación que ofrece Couchbase.

Primero, recordemos que Couchbase no es un almacén de blobs. Es un almacén de documentos basado en memoria, con una gestión de caché adhoc ajustada para que la mayoría de los datos almacenados en Couchbase estén en RAM para una consulta rápida. Los datos también se replican entre nodos (si la replicación está habilitada) dentro del cluster y opcionalmente fuera del cluster si se usa XDCR. Esta es la razón por la que los datos almacenados en Couchbase no pueden ser mayores de 20 MB. Este es un límite duro, y en la vida real 1MB ya es un documento grande para almacenar.

Sabiendo esto, la cuestión es: ¿cómo puedo almacenar grandes datos binarios en Couchbase? Respuesta sencilla: ¡en trozos!

La nueva arquitectura tiene ahora este aspecto:

Ahora hay 2 buckets en Couchbase:

  1. cmismeta : utilizado para almacenar metadatos
  2. cmisstore : utilizado para almacenar blobs

 

Cuando se crea una carpeta, sólo se modifica el bucket cmismeta con una nueva entrada porque, por supuesto, una carpeta no está asociada a ningún blob. Se trata simplemente de una estructura utilizada por el usuario para organizar los documentos y navegar en el árbol de carpetas. Las carpetas son virtuales. El punto de entrada de la estructura es la carpeta raíz tal y como se describe anteriormente.

Cuando un documento (por ejemplo un pdf o un pptx) se inserta en una carpeta, ocurren 3 cosas:

  • Un documento json que contiene todos sus metadatos se inserta en el bucket cmismeta, con una clave única. Digamos, por ejemplo, que el documento tiene la clave L0NvdWNoYmFzZU92ZXJ2aWV3LnBwdHg=.
  • Se crea un nuevo documento json con la misma clave en el bucket de cmisstore. Este documento contiene el número de chunk, el tamaño máximo de cada chunk (el mismo para todos los chunk excepto para el último que puede ser más pequeño) y el tipo mime de la aplicación.
  • El blob adjunto al documento se fragmenta en trozos binarios (el tamaño depende de un parámetro que puedes establecer en las propiedades del proyecto). Por defecto, un trozo tiene un tamaño de 500 KB. Cada trozo se almacena en el bucket de cmisstore como un documento binario, con la misma clave "L0NvdWNoYmFzZU92ZXJ2aWV3LnBwdHg=" como prefijo, y un sufijo "::partxxx" donde xxx es el número del chunk (0, 1, 2, ...).

Por ejemplo, si inserto un pptx llamado CouchbaseOverview.pptx cuyo tamaño es de 4476932 bytes en Couchbase, obtengo:

  • En el cubo cmismeta, un documento json llamado L0NvdWNoYmFzZU92ZXJ2aWV3LnBwdHg=

  • En bucket cmisstore, un documento json también llamado L0NvdWNoYmFzZU92ZXJ2aWV3LnBwdHg=

  

  • 9 trozos que contienen datos binarios y se denominan L0NvdWNoYmFzZU92ZXJ2aWV3LnBwdHg=::part0, L0NvdWNoYmFzZU92ZXJ2aWV3LnBwdHg=::part1, ... , L0NvdWNoYmFzZU92ZXJ2aWV3LnBwdHg=::part8

 

El CouchbaseStorageService es la clase que implementa la interfaz StorageService ya utilizada para almacenamiento local o almacenamiento S3 como mostré en mi blog anterior. La primera diferencia es la reutilización de la misma instancia de CouchbaseCluster que la utilizada para el MetadataService, ya que sólo se debe instanciar un Couchbase Environnement para ahorrar muchos recursos (RAM, CPU, Red, etc).

Veamos ahora el método writeContent propiamente dicho:

 

/**
 * ContentStream se divide en partes
 */
público void escribirContenido(Cadena dataId, ContentStream contentStream)
lanza StorageException { 
        // contar el número de piezas 
        largo longitud = contentStream.getLength();   
        largo nbparts = longitud / BUFFER_SIZE; 
        // la última parte   
        si (longitud – nbparts * BUFFER_SIZE > 0)  nbparts++;    
        JsonObject doc = JsonObject.empty(); 
        doc.put("contar"nbparts); 
        doc.put("mimetype"contentStream.getMimeType()); 
        doc.put("longitud"longitud);
        largo longitud total = 0; 
        int leer = 0; // El número de bytes aún no leídos 
        byte[] byteArray = nuevo byte[BUFFER_SIZE]; 
        int offset = 0; 
        para (int i = 0; i < nbpartsi++) { 
            pruebe { 
                leer = contentStream.getStream() 
                       .read(byteArray, 0, BUFFER_SIZE);      
                longitud total += leer; 
                             offset += leer
                escribirContenidoParte(dataId + PARTE_SUFIX + ibyteArrayleer); 
                doc.put(dataId + PARTE_SUFIX + ileer); 
            } captura (IOException e) { 
                 e.printStackTrace();   
            } 
        }
 
        si (longitud total != longitud) 
                    tirar nuevo Excepción de almacenamiento("Número incorrecto de bytes");      
        
         JsonDocument jsondoc = JsonDocument.create(dataIddoc); 
         cubo.upsert(jsondoc); 
     }
 
     privado void writeContentPart(Cadena partIdbyte[] bytesArrayint longitud
          lanza StorageException {
                   DocumentoBinario bDoc = BinaryDocument.create(partId
          Unpooled.copiedBuffer(bytesArray));
                  cubo.upsert(bDoc);
     } 

 

Ahora, ¿qué hacer para recuperar el archivo de Couchbase? La idea principal es obtener cada parte, concatenarlas en el mismo orden en que fueron cortadas y enviar el array de bytes al stream. Probablemente hay muchas maneras de hacer esto, yo simplemente implemento una sencilla usando un array de bytes en el que escribo cada byte.

 

privado InputStream getInputStream(Cadena dataId, StringBuffer mimeType)
lanza StorageException {
JsonDocument 
doc = cubo.get(dataId);
JsonObject 
json = doc.content();
Entero 
nbparts = json.getInt("contar");
Entero 
longitud = json.getInt("longitud");
 
          si(nbparts==null || longitud==null || mimeType==null
                 tirar nuevo Excepción de almacenamiento("Documento inválido");
          mimeType.append(json.getString("mimetype"));
          byte[] byteArray = nuevo byte[longitud]; 
          // para cada parte, leer el contenido en el byteArray 
          int offset = 0; 
          Entero partLength = null; 
         
          para (int i = 0; i < nbpartsi++) {   
               partLength = json.getInt(dataId + PARTE_SUFIX + i); 
               si(partLength == null
                     tirar nuevo Excepción de almacenamiento("longitud de la pieza "+i+" es obligatorio");
               DocumentoBinario bDoc = 
                    cubo.get(dataId + PARTE_SUFIX + i,DocumentoBinario.clase); 
               ByteBuf pieza = bDoc.content();
               byte[] dst = nuevo byte[partLength]; 
               pieza.readBytes(dst); 
               para (int k = 0; k < partLengthk++) { 
                    byteArray[k + offset] = dst[k]; 
               } 
               offset += partLength; 
               pieza.release(); 
          }
          InputStream flujo = nuevo ByteArrayInputStream(byteArray);    
          devolver flujo;
}
 

Finalmente veamos que ocurre en la herramienta workbench proporcionada por Apache Chemistry ? Puedo ver el documento en la carpeta raíz y si hago doble clic sobre él, el contenido se transmite desde Couchbase y se muestra en el visor asociado (aquí powerpoint) basado en el tipo mime. 

 

Workbench y documento abierto en powerpoint tras doble click 

Comparte este artículo
Recibe actualizaciones del blog de Couchbase en tu bandeja de entrada
Este campo es obligatorio.

Autor

Publicado por Cecile Le Pape, Arquitecta de soluciones, Couchbase

Tras 10 años en la Universidad de París 6 (Francia), donde trabajó en el equipo de bases de datos en proyectos de replicación, coherencia, XML, p2p, sindicación y telefonía móvil, Cecile decidió cambiar de aires e iniciar una nueva experiencia vital en la industria. Cecile se unió al equipo de arquitectos de una pequeña empresa llamada Oceane Consulting para desarrollar proyectos de gestión documental. Ahora es Arquitecta de Soluciones en Couchbase y está muy contenta de participar tanto en el campo técnico como en el de ventas.

1 Comentarios

  1. Vivek Krishnan abril 1, 2018 a 3:52 am

    Este es un gran artículo, me pregunto si sería para formatos de vídeo también.

Deja un comentario

¿Listo para empezar con Couchbase Capella?

Empezar a construir

Consulte nuestro portal para desarrolladores para explorar NoSQL, buscar recursos y empezar con tutoriales.

Utilizar Capella gratis

Ponte manos a la obra con Couchbase en unos pocos clics. Capella DBaaS es la forma más fácil y rápida de empezar.

Póngase en contacto

¿Quieres saber más sobre las ofertas de Couchbase? Permítanos ayudarle.