3秒でわかる
書き込み用の DB を複製して読み取り専用にした複製先。参照の負荷を逃がし、集計や一覧表示で本体を重くしないために使います。
30秒図解
もう少し詳しく
どういうものか
リードレプリカは、書き込みを受け付ける主系のデータベースから内容を複製し、参照だけを受け付ける複製先のことです。主系への更新は複製の仕組みを通じて随時レプリカへ送られ、レプリカ側は SELECT だけを処理します。
AWS の RDS や Aurora ではマネージド機能として用意されており、コンソールから数クリックで追加できます。MySQL や PostgreSQL を自前で運用する場合もレプリケーション機能で同じ構成を組めます。
なぜ必要か
多くの業務システムでは、書き込みより読み取りの回数がはるかに多くなります。一覧画面、検索、ダッシュボードの集計はすべて参照です。これらを主系に集めると、重い集計クエリが走っている間に注文の書き込みが待たされるという形で、業務の中心が止まります。
参照をレプリカへ逃がせば、主系は書き込みに専念できます。台数を増やして参照を分散させることもでき、負荷に応じた拡張が書き込み系に触れずに行えます。可用性の面でも、主系が障害を起こした際にレプリカを昇格させる手が使えます。
具体例
アプリ側は接続先を用途で分けます。
[アプリ] --書き込み--> [主系 DB] --複製--> [レプリカ1] <--参照-- [アプリ]
\-----> [レプリカ2] <--参照-- [集計バッチ]Rails の場合、接続先の切り替えは設定で表現できます。
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
connects_to database: { writing: :primary, reading: :replica }
end
ActiveRecord::Base.connected_to(role: :reading) do
Order.where(created_at: 1.month.ago..).group(:shop_id).sum(:amount)
endつまずきやすいところ
複製には遅れがあります。注文を登録した直後に一覧をレプリカから読むと、たった今作った 1 件が出てこないことがあります。数十ミリ秒から、負荷が高いときは数秒に達します。登録直後に見せる画面だけは主系から読む、という切り分けが必要です。
レプリカへ書き込もうとすると読み取り専用エラーになります。参照のつもりで呼んだ処理の中に、最終ログイン時刻の更新のような書き込みが紛れていると、そこで初めて発覚します。
レプリカを増やせば書き込み性能が上がるわけではない点も重要です。書き込みは主系 1 台で受けるため、書き込みが詰まっている状況ではシャーディングや構成変更を検討します。
似た用語との違い
| 用語 | 目的 |
|---|---|
| リードレプリカ | 参照の負荷分散 |
| スタンバイ(待機系) | 障害時の切り替え。通常は参照も受けない |
| バックアップ | 過去時点への復旧 |
覚え方
レプリカは少し前の写し。速さは手に入りますが、鮮度は主系にだけあります。