リードレプリカは、主系データベースの更新を非同期で受け取り、読み取りだけを引き受ける複製インスタンスです。一覧表示や検索、集計のような参照処理を逃がし、主系を書き込みに専念させる目的で置きます。作るだけならAWSのコマンド1本で済みますが、実際に手間がかかるのはアプリ側の振り分けと、遅延を前提にした画面設計の方です。この記事では、RDSとAuroraでのリードレプリカの作成手順、RailsとDjangoでの読み書き分離のコード、遅延とクエリ衝突の監視、昇格の手順、そして導入を見送るべき場面までを実装の順に整理します。
まとめ:リードレプリカで読み取りを逃がす前に決める遅延と振り分けの要点
結論から書きます。リードレプリカは「参照が負荷の大半を占め、数百ミリ秒〜数秒古いデータを読んでも壊れない処理がはっきりしている」システムでだけ効きます。書き込みは1台も速くなりません。
導入の順序は次のとおりです。まずスロークエリと索引を直し、それでも参照負荷で主系が詰まるならレプリカを1台作る。アプリ側では書き込み直後の読み取りを主系へ固定し、残りの参照だけをレプリカへ送る。運用ではReplicaLagに業務要件から決めた閾値で警報を掛け、PostgreSQLなら長いクエリの打ち切りにも備える。RDSとAuroraのどちらを使うかより、この振り分けと監視を先に決める方が障害の数は減ります。
リードレプリカの仕組みとMulti-AZスタンバイ・Auroraレプリカとの違い
主系の更新を非同期で受け取る読み取り専用インスタンスの基本動作
AWSのRDSユーザーガイドのリードレプリカの操作によれば、プライマリDBインスタンスへの更新はリードレプリカへ非同期でコピーされます。主系はレプリカの適用完了を待たずにコミットを返すので、書き込みの応答は増えない。その代わり、レプリカ側は常に少し過去の状態を見ることになります。
RDSで対応するエンジンはMySQL、MariaDB、PostgreSQL、Oracle、SQL Server、Db2の6種類です。同期と非同期でRPOがどう変わるか、物理レプリケーションと論理レプリケーションのどちらを使うかといった方式の選び方はデータベースレプリケーションの同期・非同期の違いと遅延設計で扱っているので、この記事では作る・振り分ける・監視する手順に絞ります。
読めないスタンバイと読めるレプリカを取り違えないための構成比較表
見積もりの段階で最も取り違えやすいのが、Multi-AZのスタンバイとリードレプリカの区別です。
| 構成 | 複製の方式 | 読み取り | 主な用途 |
|---|---|---|---|
| RDS Multi-AZ DBインスタンスの待機系 | 同期 | 不可 | 障害時の自動切り替え |
| RDSのリードレプリカ | 非同期 | 可 | 参照の分散・手動昇格 |
| Auroraレプリカ | 共有ストレージ | 可 | 参照の分散・自動切り替え先 |
Multi-AZのスタンバイは待機専用で、何台分の料金を払っても読み取り容量は増えません。逆にRDSのリードレプリカは読めるものの、主系が落ちても自動では切り替わらない。Auroraレプリカだけが両方を兼ね、Auroraのレプリケーション解説では遅延は通常100ミリ秒未満とされます。ストレージ層の仕組みと料金の差はAmazon Auroraの構成とRDSとの違いを参照してください。
主系1台あたり15台の上限とエンジン別の構成制約・追加料金の考え方
RDSのクォータ一覧では、プライマリ1台あたりのリードレプリカ数「Read replicas per primary」の既定値は15です。Oracleは15台まで作れるものの、遅延を抑えるため5台以内が推奨されています。Auroraも1クラスターあたり最大15台のレプリカという上限で、こちらは引き上げできません。
料金はレプリカ1台が通常のDBインスタンスと同じ単価で掛かります。同一リージョン内の複製転送は無料で、別リージョンへ置くと転送料金が加わる。MySQL、MariaDB、PostgreSQLではレプリカからさらにレプリカを作るカスケード構成も取れますが、Oracle、SQL Server、Db2では使えません。台数を増やす前に、1台目で主系のCPUがどれだけ下がったかを必ず測ってください。
AWS CLIでRDSのリードレプリカを作成し状態を確かめるまでの手順
自動バックアップの有効化と作成時の約1秒のI/O停止という前提条件
リードレプリカの作成手順が挙げる前提は、ソースDBインスタンスの自動バックアップを有効にし、保持期間を0以外にしておくことです。レプリカからレプリカを作る場合も同じ条件が掛かります。
作成時にはソースのスナップショットが自動で取られ、そのときソース側で通常約1秒のI/O停止が起きる。ソースがMulti-AZ構成ならスナップショットはスタンバイ側から取られるため、この停止は避けられます。本番の昼間に作るなら、先にMulti-AZ化しておくか、書き込みの少ない時間帯を選びます。作成直後はS3からデータブロックを読み込みながら動くので、初期化が終わるまで性能が出きらない点も覚えておいてください。
リードレプリカの作成から接続先エンドポイントの取得までのコマンド
create-db-instance-read-replicaによるリードレプリカ作成と、接続先エンドポイント取得の最小手順は次のとおりです。識別子はそれぞれの環境の名前に置き換えます。
# ソース側の自動バックアップ保持期間を確認(0なら先に変更する)
aws rds describe-db-instances \
--db-instance-identifier mydbinstance \
--query "DBInstances[0].BackupRetentionPeriod"
# 同じリージョン・同じVPCにリードレプリカを作成
aws rds create-db-instance-read-replica \
--db-instance-identifier myreadreplica \
--source-db-instance-identifier mydbinstance \
--db-instance-class db.r6g.large
# 利用可能になるまで待ち、接続先エンドポイントを取得
aws rds wait db-instance-available --db-instance-identifier myreadreplica
aws rds describe-db-instances \
--db-instance-identifier myreadreplica \
--query "DBInstances[0].[Endpoint.Address,StatusInfos]"
レプリカは主系と別のエンドポイントを持ちます。アプリはこのホスト名を読み取り用の接続先として受け取る必要があり、ここから先の振り分けはデータベース側ではなくアプリ側の仕事になる。AWSはレプリカを主系と同じVPCに置くことを強く推奨しており、暗号化されたレプリカを作るならソースも暗号化されていなければなりません。
Aurora Auto Scalingでリーダーを0〜15台の範囲で増減させる設定
Auroraでは、リーダーの台数をCPU使用率に合わせて自動で増減できます。Aurora Auto Scalingの解説によれば、最小・最大容量はいずれも0〜15の範囲で指定し、スケールインとスケールアウトのクールダウンは既定で300秒です。
# リーダー台数を1〜4台の範囲で管理対象に登録
aws application-autoscaling register-scalable-target \
--service-namespace rds \
--resource-id cluster:my-aurora-cluster \
--scalable-dimension rds:cluster:ReadReplicaCount \
--min-capacity 1 --max-capacity 4
# リーダーの平均CPUを40%に保つターゲット追跡ポリシー
aws application-autoscaling put-scaling-policy \
--policy-name reader-cpu40 \
--service-namespace rds \
--resource-id cluster:my-aurora-cluster \
--scalable-dimension rds:cluster:ReadReplicaCount \
--policy-type TargetTrackingScaling \
--target-tracking-scaling-policy-configuration \
'{"TargetValue":40.0,"PredefinedMetricSpecification":{"PredefinedMetricType":"RDSReaderAverageCPUUtilization"}}'
Auto Scalingが動くには、最初からリーダーが1台以上ある必要があります。増えたリーダーはリーダーエンドポイントの背後へ自動で加わるため、アプリの接続先を書き換えずに済む。一方、RDSのリードレプリカには台数の自動増減がなく、手動で管理します。
アプリケーションで読み取りと書き込みを振り分けるRailsとDjangoの実装例
Railsのconnects_toと自動ロール切り替えで書き込み後2秒を主系へ固定
Railsは標準機能で読み書きの分離を持っています。Rails Guidesの複数データベースの章にある構成を、リードレプリカの接続先に当てはめると次の形になります。
# config/database.yml
production:
primary:
adapter: postgresql
host: mydbinstance.xxxx.ap-northeast-1.rds.amazonaws.com
database: app_production
primary_replica:
adapter: postgresql
host: myreadreplica.xxxx.ap-northeast-1.rds.amazonaws.com
database: app_production
replica: true
# app/models/application_record.rb
class ApplicationRecord < ActiveRecord::Base
primary_abstract_class
connects_to database: { writing: :primary, reading: :primary_replica }
end
# bin/rails g active_record:multi_db で生成した初期化ファイル内
Rails.application.configure do
config.active_record.database_selector = { delay: 2.seconds }
config.active_record.database_resolver = ActiveRecord::Middleware::DatabaseSelector::Resolver
config.active_record.database_resolver_context = ActiveRecord::Middleware::DatabaseSelector::Resolver::Session
end
この設定では、GETとHEADのリクエストがレプリカへ向かい、POSTやPATCHなどの書き込み後は指定した2秒間、同じセッションの読み取りが主系に固定されます。replica: trueを付け忘れるとRailsはその接続でマイグレーションを流そうとするので、必ず付けてください。2秒という値はAuroraの通常の遅延に対しては余裕があり、RDSのリードレプリカで遅延が秒単位に伸びる環境なら、実測したReplicaLagの上位値に合わせて延ばします。
DjangoのデータベースルータでSELECTだけをレプリカへ送る実装と注意点
Djangoでは、データベースルータで振り分けを定義します。Django 5.2の複数データベースの文書にある例を、レプリカ1台の構成へ縮めたものが次のコードです。
# settings.py
DATABASES = {
"default": {"ENGINE": "django.db.backends.postgresql", "HOST": "mydbinstance.xxxx.ap-northeast-1.rds.amazonaws.com", "NAME": "app"},
"replica": {"ENGINE": "django.db.backends.postgresql", "HOST": "myreadreplica.xxxx.ap-northeast-1.rds.amazonaws.com", "NAME": "app"},
}
DATABASE_ROUTERS = ["myproject.routers.PrimaryReplicaRouter"]
# myproject/routers.py
class PrimaryReplicaRouter:
def db_for_read(self, model, **hints):
return "replica"
def db_for_write(self, model, **hints):
return "default"
def allow_relation(self, obj1, obj2, **hints):
return True
def allow_migrate(self, db, app_label, model_name=None, **hints):
# レプリカは読み取り専用なのでマイグレーションは主系だけに流す
return db == "default"
Railsと違い、このルータは書き込み直後かどうかを知りません。登録処理の直後に同じレコードを読み直す箇所では、Order.objects.using("default").get(pk=pk)のように接続先を明示して主系を読みます。ルータ全体を賢くしようとするより、壊れる画面を洗い出して個別に主系へ向ける方が、挙動を追いやすくなります。
ORMを通らないSQLとトランザクション内の読み取りで起きる振り分け漏れ
振り分けのバグは、ORMの外側で起きることが大半です。
- 生SQLの実行:Djangoの
connection.cursor()は既定の接続を使い、ルータを通りません。 - トランザクション内の読み取り:主系へ書いたあと、同じトランザクションの中で読む処理がレプリカへ流れると、まだ存在しない行を探すことになります。
- バッチとワーカー:Webのリクエストを前提にした自動切り替えは、Sidekiqやジョブキューからの処理には効きません。
いずれも「書いた直後に読む」組み合わせで事故になります。遅延を許容できる処理とできない処理の切り分け方は結果整合性と強整合性の違いとレプリカ遅延の設計に整理しています。
レプリカ遅延とクエリキャンセルを監視して読み取り障害を防ぐ運用設定
ReplicaLagをCloudWatchから取得して警戒水準を決めるコマンド例
RDSは遅延をReplicaLagというCloudWatchメトリクス(秒)で出します。リードレプリケーションのモニタリングによれば、値が-1ならレプリケーションが止まっており、0なら主系に追いついた状態です。
# 直近1時間のReplicaLagの最大値を5分刻みで取得
aws cloudwatch get-metric-statistics \
--namespace AWS/RDS \
--metric-name ReplicaLag \
--dimensions Name=DBInstanceIdentifier,Value=myreadreplica \
--start-time 2026-09-26T00:00:00Z --end-time 2026-09-26T01:00:00Z \
--period 300 --statistics Maximum
-- PostgreSQLのレプリカに接続して遅延秒数を直接確かめるSQL
SELECT extract(epoch from now() - pg_last_xact_replay_timestamp()) AS reader_lag;
閾値は製品の既定値ではなく、Railsのdelayに設定した秒数から逆算します。2秒で主系固定を解除しているなら、ReplicaLagの警告は1秒、重大は2秒という具合です。遅延がこの値を超えた時間帯は、書き込み直後の画面で古い値が見えている可能性がある。PostgreSQLのSQLは書き込みが止まっている時間帯に値が伸び続ける癖があるので、CloudWatchの値と並べて判断してください。
PostgreSQLのレプリカで長いクエリが打ち切られる衝突と設定の選び方
PostgreSQLのレプリカで集計クエリを走らせると、canceling statement due to conflict with recoveryというエラーで途中終了することがあります。主系のVACUUMが消した行を、レプリカ側の長いクエリがまだ読んでいるときに起きる衝突です。PostgreSQL 18のHot Standbyの文書は、衝突の原因として排他ロック、VACUUMによる行の削除、データベースの削除など5種類を挙げています。
対処は2つあり、代償が違います。max_standby_streaming_delay(本体の既定は30秒)を延ばせば、クエリは生き残るものの、その間レプリカへの適用が止まって遅延が伸びる。hot_standby_feedbackを有効にすれば打ち切りは減る一方、主系のVACUUMが行を回収できずにテーブルが膨らみます。参照用のレプリカと分析用のレプリカを分け、分析用だけ遅延を大きく許すのが扱いやすい構成です。発生件数はレプリカ側のpg_stat_database_conflictsで数えられます。
30日停止で自動終了されるレプリケーション状態の見方とerror時の対処
レプリケーションの状態は、コンソールやdescribe-db-instancesのStatusInfosで確認できます。正常時はreplicating、異常時はerrorです。MySQLとMariaDBでは手動で止めたstoppedもあります。
見落としやすいのがterminatedです。MySQL、MariaDB、PostgreSQLでは、レプリケーションが30日を超えて連続停止すると自動的に終了され、再開できなくなる。保持されたログがストレージを圧迫し、切り替え時間を延ばすのを防ぐための仕様です。errorを検知したら、30日の猶予を待たずに原因を直すか、レプリカを作り直すかを決めます。
昇格・クロスリージョン・移行でリードレプリカを使う場面と戻れない操作
レプリカ昇格前に書き込み停止とReplicaLag 0を確認する手順
リードレプリカは、promote-read-replicaで単独のDBインスタンスへ昇格できます。昇格の手順では、主系への書き込みを止め、ReplicaLagで全更新の反映を確かめてから実行するよう求めています。
# 1. アプリの書き込みを止めたあと、遅延が0になったことを確認
aws cloudwatch get-metric-statistics --namespace AWS/RDS --metric-name ReplicaLag \
--dimensions Name=DBInstanceIdentifier,Value=myreadreplica \
--start-time 2026-09-26T00:00:00Z --end-time 2026-09-26T00:10:00Z \
--period 60 --statistics Maximum
# 2. 昇格(完了までレプリカは再起動を伴う)
aws rds promote-read-replica \
--db-instance-identifier myreadreplica \
--backup-retention-period 7
昇格したインスタンスはリードレプリカへ戻せません。所要時間はインスタンスの大きさによって数分から数十分かかる。この一方通行の性質を使い、メジャーバージョンアップ前の検証や、大きな索引の作成をレプリカ側で済ませてから切り替える使い方もあります。
別リージョンのレプリカでDRに備えるときの転送料金とRPOの見積もり
リードレプリカは主系と別のリージョンにも置けます。リージョン全体の障害に備え、昇格させて主系の代わりにする使い方です。ただし同一リージョンでは無料の複製転送が、リージョンをまたぐと課金対象になります。
見積もりで忘れやすいのはRPOです。非同期のため、主系リージョンが落ちた瞬間にレプリカへ届いていない更新は失われる。昇格も手動なので、RTOには人が判断して操作する時間が乗ります。1秒未満の欠損と自動に近い切り替えを求めるなら、Aurora Global Databaseを別途検討する段階です。
参照負荷から見るリードレプリカを入れるべき条件と見送るべき場面の判断基準
主系の参照比率とスロークエリの内訳からレプリカ導入の要否を判定する順序
判定は3段階で進めます。第一に、主系の負荷のうち参照が何割かを測る。スロークエリログやPostgreSQLのpg_stat_statementsで上位のクエリを並べ、SELECTが負荷の大半を占めていなければ、レプリカは効きません。第二に、上位の参照クエリに索引の欠落や全件走査が無いかを見る。1本の索引で負荷が半分になる事例は珍しくありません。
第三に、残った参照を「数秒古くても壊れない処理」と「書いた直後に読む処理」へ分ける。前者が大半を占めて初めて、リードレプリカの導入に進みます。台数を足す考え方そのものの整理はスケールアウトとスケールアップの違いと使い分けが前提になります。
キャッシュとインスタンス増強で足りるのにレプリカを足す失敗パターン
見送るべき場面ははっきりしています。同じ一覧や商品情報を何度も読むだけなら、アプリ側のキャッシュの方が遅延も費用も小さい。主系のCPUに余裕がないだけで参照比率が低いなら、インスタンスクラスを1段上げる方が早く、振り分けのコードも要りません。
もう1つの失敗は、書き込み直後に読む画面が多いシステムへレプリカを入れることです。主系固定の例外が増えるほど、レプリカへ流れる参照は減り、1台分の料金と遅延という新しい障害要因だけが残る。こうした構成の見立てやRDS・Auroraの設計、移行までを含むクラウド基盤の構築は、AWS・Google Cloud・Azureのインフラ構築支援でも相談を受けています。
よくある質問
リードレプリカの導入と運用で繰り返し出てくる質問に答えます。
リードレプリカを増やせば書き込みも速くなりますか?
速くなりません。書き込みを受け付けるのは主系1台のままで、レプリカはその変更を後から適用するだけです。主系の書き込み処理そのものが上限に達しているなら、インスタンスの増強、不要データの退避、それでも足りなければシャーディングによる水平分割という順序で検討します。参照負荷を逃がした結果として主系に余裕が生まれ、書き込みの応答が改善する間接的な効果はあります。
リードレプリカとMulti-AZは両方必要ですか?
目的が違うので、可用性と参照分散の両方が要るなら両方を置きます。RDSのMulti-AZ DBインスタンスのスタンバイは読めず、障害時の自動切り替え専用です。リードレプリカは読めますが自動では切り替わりません。Auroraを選べばレプリカが切り替え先を兼ねるため、1台で両方の役割を持たせられます。
リードレプリカに書き込むことはできますか?
通常の運用では書き込みません。PostgreSQLのレプリカは読み取り専用で、書き込みはエラーになります。MySQLでは設定次第で書けてしまう場合がありますが、主系と内容がずれてレプリケーションが止まる原因になります。書き込みが必要になったら、レプリカを昇格させて独立したインスタンスとして扱うのが正しい手順です。
リードレプリカの遅延はどのくらいですか?
構成と負荷によって変わります。Auroraレプリカは共有ストレージを使うため、AWSの文書では通常100ミリ秒未満とされています。RDSのリードレプリカはログを転送して適用する方式で、書き込みが集中する時間帯や長いトランザクションの後には秒単位へ伸びることがある。実際の値はReplicaLagで継続的に測り、振り分けの設計に反映してください。
リードレプリカの料金はどう計算されますか?
RDSのリードレプリカは、同じクラスの通常のDBインスタンスと同じ単価で課金されます。ストレージも別途掛かります。同一リージョン内の複製転送は無料で、別リージョンに置くとデータ転送料金が加わる。2台目以降を足す前に、1台目で主系の負荷がどれだけ下がったかを測り、費用対効果を確かめてから判断するのが確実です。
関連記事
- Amazon RDSとは?仕組み・対応エンジンと料金モデル・採用判断を実装者目線で解説:リードレプリカの土台になるRDSの全体像を確認できます
- Aurora PostgreSQLとは?対応バージョン・拡張機能とBabelfish・RDSからの移行判断を実装者目線で解説:Auroraレプリカを使う前提のPostgreSQL互換版を扱っています
- Amazon RDS for PostgreSQLとは?マルチAZ構成・拡張機能の統制と延長サポート課金・DMS移行を実装目線で解説:マルチAZとレプリカを組み合わせる構成の検討に使えます
- Cloud SQLとは?GCPのマネージドRDBの仕組み・エディションと採用判断を実装者目線で解説:Google Cloudでリードレプリカを組む場合の前提を整理しています