wrno / cassandra-nosql2023

Laboratorio 2 de Taller de Bases de Datos NoSQL 2023 utilizando Apache Cassandra

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Laboratorio NoSQL: API de domicilios en Cassandra (cassandra-nosql2023)

Laboratorio 2 de Taller de Bases de Datos NoSQL 2023 utilizando Apache Cassandra.
El repositorio contiene una solución de .NET cuyo proyecto principal es una API para almacenar en y consultar domicilios desde una base de datos Apache Cassandra.

Tabla de contenidos

  1. Grupo
  2. Herramientas utilizadas
  3. ¿Por qué Cassandra?
  4. Modelado de datos
    1. Tablas
      1. personas
      2. domiciliosporpersona
      3. domiciliospordepartamento
      4. domiciliosporlocalidad
      5. domiciliosporbarrio
      6. domiciliospordepartamentolocalidad
      7. domiciliospordepartamentobarrio
      8. domiciliosporlocalidadbarrio
      9. domiciliospordepartamentolocalidadbarrio
    2. Data Type Objects
      1. PersonaDTO
      2. NuevoDomicilioDTO
      3. DomicilioPersonaDTO
      4. DomicilioDTO
  5. Instalar Cassandra con Docker en Windows
  6. Configurar la aplicación
  7. Servicios
    1. api/Persona: POST
    2. api/Domicilio: POST
    3. api/Domicilio/persona/{ci}: GET
    4. api/Domicilio: GET
  8. Pruebas

Grupo

  • Acosta, Federico
  • Collazo, Bruno
  • Grasso, Sebastián

Herramientas utilizadas

  • La solución fue desarrollada en .NET 7 usando C# como lenguaje de programación.
  • Los datos se almacenan en una base de datos Apache Cassandra 4.1.
  • Tanto la base de datos como el sistema se despliegan utilizando Docker.
  • La base de datos, opcionalmente, se puede desplegar en DataStax Astra.
  • Para la conexión con la base de datos Apache Cassandra desde nuestra aplicación desarrollada en C#, se utiliza el driver CassandraCSharpDriver desarrollado por DataStax.
  • Para realizar pruebas, se utilizaron Swagger UI, Postman API y Apache JMeter 5.6.

¿Por qué Cassandra?

En Apache Cassandra, además de ofrecer gran velocidad de respuesta —sobre todo— a operaciones de lectura y teóricamente 100% de uptime, el modelado de datos es query-driven: esto significa que las tablas a generar van a estar definidas por las consultas proyectadas, no al revés.
En esta realidad específica, tenemos las siguientes consultas definidas:

  • direcciones por persona,
  • direcciones por departamento,
  • direcciones por localidad,
  • direcciones por barrio,
  • direccones por departamento y localidad,
  • direciones por departamento y barrio,
  • direcciones por localidad y barrio y
  • direcciones por departamento, localidad y barrio.

Sabiendo que estas son las únicas consultas que se pueden realizar, que en todos los casos se puede definir el o los filtros como clave de partición ya que no son datos editables y no se le pueden agregar filtros extra que puedan enlentecer las consultas, Cassandra parece ser un buen candidato para almacenar nuestros datos.

Modelado de datos

Tablas

Referencias
Clave Significado
K Clave de partición
C↑ Clave de clustering ascendente
C↓ Clave de clustering descendiente
S Columna estática
IDX Índice secundario

Se debe generar una tabla por cada consulta que definimos en el punto anterior. De esta forma, se generan las siguientes tablas en Apache Cassandra:

personas

Columna Tipo Índice
ci int K
nombre text
apellido text
edad int

domiciliosporpersona

Columna Tipo Índice
ci int K
fechacreada timestamp C↓
departamento text C↑
localidad text C↑
barrio text C↑
calle text C↑
nro int C↑
apartamento text C↑
padron int C↑
ruta text C↑
km float C↑
letra text C↑
nombre text S
apellido text S
edad int S

domiciliospordepartamento

Columna Tipo Índice
ci int K
departamento text C↑
localidad text C↑
barrio text C↑
calle text C↑
nro int C↑
apartamento text C↑
padron int C↑
ruta text C↑
km float C↑
letra text C↑

domiciliosporlocalidad

Columna Tipo Índice
localidad text K
departamento text C↑
barrio text C↑
calle text C↑
nro int C↑
apartamento text C↑
padron int C↑
ruta text C↑
km float C↑
letra text C↑

domiciliosporbarrio

Columna Tipo Índice
barrio text K
departamento text C↑
localidad text C↑
calle text C↑
nro int C↑
apartamento text C↑
padron int C↑
ruta text C↑
km float C↑
letra text C↑

domiciliospordepartamentolocalidad

Columna Tipo Índice
departamento text K
localidad text K
barrio text C↑
calle text C↑
nro int C↑
apartamento text C↑
padron int C↑
ruta text C↑
km float C↑
letra text C↑

domiciliospordepartamentobarrio

Columna Tipo Índice
departamento text K
barrio text K
localidad text C↑
calle text C↑
nro int C↑
apartamento text C↑
padron int C↑
ruta text C↑
km float C↑
letra text C↑

domiciliosporlocalidadbarrio

Columna Tipo Índice
localidad text K
barrio text K
departamento text C↑
calle text C↑
nro int C↑
apartamento text C↑
padron int C↑
ruta text C↑
km float C↑
letra text C↑

domiciliospordepartamentolocalidadbarrio

Columna Tipo Índice
departamento text K
localidad text K
barrio text K
calle text C↑
nro int C↑
apartamento text C↑
padron int C↑
ruta text C↑
km float C↑
letra text C↑

Data Type Objects

PersonaDTO

Columna Tipo Chequeos
Ci int - Requerido
- Mín: 10000000
- Máx: 99999999
Nombre string - Requerido
Apellido string - Requerido
Edad int - Requerido
- Mín: 0

NuevoDomicilioDTO

Columna Tipo Chequeos
Ci int - Requerido
- Mín: 10000000
- Máx: 99999999
Departamento string - Requerido
Localidad string - Requerido
Barrio string - Requerido
Calle string - Requerido
Nro int - Requerido (0 en caso de ser S/N)
- Mín: 0
Apartamento string
Padron int - Mín: 0
Ruta string
Km float - Mín: 0
Letra string

DomicilioPersonaDTO

Columna Tipo Chequeos
FechaCreada DateTimeOffset - Requerido
Ci int - Requerido
Nombre string - Requerido
Apellido string - Requerido
Edad int - Requerido
Departamento string - Requerido
Localidad string - Requerido
Barrio string - Requerido
Calle string - Requerido
Nro int - Requerido
Apartamento string
Padron int
Ruta string
Km float
Letra string

DomicilioDTO

Columna Tipo Chequeos
Departamento string - Requerido
Localidad string - Requerido
Barrio string - Requerido
Calle string - Requerido
Nro int - Requerido
Apartamento string
Padron int
Ruta string
Km float
Letra string

Instalar Cassandra con Docker en Windows

Para poder usar Cassandra, debe asegurarse de tener instalado Java SE 8 u OpenJDK 8.

Debe instalar WSL 2 con Ubuntu:

  • Ejecute PowerShell como administrador.
  • Ejecute el siguiente comando: wsl --install -d ubuntu.
  • Reinicie la computadora y ejecute Ubuntu si no lo hace automáticamente.
  • Configure su usuario de Ubuntu.
  • Actualice toda aplicación de Ubuntu y repositorios a la última versión usando sudo apt update y luego sudo apt upgrade.

Ahora puede descargar e instalar Docker Desktop desde la página oficial de Docker.

Para instalar la imagen de Cassandra en Docker, tiene dos opciones:

  1. Con Docker Desktop
    • En el buscador, escriba "Cassandra".
    • Seleccione el primer resultado.
    • Haga clic en Pull.
    • Vaya al menú Images.
    • Haga clic en Run en la imagen llamada cassandra.
    • Definir nombre y mapear el puerto 9042 del contenedor. En nuestro caso, usamos el nombre cass_cluster y mapeamos el puerto 9042 en el puerto 9042.
    • Haga clic en Run.
  2. Por consola
    • docker pull cassandra:latest para obtener la última imagen de Cassandra.
    • docker run -p 127.0.0.1:9042:9042 --name cass_cluster cassandra:latest para instalar un nuevo contenedor de Cassandra en Docker con nombre cass_cluster, mapeando el puerto 9042 (derecha) en 127.0.0.1:9042.

Configurar la aplicación

Modificar API/appsettings.json según las necesidades:

  • AppSettings:Cassandra:Deployment puede tomar los valores "Docker" o "Astra" (que se encuentran en Core.Enums.Deployment) e indica dónde se encuentra la base de datos a la que nos conectamos.
  • AppSettings:Cassandra:Username es el nombre de usuario con el cual se conecta al contenedor de Cassandra.
  • AppSettings:Cassandra:Password es la contraseña con la cual se conecta al contenedor de Cassandra.
  • AppSettings:Cassandra:ContactPoint es la IP a través de la cual se accede a Cassandra.
  • AppSettings:Cassandra:Port es el puerto en el que se mapeó el puerto 9042 de Cassandra.
  • AppSettings:Cassandra:Keyspace es el nombre del keyspace en el cual guardaremos los datos.
  • AppSettings:Cassandra:BundlePath es el path en el que se despliega en el contenedor el archivo secure-connect-[nombre-de-BD-en-Astra].zip que devuelve Astra. Esto se configura en el Dockerfile.
  • AppSettings:Cassandra:ClientId es equivalente al valor clientId en el archivo [nombre-de-BD-en-Astra]-token.json que devuelve Astra.
  • AppSettings:Cassandra:ClientSecret es equivalente al valor secret en el archivo [nombre-de-BD-en-Astra]-token.json que devuelve Astra.

Si se usa base de datos en Astra, modificar API/Dockerfile:
La línea COPY ["DAL/Persistence/secure-connect-cass-cluster.zip", "/secure-connect-cass-cluster.zip"] copia el archivo secure-connect-[nombre-de-BD-en-Astra].zip en la carpeta DAL/Persistence al contenedor en el directorio raíz con mismo nombre. Este último parámetro debe ser igual al valor definido en AppSettings:Cassandra:BundlePath en API/appsettings.json.

IMPORTANTE

Si se usa base de datos en Docker, es posible que al intentar conectarse a la IP especificada (sea 127.0.0.1, localhost o cual sea) en el docker run no sea suficiente para llegar al contenedor de Cassandra. En ese caso, seguir los siguientes pasos:

  1. Con Docker Desktop
    • Seleccione el contenedor.
    • Clic en Exec.
    • Ejecute cqlsh.
  2. Por consola
    • Ejecute docker exec -it cass_cluster cqlsh cambiando cass_cluster por el nombre que le puso al contenedor.

Una vez llegados a este punto, independientemente de qué herramienta uso, siga los siguientes pasos:

  • Ejecute el siguiente comando: SELECT listen_address FROM system.local;
  • Use la IP devuelta como contact point en API/appsettings.json.

Servicios

api/Persona: POST

Agrega una persona que no existe en el sistema, se pasa como parámetro un objeto de tipo persona. En caso de la persona existir ya en el sistema (la CI pertenece a una persona que está en la base) se retorna el error 401 con el mensaje: "La persona ya existe".

  • Recibe:
    • PersonaDTO: JSON en body. Requerido.
  • Devuelve:
    • PersonaDTO: JSON.

api/Domicilio: POST

Agrega una dirección asociada a una persona. Se pasa como parámetro la cédula de la persona y un objeto de dirección. Si la persona (cédula) no existe en el sistema, se retorna el error 402 con el mensaje: "No existe una persona con la cédula aportada como parámetro".

  • Recibe:
    • NuevoDomicilioDTO: JSON en body. Requerido.
  • Devuelve:
    • DomicilioPersonaDTO: JSON.

api/Domicilio/persona/{ci}: GET

Obtiene todas las direcciones asociadas a una persona. Se pasa como parámetro la cédula de la persona. Las direcciones se listan de forma tal que las últimas ingresadas se muestran primero. Este endpoint debe ofrecer la posibilidad de obtener los resultados de forma paginada. Si la persona (cédula) no existe en el sistema, se retorna el error 402 con el mensaje: "No existe una persona con la cédula aportada como parámetro".

  • Recibe:
    • ci: Cédula de la persona. Path param. Número entero. Requerido. Mínimo: 10000000. Máximo: 99999999.
    • limit: Cantidad de registros en caso de paginado. Query param. Opcional.
    • X-PagingState: Paging state devuelto por Cassandra en la anterior query con los mismos parámetros. Header. Opcional.
  • Devuelve:
    • Lista de DomicilioPersonaDTO: Colección de JSONs.
    • X-PagingState: Paging state para obtener la siguiente página en la siguiente consulta. Header.

api/Domicilio: GET

Obtiene todos los domicilios asociados a un criterio de búsqueda, que puede ser por: Barrio, Localidad, Departamento. Los criterios se pueden combinar. El criterio se pasa como parámetro.

  • Recibe:
    • departamento: Departamento. Query param. Opcional.
    • localidad: Localidad. Query param. Opcional.
    • barrio: Barrio. Query param. Opcional.
  • Devuelve:
    • Lista de DomicilioDTO: Colección de JSONs.

Pruebas

Para realizar las pruebas con:

  • Swagger UI: Ir a https://[ip-o-dominio]:[puerto]/swagger/index.html.
  • Postman API: Importar el archivo Pruebas/Postman/Taller NoSQL.postman_collection.json como colección y guiarse por la documentación para realizar modificaciones en los distintos requests cambiando IP/dominio y puerto por el correspondiente.
  • Apache JMeter: Abrir el archivo Pruebas/jmeterTEST/pruebasCassandraProy.jmx en Apache JMeter cambiando IP/dominio y puerto por el correspondiente en cada una de las pruebas.

About

Laboratorio 2 de Taller de Bases de Datos NoSQL 2023 utilizando Apache Cassandra


Languages

Language:C# 98.0%Language:Dockerfile 2.0%