Введение
Приложение направляет чтение и запись в одну основную базу. Вы создадите реплику PostgreSQL, перенаправите чтение и докажете, что новые записи основного экземпляра становятся доступны на реплике, а запись в неё отклоняется.
Это необязательное расширение после работ о подключении, SQL и восстановлении. Среда начинается независимо с основной базой и тремя заказами. В конце вы удалите реплику и основной экземпляр.
Связь с сертификацией
Эта работа даёт начальную практику по следующим темам экзаменов.
- Cloud Practitioner (CLF-C02) · Задача 3.4: Распознать применение реляционной реплики чтения.
- Solutions Architect – Associate (SAA-C03) · Задача 3.3: Настроить реплики для шаблона чтения приложения.
Создание и проверка реплики чтения
На этом этапе вы создадите второй PostgreSQL, принимающий изменения основного экземпляра.
Реплика чтения отвечает на запросы из скопированных данных. PostgreSQL передаёт изменения через журнал предзаписи — WAL. Резервный сервер воспроизводит изменения. Это отдельный движок, и репликация может отставать от только что подтверждённой записи.
Реплика чтения и резервный экземпляр Multi-AZ имеют разные цели. Реплика предоставляет endpoint для запросов приложения. Резервный сервер стандартного развёртывания DB-экземпляра Multi-AZ обеспечивает доступность и переключение при отказе, но не обслуживает чтение приложения. Здесь реализована реплика, а не переключение Multi-AZ.
Загрузите настройки подключения:
cd /home/labex/project
source database.env
Проверьте источник:
aws rds \
describe-db-instances \
--db-instance-identifier orders-db \
--query 'DBInstances[0].{Identifier:DBInstanceIdentifier,Status:DBInstanceStatus,BackupRetention:BackupRetentionPeriod,Endpoint:Endpoint}'
RDS требует ненулевой срок хранения резервных копий для источника реплики. Этот модуль предоставляет основную базу со сроком 1. Вы используете готовую конфигурацию; планирование автоматических копий не проверяется.
Создайте реплику:
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
Проверьте оба ресурса:
aws rds \
describe-db-instances \
--query 'DBInstances[].{Identifier:DBInstanceIdentifier,Source:ReadReplicaSourceDBInstanceIdentifier,Endpoint:Endpoint.Address}' \
--output table
Ожидаются отдельный endpoint orders-reader и связь с источником orders-db. AWS View должен показать основную базу и реплику.
Запросите настоящий движок реплики:
psql \
"service=orders-reader" \
--command 'SELECT current_database(), pg_is_in_recovery();'
Ожидаются база orders и pg_is_in_recovery равное t (true). PostgreSQL действительно работает в режиме восстановления резервного сервера, а не просто имеет метку реплики в RDS.
Разделение endpoints чтения и записи
На этом этапе вы оставите запись на основном экземпляре, а чтение направите в реплику.

Концептуальная схема: Запись идёт в основную БД; чтение может использовать асинхронно обновляемую реплику.
Проверьте конфигурацию приложения:
cat app-config.json
Оба хоста указывают на основную базу. Получите endpoint реплики:
READER_ENDPOINT=$(aws rds \
describe-db-instances \
--db-instance-identifier orders-reader \
--query 'DBInstances[0].Endpoint.Address' \
--output text)
Измените только read_host:
jq \
--arg host "$READER_ENDPOINT" \
'.read_host = $host' \
app-config.json > app-config.new
mv app-config.new app-config.json
Прочитайте данные через приложение:
curl \
--silent \
--show-error \
--fail \
http://127.0.0.1:8080/application/orders | jq
Ожидаются три исходных заказа и read_only: true. Ответ приходит из реального SQL-подключения к резервному серверу. AWS View должен определить источник данных приложения как реплику чтения.
Реплика использует учётные записи базы, скопированные из источника. Выбор endpoint определяет экземпляр назначения; аутентификация и SQL-права по-прежнему действуют.
Наблюдение репликации и отказа записи
На этом этапе вы сохраните новый заказ через основную базу и прочитаете его из реплики.
Добавьте заказ через приложение. Его обработчик POST использует write_host, всё ещё указывающий на основную базу:
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
Ожидается saved: true. Запросите источник и реплику независимо:
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;'
Ожидается заказ Kai на 5.00 на обоих. Если первый запрос реплики ещё не видит строку, повторите его через некоторое время: асинхронная репликация допускает задержку. Реплика полезна для частого чтения, но немедленная согласованность может требовать чтения только что записанного значения из основной базы.
Прочитайте список приложения снова:
curl \
--silent \
--show-error \
--fail \
http://127.0.0.1:8080/application/orders | jq
Ожидаются четыре заказа и read_only: true.
Попробуйте выполнить настоящую вставку в реплику:
psql \
"service=orders-reader" \
--set=ON_ERROR_STOP=1 \
--command "INSERT INTO orders (order_id, customer, total) VALUES (105, 'Lena', 9.00);"
Ожидается ошибка о невозможности INSERT в транзакции только для чтения. Режим восстановления отвергает запись даже для главного пользователя. Убедитесь, что попытка не создала заказ в любом из движков:
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;'
Ожидается 0 в каждом. Записывать следует в основную базу, а читать из реплики — когда это допускают требования согласованности.

Удаление реплики и основной базы
На этом этапе вы удалите два учебных экземпляра.
Сначала удалите реплику, затем источник:
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'
Ожидаются [] и отсутствие баз в AWS View. Сохраните приложение и подготовленные сетевые ресурсы.
Итоги
Вы создали реплику PostgreSQL и проверили настоящий режим восстановления. Разделили endpoints чтения и записи, увидели новую запись основного экземпляра в реплике и подтвердили отказ прямой записи. Затем удалили оба экземпляра.
Реплика поддерживает чтение; её цель и поведение отличаются от резервного сервера стандартного развёртывания DB-экземпляра Multi-AZ. Финальное задание применяет изученные навыки подключения и диагностики.



