DEV Community

Kevin Catucuamba
Kevin Catucuamba

Posted on

Aurora DSQL, una alternativa a PostgreSQL

Introducción

Aurora DSQL de Amazon es una base de datos relacional distribuida y sin servidor, diseñada para manejar cargas de trabajo transaccionales de forma eficiente. Permite crear clústeres en una sola región o en múltiples regiones, conectarse a ellos y cargar esquemas de ejemplo. A través de la consola de administración de AWS y la herramienta psql, los usuarios pueden interactuar con la base de datos. Al finalizar la configuración, se obtiene un clúster de Aurora DSQL completamente funcional, listo para usarse en entornos de prueba o producción.

Contexto

Según la documentación, Aurora DSQL es compatible con ORMs y otras herramientas comunes utilizadas para interactuar con bases de datos en aplicaciones backend. En los ejemplos que se presentan a continuación, se mostrará de manera rápida cómo se realiza la interacción y cuáles son algunas de sus limitaciones, considerando que ciertas características propias de PostgreSQL se encuentran deshabilitadas.

Se realizaron pruebas en dos tipos de backend:

  • B1: Spring Boot con JPA (Hibernate ORM)
  • B2: Node.js con Knex.js (query builder)

En ambos casos, se trata de pruebas de concepto rápidas, enfocadas en ofrecer una primera impresión de la funcionalidad de Aurora DSQL con estas herramientas, sin profundizar en todos los detalles avanzados de su uso.

Requisitos

Para comprender esta prueba realizada en este documento con Amazon DSQL es preferente tener conocimiento mínimo en estas herramientas:

  • Java / Spring Boot (Spring JPA, JDBC)
  • NodeJS / KnexJS Query Builder

Creando un cluster de Aurora DSQL

La creación de un cluster en Aurora DSQL es bastante sencilla; para este caso, lo creamos usando la consola web de AWS.

Seleccionamos crear un cluster y seleccionamos la opción de "Single-Region", para este caso dejamos las configuraciones por defecto y creamos el cluster.

Esperar a que se cree el recurso y estaríamos listos para conectarnos a la base de datos.

Ingresamos al cluster y seleccionamos el botón Conectar y seleccionamos Get Token, en dicha pantalla se despliegan las credenciales que debemos usar para conectarnos a la base de datos: host, port, database y password (token)

A modo de ejemplo, se crea una tabla de productos en Aurora DSQL para verificar el funcionamiento.

B1 Spring Boot JPA

Para el caso de Spring Boot tenemos realizadas las siguientes configuraciones:

dependencias

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>software.amazon.dsql</groupId>
            <artifactId>aurora-dsql-jdbc-connector</artifactId>
            <version>1.2.0</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <scope>annotationProcessor</scope>
        </dependency>
    </dependencies>
Enter fullscreen mode Exit fullscreen mode

Notar que estamos usando la librería aurora-dsql-jdbc-connector para usarla como driver en las configuraciones de conexión a la base de datos.

application.yml

spring:
  application:
    name: my-sb-app
  datasource:
    url: jdbc:aws-dsql:postgresql://${AURORA_HOST}:${AURORA_PORT:5432}/${AURORA_DB}
    username: ${AURORA_USER}
    password: ${AURORA_PASSWORD}
    driver-class-name: software.amazon.dsql.jdbc.DSQLConnector
  jpa:
    hibernate:
      ddl-auto: none   
create-drop
    show-sql: true
    properties:
      hibernate:
        format_sql: true
        dialect: org.hibernate.dialect.PostgreSQLDialect
Enter fullscreen mode Exit fullscreen mode

Dado que no es una base de datos nativa de PostgreSQL, note que el spring datasource y driver tinen un ligero cambio, tal como se explica en la documentación de Aurora DSQL: https://docs.aws.amazon.com/aurora-dsql/latest/userguide/SECTION_program-with-jdbc-connector.html

Se adjunta las configuraciones minimas necesarias para consultar y crear usuarios:

@Entity
@Table(name = "products", schema = "pfinance")
@Getter
@Setter
public class ProductEntity {

    @Id
    @Column(name = "prd_id", nullable = false)
    private Integer id;

    @Column(name = "prd_name", length = 50)
    private String name;

    @Column(name = "prd_price", precision = 18, scale = 6)
    private BigDecimal price;

    @Column(name = "prd_created_at", columnDefinition = "timestamp default now()")
    private LocalDateTime createdAt;

    @Column(name = "prd_updated_at", columnDefinition = "timestamp default now()")
    private LocalDateTime updatedAt;

    @Column(name = "prd_creator", length = 50)
    private String creator;

}

public interface ProductJPARepository extends JpaRepository<ProductEntity, Integer> {
}


@RestController
@RequiredArgsConstructor
public class TwoController {

    private final ProductJPARepository productJPARepository;
    private static final String CREATOR_ID = "1f8ba4c8-9d86-472d-8881-b90bb13bf643";

    @GetMapping("/users")
    public ResponseEntity<List<ProductEntity>> getProducts() {
        List<ProductEntity> products = productJPARepository.findAll();
        return ResponseEntity.ok(products);
    }

    @PostMapping("/users")
    public ResponseEntity<String> createProduct(@RequestBody ProductEntity productEntity) {
        productEntity.setCreatedAt(java.time.LocalDateTime.now());
        productEntity.setUpdatedAt(java.time.LocalDateTime.now());
        productEntity.setCreator(CREATOR_ID);
        productJPARepository.save(productEntity);
        return ResponseEntity.ok("Product created successfully");
    }


}


Enter fullscreen mode Exit fullscreen mode

Una vez realizadas las configuraciones necesarias, el servicio se ha conectado sin problemas, dando como resultado que efectivamente se puede usar ORMs con esta base de datos relacional de tipo serverless.

Nota importante: El conector JDBC propio de Amazon Aurora DSQL que se esta usando administra el flujo de generación de tokens cuando se caduca, es por eso que a pesar de que haya pasado los 15 minutos de tiempo de vida del token incial, dicho driver tiene la capacidad de generar nuevos tokens de forma automática facilitando la integración con aplicaciones existentes, para ello el servicio tiene que tener los permisos IAM necesarios o en defecto tener las key access con permisos para generar nuevos tokens, para más información revisar: https://docs.aws.amazon.com/aurora-dsql/latest/userguide/SECTION_program-with-jdbc-connector.html

B2 NodeJS Knex.js

Para esta prueba se utiliza Knex.js, un query builder (constructor de consultas SQL) para Node.js que facilita la creación y ejecución de consultas en diferentes bases de datos de forma programática y flexible.

Para obtener el token (password) necesario para conectarse a la base de datos, AWS proporciona la librería aws-sdk/dsql-signer para Node.js. Su configuración es bastante sencilla, como se muestra a continuación:

import { DsqlSigner } from "@aws-sdk/dsql-signer";
import { getDSQLEnvs } from "./utils";
import { buildKnexConfig } from "./knex-config";


export const getKnexConfig = async () => {

    const { user, clusterEndpoint, region, port, database } = getDSQLEnvs();

    const signer = new DsqlSigner({
        hostname: clusterEndpoint,
        region: region,
    });

    const token = await signer.getDbConnectAdminAuthToken();

    return buildKnexConfig({
        host: clusterEndpoint,
        port: port,
        user: user,
        password: token,
        database: database,
    });
}
Enter fullscreen mode Exit fullscreen mode

Nota: recordar que para que el programa pueda obtener las credenciales debe tener los permisos correspondientes o si es local las llaves de acceso correspondientes.

Configuración de Knex.Config:

import { Knex } from "knex";

export const buildKnexConfig = (conn: ConnectionDetails) => {
    const config: Knex.Config = {
        client: "pg",
        connection: {
            host: conn.host,
            port: conn.port,
            user: conn.user,
            password: conn.password,
            database: conn.database,
            ssl: {
                rejectUnauthorized: true,
            },
        },
        debug: false
    }
    return config;
}
Enter fullscreen mode Exit fullscreen mode

Clase que inicializa una conexión para knexjs:

import knex, { Knex } from "knex";
import { getKnexConfig } from "./dsql-ds";

export class KnexjsDB {
    private static instance: KnexjsDB;
    private db: Knex;

    private constructor(db: Knex) {
        this.db = db;
    }

    static async create(): Promise<KnexjsDB> {
        if (!KnexjsDB.instance) {
            const config = await getKnexConfig();
            KnexjsDB.instance = new KnexjsDB(knex(config));
        }
        return KnexjsDB.instance;
    }

    get connection(): Knex {
        return this.db;
    }

}
Enter fullscreen mode Exit fullscreen mode

Script para realizar una prueba de conexión:

import { KnexjsDB } from "./db/knexdb";

(async () => {
    const knexdb = await KnexjsDB.create();
    const conn = knexdb.connection;
    const products = await conn
    .select("*")
    .from("pfinance.products")
    .limit(3)
    console.log("Database Products:", products);
})();
Enter fullscreen mode Exit fullscreen mode

Realizando una prueba para consultar productos de la base de datos de Amazon Aurora DSQL:

Tomar en cuenta que está versión de PostgreSQL no disponibiliza todas las características que una base de datos PostgreSQL normal, si intentamos ejecutar una funcionalidad que no soporta evidentemente fallará, uno de esas características justamente es generar secuenciales:

Si se ejecuta:

await conn.raw(`CREATE SEQUENCE spike_seq START WITH 1 INCREMENT BY 1;`);
Enter fullscreen mode Exit fullscreen mode

Se genera un error como el siguiente:

Para más ejemplos en diferentes lenguajes y herramientas revisar estos ejemplos de AWS: https://github.com/aws-samples/aurora-dsql-samples

Conclusiones finales Aurora DSQL

  • Aurora DSQL es una excelente opción para implementar una base de datos compatible con PostgreSQL en aplicaciones nuevas o existentes que requieran el poder y la flexibilidad del lenguaje SQL. Sin embargo, es importante considerar sus limitaciones actuales, entre las que destacan la ausencia de llaves foráneas, secuencias (sequences), triggers y otras características avanzadas del ecosistema PostgreSQL. Para revisar en detalle estas restricciones, se recomienda consultar la documentación oficial de AWS: https://docs.aws.amazon.com/aurora-dsql/latest/userguide/working-with-postgresql-compatibility.html

  • Aurora DSQL es una base de datos distribuida y serverless, cuyo modelo de costos se basa en el consumo de DPUs (Distributed Processing Units) y en el almacenamiento utilizado. Este esquema de facturación permite pagar únicamente por el uso real de los recursos, representando un alivio significativo en costos para aplicaciones con actividad variable. Además, el clúster ajusta automáticamente su capacidad y puede reducir su consumo a cero cuando está inactivo, algo poco común en bases de datos transaccionales, revisar costos en: https://aws.amazon.com/rds/aurora/dsql/pricing/

  • En cuanto a la compatibilidad con herramientas comunes de bases de datos como PostgreSQL, Aurora DSQL ofrece un buen nivel de compatibilidad. Para conectarse y generar las credenciales necesarias, es recomendable utilizar las librerías proporcionadas por AWS. Por lo tanto, esta base de datos puede integrarse en aplicaciones existentes, siempre considerando las limitaciones propias de Aurora DSQL.

  • Finalmente, Aurora DSQL según la documentación resulta ideal para cargas de trabajo dinámicas o impredecibles, como aplicaciones que experimentan picos de tráfico en ciertos momentos del día o de la semana. Sin embargo, en entornos con uso constante, alto rendimiento sostenido o requerimientos avanzados de PostgreSQL, podría resultar más adecuado optar por Aurora PostgreSQL o Amazon RDS PostgreSQL, que ofrecen un comportamiento más tradicional y completo.

Referencias

Top comments (0)