Slide 1

Slide 1 text

GraphQL×Railsアプリのデータベース負荷分散 - 月間3,000万人利用サービスを無停止で 2025.09.26 Kaigi on Rails 2025 @JP TOWER Hall & Conference Koya Masuda 1

Slide 2

Slide 2 text

GraphQL×Railsアプリのデータベース負荷分散 - 月間3,000万人利用サービスを無停止で 2

Slide 3

Slide 3 text

GraphQL×Railsアプリのデータベース負荷分散 - 月間3,000万人利用サービスを無停止で → RDBにおけるRead/Write Splitting(r/w Splitting) 3

Slide 4

Slide 4 text

GraphQL×Railsアプリのデータベース負荷分散 - 月間3,000万人利用サービスを無停止で → Rails標準機能に乗っかれなくて困ることがある 4

Slide 5

Slide 5 text

GraphQL×Railsアプリのデータベース負荷分散 - 月間3,000万人利用サービスを 無停止で → ビジネス要求に答える 💪 5

Slide 6

Slide 6 text

GraphQL×Railsアプリのデータベース負荷分散 - 月間3,000万人利用サービス を無停止で → マイベスト 6

Slide 7

Slide 7 text

月間利用者数 3,000 ユーザーの “選択”を サポートするサービス 万人以 上 (2025年8月時点) 7

Slide 8

Slide 8 text

商品の検証の様子

Slide 9

Slide 9 text

インターネッツを観測できる 9 非常に強い大型台風10号が日本到来 → 気圧が急激に下がる → みんなのストームグラスがエグくイキリ 立つ → Xにあげてバズる → 検索してマイベストで比較検討する

Slide 10

Slide 10 text

インターネッツを観測できる 10 非常に強い大型台風10号が日本到来 → 気圧が急激に下がる → みんなのストームグラスがエグくイキリ 立つ → Xにあげてバズる → 検索してマイベストで比較検討する

Slide 11

Slide 11 text

持ち帰っていただきたいこと 11 ● GraphQL × RailsのDB負荷分散はQueryとMutationの責務分離で実現できる ● 技術選定は「組織」の観点を持つ ● ホワイトリストで小さく試してリスク管理しよう

Slide 12

Slide 12 text

想定する聞き手 12 ● GraphQL × Railsを使って開発している、しようとしている方 ● DB負荷分散について学んでみたい方 ● リスク管理しながら技術導入するプロセスが気になる方

Slide 13

Slide 13 text

1 DB負荷分散することになった背景 3 技術選定プロセス 2 Read / Write Splittingの技術 4 GraphQL × RailsでRead / Write Splittingしようとすると困ること 13 アウトライン 5 リスク管理しながら導入する

Slide 14

Slide 14 text

01 DB負荷分散導入することになった背景 14

Slide 15

Slide 15 text

テレビ特集 15 某テレビ番組 某コーナー

Slide 16

Slide 16 text

テレビ特集 ● レポーターが話題の企業や人物を徹底取材 ● 「今注目の mybestにTV初潜入!」という企画 ● 平日朝 7:35から10分ほど特集される 16

Slide 17

Slide 17 text

マイベストのアーキテクチャ 17 ● ECSはオートスケールに対応 ● アプリケーションからAuroraへはwriterのクラスターにのみ接続

Slide 18

Slide 18 text

マイベストのアーキテクチャ 18 やれるとしたらECSタスクを事前 に増やすくらいかなぁ

Slide 19

Slide 19 text

いざ、放送! 19

Slide 20

Slide 20 text

サイトめちゃ重い ● 1分間に40,000アクセス ● 666rps相当 ● 鳴り止まないアラート ● ECSはオートスケールも… ● DBがボトルネック → サービスダウン 20

Slide 21

Slide 21 text

テレビ砲直撃 😭 ● 1分間に40,000アクセス ● 666rps相当 ● 鳴り止まないアラート ● ECSはオートスケールも… ● DBがボトルネック → サービスダウン 21

Slide 22

Slide 22 text

これまで月間 3,000万UUを どうやって捌いてきたのか? 🤔 22

Slide 23

Slide 23 text

普段のユーザー行動 23 https://my-best.com/1234 → 直接アクセスが多いので、コンテンツに CDNキャッシュを設定している スマホ壊れちゃった … 「スマホ おすすめ」

Slide 24

Slide 24 text

テレビ特集時のユーザー行動 24 マイベストというサービスが あるらしいぞ https://my-best.com/ → サービス名で流入し、キャッシュの効いていないページにアクセス 「マイベスト」

Slide 25

Slide 25 text

DBをスケールアウトできないと 取れる手段が限られる 25

Slide 26

Slide 26 text

02 Read / Write Splittingの手段 26

Slide 27

Slide 27 text

Read / Write Splittingとは? 27

Slide 28

Slide 28 text

DBサーバー 前提知識:レプリケーション ● 複数のサーバーにデータベースを複製 する技術 ● 同じデータを持つデータベースに同じ SQLを実行したら、同じ状態になるよね、 という考え方 ● 複製されたデータベースをレプリカと呼 ぶ 28 アプリケーション サーバー CRUD データ同期 プライマリ レプリカ https://www.shoeisha.co.jp/book/detail/9784798186627

Slide 29

Slide 29 text

DBサーバー リードレプリカによる負荷分散 ● 参照専用のレプリカをリードレプリカと呼 ぶ ● リードレプリカを増やすことで参照SQLを 分散できる ● Read(参照)とWrite(更新)のSQLを分 離して別のDBに処理させることを「Read / Write Splitting」という ※以降、プライマリ=writer、レプリカ=readerと表現します 29 アプリケーション サーバー Write データ同期 Read プライマリ リードレプリカ

Slide 30

Slide 30 text

Read / Write Splittingしてくれるのは誰? 30

Slide 31

Slide 31 text

①ミドルウェアに任せる ②アプリケーション側で接続するデータベースを分岐する 31 Read / Write Splitting の主なアプローチ

Slide 32

Slide 32 text

①ミドルウェアに任せる(※Rackではないです) 32 Read / Write Splitting の主なアプローチ アプリケーション サーバー ミドルウェア ミドルウェアの設定を書く writer reader

Slide 33

Slide 33 text

②アプリケーション側で接続するデータベースを分岐する 33 Read / Write Splitting の主なアプローチ アプリケーション サーバー ここをアプリケーションで実装する writer reader

Slide 34

Slide 34 text

Railsの複数DB ● 複数DBのマイグレーション ● r/wのロールの自動切り替え ● 手動のデータベース接続切替 ● モデル単位の切替 34 https://railsguides.jp/v8.0/active_record_multiple_databases.html config/database.yml レプリカには replica: trueを指定する

Slide 35

Slide 35 text

reader / writer ロールの自動切り替え 35 https://railsguides.jp/v8.0/active_record_multiple_databases.html HTTPメソッドによってreaderとwriterのロールを使い分け POST, DELETE PUT, PATCH GET, HEAD reader writer

Slide 36

Slide 36 text

03 技術選定プロセス 36

Slide 37

Slide 37 text

技術選定、どんな観点で考えるか? 37

Slide 38

Slide 38 text

技術選定のポイント 38 ● 技術に関すること ○ 要件を満たせる技術なのか? ○ 拡張性があるか? ● 組織に関すること ○ 普段の開発速度に影響するか? ○ 扱えるメンバーがどれくらいいるか? https://book.impress.co.jp/books/1118101029

Slide 39

Slide 39 text

当時のマイベストの開発組織 39 ● バックエンドエンジニア:10名 ● SRE:2名 ○ バックエンドから転向&バックエンド兼務 ○ 業務委託(稼働薄め)

Slide 40

Slide 40 text

技術選定 40 アプリケーション ミドルウェア 技術 欲しい機能は自分たちで実装 多機能 組織 扱える人数が多い 扱える人数が少ない

Slide 41

Slide 41 text

技術選定 41 ● 複数DBに対応している ● 新しい依存関係が増えない ● Rails(Ruby)に閉じた中でコントロールできるメリット アプリケーション ミドルウェア 技術 欲しい機能は自分たちで実装 多機能 組織 扱える人数が多い 扱える人数が少ない

Slide 42

Slide 42 text

技術選定 42 アプリケーション ミドルウェア 技術 欲しい機能は自分たちで実装 多機能 組織 扱える人数が多い 扱える人数が少ない ● 初期実装者の手を離れても、他の開発者がメンテナンスできるメリット

Slide 43

Slide 43 text

技術選定 43 アプリケーション ミドルウェア 技術 欲しい機能は自分たちで実装 多機能 組織 扱える人数が多い 扱える人数が少ない ● アプリケーションでRead / Write Splittingの制御を行うことに決定

Slide 44

Slide 44 text

04 GraphQL × Railsでr/w Splitting しようとすると困ること 44

Slide 45

Slide 45 text

前提知識: GraphQLの基礎① 45 参照がQuery、更新がMutation Operation SQL GraphQL Create INSERT Mutation Read SELECT Query Update UPDATE Mutation Delete DELETE Mutation

Slide 46

Slide 46 text

前提知識: GraphQLの基礎② 46 POSTのリクエストボディにクエリを書く to curl

Slide 47

Slide 47 text

GraphQL × Railsのr/w Splittingで困ること 47

Slide 48

Slide 48 text

① GraphQLリクエストが HTTP POSTリクエストである 48 RailsはHTTPメソッドで接続DBを切り替えるため、標準機能は使えない POST, DELETE PUT, PATCH GET, HEAD writer reader

Slide 49

Slide 49 text

② Queryで更新している(かも) ● GETリクエストで更新しているようなもの ● Query→参照、Mutation→更新だが、Queryで更新していないかは実装による ○ Queryの中で`find_or_create_by!`みたいな実装を発見 😭 → Mutationをwriterに、Queryをreaderに、と単純にはできない 49

Slide 50

Slide 50 text

① GraphQLがPOSTリクエストな件 50

Slide 51

Slide 51 text

CQRSパターン 51 参照がQuery、更新がCommand https://docs.aws.amazon.com/ja_jp/prescriptive-guidance/latest/modernization-data-persistence/cqrs-pattern.html

Slide 52

Slide 52 text

CQRSパターン 52 参照がQuery、更新がCommand https://docs.aws.amazon.com/ja_jp/prescriptive-guidance/latest/modernization-data-persistence/cqrs-pattern.html GraphQLに似ている ● CommandがMutation ● QueryはそのままQuery

Slide 53

Slide 53 text

CQRSパターン 53 参照がQuery、更新がCommand https://kaigionrails.org/2023/talks/krpk1900/ GraphQLに似ている ● CommandがMutation ● QueryはそのままQuery

Slide 54

Slide 54 text

CQRSパターン 54 Mutation → writer、Query → reader https://docs.aws.amazon.com/ja_jp/prescriptive-guidance/latest/modernization-data-persistence/cqrs-pattern.html

Slide 55

Slide 55 text

graphql-rubyのTracing 55 ● 様々なGraphQLのイベントをフックでき る ● 自由にmoduleを定義でき、schemaに mixinできる

Slide 56

Slide 56 text

Tracingを用いたRead / Write Splitting 56 複数Queryをまとめて実行するメソッド すべてQuery(Mutationを含まない) ならreaderに接続する

Slide 57

Slide 57 text

② Queryは本当にRead Only…? 57

Slide 58

Slide 58 text

ホワイトリスト式 Read / Write Splitting 58 Read OnlyなQuery名をホワイトリストに登録 Query && ホワイトリスト登録済みか

Slide 59

Slide 59 text

どうやって Read Onlyなことを確認する? 59

Slide 60

Slide 60 text

Active Support Instrumentation 60 https://railsguides.jp/active_support_instrumentation.html ● Railsの内部イベントをフックできる仕組み ● ActiveSupport::Notifications.subscribeでブロック内で測定できる

Slide 61

Slide 61 text

Active Support Instrumentation 61 https://railsguides.jp/active_support_instrumentation.html ● Railsの内部イベントをフックできる仕組み ● ActiveSupport::Notifications.subscribeでブロック内で測定できる

Slide 62

Slide 62 text

Active Support InstrumentationでQueryによるSQLを検査 62 更新SQLを正規表現で探して、見つかったら例外を吐く SQL発行時のイベント 開発環境やステージングに導入し開発時に気がつけるように!

Slide 63

Slide 63 text

課題と解決アプローチのまとめ 63 1. GraphQLリクエストがHTTP POSTリクエストである → CQRSパターンに沿って、Query → reader、Mutation → writer 2. Queryで更新している(かも) → Read OnlyなQueryをホワイトリストで管理する

Slide 64

Slide 64 text

05 リスク管理しながら導入する 64

Slide 65

Slide 65 text

graphql-rubyのSchema 65 SchemaにはQueryやMutationの型情報やフィールド名を書いておく

Slide 66

Slide 66 text

マイベストの Schema 66 管理画面 Web アプリ

Slide 67

Slide 67 text

マイベストの Schema 67 影響箇所や利用時間帯が限られているので、ファーストステップに最適 管理画面 Web アプリ

Slide 68

Slide 68 text

小さく試す 68 ● はじめに管理画面の影響範囲の狭いQueryでの動作確認を取った ● その後、Webやアプリの主要Queryをホワイトリストに追加していった ● 優先順位はテレメトリから総実行時間が長い順に進めた

Slide 69

Slide 69 text

メトリクスの変化をお祝い 69

Slide 70

Slide 70 text

70 プライマリ DBのCPU利用率をピーク時から 50%Down🎉 データベースがスケールアウトできない課題も解決 🎉

Slide 71

Slide 71 text

まとめ 71 ● GraphQL × RailsのDB負荷分散はQueryとMutationの責務分離で実現できる ● 技術選定は「組織」の観点を持つ ● ホワイトリストで小さく試してリスク管理しよう

Slide 72

Slide 72 text

About me Koya Masuda ● 2021年 新卒で未経験からエンジニア ● 2024年~ マイベスト所属 ● サッカーが好き @koxya @koxya 72

Slide 73

Slide 73 text

LT登壇者募集中!!! 73 https://connpass.com/event/370180/