R/W Splittingライブラリを自作する際に考えたことと、 実際に使い始めてどうだったかについて振り返ってみました
© - BASE, Inc.2020/06/04 コネヒトマルシェ オンライン川島 慧/@nazonohito既存サービスに後からR/W Splittingライブラリを⼊れる時に考えたこと
View Slide
© - BASE, Inc.Product Division 川島 慧@nazonohito
© - BASE, Inc.BASEがR/W Splittingを開始してからちょうど1年経ったので、ライブラリ製作者の視点から振り返ってみます
© - BASE, Inc.そもそもR/W Splittingとは?
© - BASE, Inc.R/W Splittingとは• Read/Write Splitting• マスター/リードレプリカ構成のRDBMSに対して負荷分散の⽬的でアプリケーションのアクセス先を制御する• 参照系クエリをリードレプリカに寄せることでマスターのマシンリソースを有効活⽤できるようになる
© - BASE, Inc.背景について
© - BASE, Inc.BASEの背景• サービスの成⻑によってトラフィックの量が増⼤していた• ⼈気ショップのセールによる瞬間的な⾼負荷が発⽣することもあったBASEが今後も安定して成⻑していくためにデータベースのスケーラビリティが⼤きな課題になってきた
© - BASE, Inc.それまでのR/W Splitting事情• CakePHP 公式で⽤意されている仕組みはない• リード専⽤ModelやBehaviorによって部分的に実現していたが、もっと汎⽤的なR/W Splittingライブラリが必要になってきたので作ることになった• ※コネヒトさんがCakePHP のR/W Splittingライブラリを公開する以前なので⾃作するしかなかった
© - BASE, Inc.実装⽅針を考える
© - BASE, Inc.主な関⼼事• アクセス先の明⽰的に切り替えを可能にする仕組みが欲しい• 既存の巨⼤なコードベースにどうシームレスに導⼊していくか• ⼤規模な切り替えをどう安全に実現していくか
© - BASE, Inc.ユースケースを想定して設計する• 既存コードに対するR/W Splittingの適⽤⽅法をある程度類型化して考えを整理する
© - BASE, Inc.ユースケースの想定
© - BASE, Inc.ユースケース1:スロークエリを狙い撃ちした部分適⽤• NewRelicなどのアプリケーション監視からボトルネックとなっているクエリを発⾒して、それだけをリードレプリカに向ける• クエリの実⾏負荷は特定のクエリに偏在しているので、最も費⽤対効果の⾼い適⽤⽅法
© - BASE, Inc.ユースケース2:コントローラアクション単位で適⽤• コントローラアクション単位でリードレプリカに向ける• 参照系コントローラアクションなど、参照クエリしか無いと分かっている箇所にまとめてリードレプリカに向ける
© - BASE, Inc.ユースケース3:アプリケーション単位で適⽤• アプリケーション単位で全てのDBアクセスをデフォルトではリードレプリカへ向けてしまうドラスティックな適⽤• 更新系クエリ全てに対して明⽰的にマスターへ向けてやる必要がある• 最も負荷分散の効果が⾼いが、更新系クエリの⾒逃しやレプリケーション遅延による影響が危惧される
© - BASE, Inc.3つの想定ユースケース• 後者のユースケースほど適⽤範囲が広くて適⽤が⼤変• 初期導⼊時に広範囲のコードを読む必要がある• 後の改修の影響を受けやすいリスクが有る最初は参照クエリだけだったが、後の改修で更新クエリが発⾏されるようになる可能性がある
© - BASE, Inc.考えたこと• 基本的にはスロークエリを狙い撃ちするアプローチになると思う• ただDBコネクション数を減らす効果は薄いので、広い範囲への適⽤はいずれ避けられないと考えていた
© - BASE, Inc.部分適⽤ではコネクション数は減らない参照クエリ参照クエリ参照クエリ参照クエリ参照クエリ参照クエリ参照クエリͱ͋ΔࢀরΫΤϦ͔͠ൃߦ͠ͳ͍ίϯτϩʔϥΞΫγϣϯ͕ݺΕͨ࣌マスター
© - BASE, Inc.部分適⽤ではコネクション数は減らない参照クエリ参照クエリ参照クエリ参照クエリ参照クエリ参照クエリ参照クエリͱ͋ΔࢀরΫΤϦ͔͠ൃߦ͠ͳ͍ίϯτϩʔϥΞΫγϣϯ͕ݺΕͨ࣌マスターマスターリードレプリカスロークエリなのでリードレプリカへ※DBコネクションは計2つ⽣成される
© - BASE, Inc.部分適⽤ではコネクション数は減らない参照クエリ参照クエリ参照クエリ参照クエリ参照クエリ参照クエリ参照クエリͱ͋ΔࢀরΫΤϦ͔͠ൃߦ͠ͳ͍ίϯτϩʔϥΞΫγϣϯ͕ݺΕͨ࣌リードレプリカ※理想的な状態はこっち、DBコネクションは1つ
© - BASE, Inc.安全装置の実装• リードレプリカに発⾏してほしくないクエリが実⾏されかけた場合に、ライブラリ側で検知して⾃動でマスターへ切り替える仕組み• リードレプリカに発⾏されてほしくないもの• 更新系クエリ• トランザクション• etc
© - BASE, Inc.安全装置の実装ModelSwitchableDatasourceBehaviorSwitchableMysql(DataSource)SwitchablePDOPDOPDOMasterReadReplicaReadReplicaModelίʔϧόοΫʹΑͬͯॻ͖ࠐΈɾআΛݕ(beforeSave/beforeDelete)τϥϯβΫγϣϯ։࢝Λݕߋ৽ܥΫΤϦΛਖ਼نදݱͰݕ
© - BASE, Inc.R/W Splittingの適⽤
© - BASE, Inc.適⽤してからしばらくは• 基本的にはスロークエリを狙い撃ちした部分適⽤だけが使われた• コントローラアクション単位の適⽤はごく⼀部で⾏われてきたがほとんど⾏われることはなかった
© - BASE, Inc.⼀度だけコネクション数が減らしたいタイミングがあった• マスターのコネクションキャパシティの上限が近づいてコネクション数を減らす必要が出てきた• アプリケーション単位での切り替え(デフォルトでリードレプリカに向けて、更新系クエリが投げられる箇所を明⽰的にマスターへ向ける)を実⾏した• ほとんど参照しか無いと分かっているアプリケーションだったので⼤丈夫だと判断された
© - BASE, Inc.ドラスティックな切り替えの⽅法• コードを全部調べ上げてやるのは量的に厳しい• ⾃動テストや⼿動テストで動作確認しつつ、漏れた部分は安全装置による⾃動切り替えに頼って切り替えを実⾏した
© - BASE, Inc.⼤規模切り替えの結果
© - BASE, Inc.⼤規模切り替えの結果• うまくいった ϦϦʔεલϚελʔ:ϦʔυϨϓϦΧͷίωΫγϣϯ͓͓Αͦ3:1ϦϦʔεޙ΄΅1:1ϚελʔͷίωΫγϣϯ1/2ۙ͘·ͰԼ͕ΓɺٯʹϦʔυϨϓϦΧ2ഒʹͳͬͨ
© - BASE, Inc.⼤規模切り替えの結果• サービス影響は出さずにコネクションを⼤幅に減らせた• 参照クエリの殆どがリードレプリカに向いたのでマスターの負荷も下がった• ただし、その裏側では安全装置が凄まじい回数起動していた• 安全装置によってサービス影響が抑えられていた
© - BASE, Inc.考察• ドラスティックな切り替えでも安全装置があれば案外なんとかなってしまった• ⼈間が頑張らない機械的なアプローチでもいくつか条件が重なればこういうアプローチもありうることが分かった※レプリケーション遅延による更新の反映されていない参照が発⽣するリスクは潜在的にあるが、Auroraはレプリケーション遅延が発⽣しづらいらしいのでそこで抑えられているのかもしれない
© - BASE, Inc.まとめ• 既存のコードベースに後からR/W Splittingを導⼊していく際に考えたことを共有• 基本的にはスロークエリを狙い撃ちした部分適⽤で良さそうだが、コネクション数の削減を⽬指すと⼤規模な導⼊は避けられない• ⼤規模な導⼊をする際は切り替えを⾃動化する仕組みがあれば⼈間が頑張らずうまくいくケースがある
© - BASE, Inc.ご清聴ありがとうございました