Envía consultas a una réplica de lectura

AWSBeginner
Practicar Ahora

Introducción

La aplicación envía lecturas y escrituras al mismo primario. Crearás una réplica PostgreSQL, dirigirás las consultas a ella y demostrarás que recibe las nuevas escrituras del primario, mientras rechaza escrituras directas.

Esta es una extensión opcional después de los laboratorios de conexión, SQL y recuperación. El entorno empieza de forma independiente con un primario y tres pedidos de ejemplo. Eliminarás la réplica y el primario al final.

Relación con certificaciones

Este laboratorio ofrece práctica introductoria para los siguientes temas de examen.

Crea e inspecciona una réplica de lectura

En este paso crearás otro PostgreSQL que recibe cambios del primario.

Una réplica de lectura atiende consultas con datos copiados. PostgreSQL envía cambios mediante el registro de escritura anticipada, o WAL. El servidor en espera reproduce los cambios; es un motor separado y la replicación puede ir por detrás de una escritura recién confirmada.

Una réplica de lectura y un servidor en espera Multi-AZ tienen fines distintos. La réplica ofrece un endpoint para consultas. El servidor en espera de una implementación estándar de instancia de base Multi-AZ sirve para disponibilidad y conmutación por error y no atiende lecturas de aplicaciones. Este laboratorio implementa una réplica, no una conmutación Multi-AZ.

Carga la configuración de conexión:

cd /home/labex/project
source database.env

Inspecciona el origen:

aws rds \
  describe-db-instances \
  --db-instance-identifier orders-db \
  --query 'DBInstances[0].{Identifier:DBInstanceIdentifier,Status:DBInstanceStatus,BackupRetention:BackupRetentionPeriod,Endpoint:Endpoint}'

RDS exige un período de retención de copias distinto de cero en el origen de una réplica. Este entorno proporciona un primario con retención 1. Usarás esa configuración; el ejercicio no prueba la programación automática de copias.

Crea la réplica:

aws rds \
  create-db-instance-read-replica \
  --db-instance-identifier orders-reader \
  --source-db-instance-identifier orders-db \
  --db-instance-class db.t3.micro \
  --no-publicly-accessible \
  --query 'DBInstance.{Identifier:DBInstanceIdentifier,Source:ReadReplicaSourceDBInstanceIdentifier,Status:DBInstanceStatus,Endpoint:Endpoint}'
aws rds \
  wait db-instance-available \
  --db-instance-identifier orders-reader

Inspecciona ambos recursos:

aws rds \
  describe-db-instances \
  --query 'DBInstances[].{Identifier:DBInstanceIdentifier,Source:ReadReplicaSourceDBInstanceIdentifier,Endpoint:Endpoint.Address}' \
  --output table

Debes obtener otro endpoint para orders-reader y una relación de origen con orders-db. AWS View debe listar primario y réplica.

Consulta el motor real de la réplica:

psql \
  "service=orders-reader" \
  --command 'SELECT current_database(), pg_is_in_recovery();'

Debes obtener la base orders y pg_is_in_recovery igual a t (true). PostgreSQL ejecuta realmente el modo de recuperación en espera, en vez de tener solo una etiqueta de réplica en RDS.

Separa los endpoints de lectura y escritura

En este paso mantendrás las escrituras en el primario y enviarás las consultas a la réplica.

Las escrituras van al principal; las lecturas pueden usar la réplica asíncrona

Diagrama conceptual: Las escrituras van al principal; las lecturas pueden usar la réplica asíncrona.

Inspecciona la configuración de la aplicación:

cat app-config.json

Ambos hosts indican el primario. Obtén el endpoint de la réplica:

READER_ENDPOINT=$(aws rds \
  describe-db-instances \
  --db-instance-identifier orders-reader \
  --query 'DBInstances[0].Endpoint.Address' \
  --output text)

Cambia solo read_host:

jq \
  --arg host "$READER_ENDPOINT" \
  '.read_host = $host' \
  app-config.json > app-config.new
mv app-config.new app-config.json

Lee mediante la aplicación:

curl \
  --silent \
  --show-error \
  --fail \
  http://127.0.0.1:8080/application/orders | jq

Debes obtener los tres pedidos originales y read_only: true. La respuesta procede de la conexión SQL real de la aplicación al servidor en espera. AWS View debe identificarlo como réplica de lectura.

La réplica usa las identidades de base copiadas del origen. Elegir el endpoint decide qué instancia recibe la conexión; la autenticación y los permisos SQL siguen aplicándose.

Observa la replicación y el rechazo de escrituras

En este paso guardarás un pedido por el primario y lo leerás de la réplica.

Añade un pedido por la aplicación. Su manejador POST usa write_host, que sigue apuntando al primario:

curl \
  --silent \
  --show-error \
  --fail \
  --request POST \
  --header 'Content-Type: application/json' \
  --data '{"order_id":104,"customer":"Kai","total":"5.00"}' \
  http://127.0.0.1:8080/application/orders

Debes obtener saved: true. Consulta origen y réplica por separado:

psql \
  "service=orders-db" \
  --command 'SELECT order_id, customer, total FROM orders WHERE order_id = 104;'
psql \
  "service=orders-reader" \
  --command 'SELECT order_id, customer, total FROM orders WHERE order_id = 104;'

Debes obtener el pedido de Kai por 5.00 en ambos. Si aún no aparece en la primera consulta a la réplica, repítela al cabo de un momento: la replicación asíncrona admite retraso. Una réplica sirve para cargas con muchas lecturas, pero la consistencia inmediata puede exigir leer del primario un valor recién escrito.

Lee otra vez la lista de la aplicación:

curl \
  --silent \
  --show-error \
  --fail \
  http://127.0.0.1:8080/application/orders | jq

Debes obtener cuatro pedidos y read_only: true.

Intenta insertar realmente en la réplica:

psql \
  "service=orders-reader" \
  --set=ON_ERROR_STOP=1 \
  --command "INSERT INTO orders (order_id, customer, total) VALUES (105, 'Lena', 9.00);"

Debes obtener un error indicando que INSERT no se puede ejecutar en una transacción de solo lectura. El modo de recuperación rechaza la escritura incluso con la identidad maestra. Confirma que el pedido intentado no existe en ninguno de los motores:

psql \
  "service=orders-db" \
  --command 'SELECT count(*) FROM orders WHERE order_id = 105;'
psql \
  "service=orders-reader" \
  --command 'SELECT count(*) FROM orders WHERE order_id = 105;'

Debes obtener 0 de cada uno. Las escrituras corresponden al primario; las consultas pueden usar la réplica cuando sus requisitos de consistencia lo permiten. La aplicación lee los pedidos originales y el nuevo pedido replicado desde la réplica de solo lectura.

Elimina réplica y primario

En este paso eliminarás las dos instancias de práctica.

Elimina primero la réplica y después el origen:

aws rds \
  delete-db-instance \
  --db-instance-identifier orders-reader \
  --skip-final-snapshot \
  --query 'DBInstance.DBInstanceIdentifier'
aws rds \
  wait db-instance-deleted \
  --db-instance-identifier orders-reader
aws rds \
  delete-db-instance \
  --db-instance-identifier orders-db \
  --skip-final-snapshot \
  --query 'DBInstance.DBInstanceIdentifier'
aws rds \
  wait db-instance-deleted \
  --db-instance-identifier orders-db
aws rds \
  describe-db-instances \
  --query 'DBInstances[].DBInstanceIdentifier'

Debes obtener [] y ninguna base en AWS View. Conserva la aplicación y los recursos de red preparados.

Resumen

Creaste una réplica PostgreSQL y verificaste su modo real de recuperación en espera. Separaste los endpoints de lectura y escritura, observaste una escritura del primario llegar a la réplica y confirmaste el rechazo de escrituras directas. Finalmente eliminaste ambas instancias.

Una réplica soporta patrones de lectura; su finalidad y comportamiento difieren del servidor en espera de una implementación estándar de instancia Multi-AZ. El desafío final aplica las habilidades de conexión y diagnóstico aprendidas.