Copyright© M&Aクラウド
Repositoryパターンを維持しながら
N+1問題を起こさないようにする方法論
PHP Conference 2021
@yamotuki
Copyright© M&Aクラウド
今日の話題: レスポンス速度と設計の話
2
Copyright© M&Aクラウド 3
レスポンス速度について
重いサイトはユーザーが離れる
● 直帰率の上昇
○ 「2秒以内に読み込まれるページの平均直帰率は
9%」
○ 「5秒以内に読み込まれるページの直帰率は
38%に急上昇」
● コンバージョン低下やSEOへの影響など他多数
「Website Load Time Statistics: Why Speed Matters in 2021」, https://www.websitebuilderexpert.com/building-websites/website-load-time-statistics/
Copyright© M&Aクラウド
レスポンス速度について
4
速度に関する指標
● TTFB
● StartRender
● Visual Complete
● Speed Index
● onLoad
● Fully Loaded
「Here’s What We Learned About Page Speed」, https://backlinko.com/page-speed-stats
Copyright© M&Aクラウド
レスポンス速度について
5
速度に関する指標
● TTFB => 今回はこれを見るところ
● StartRender
● Visual Complete
● Speed Index
● onLoad
● Fully Loaded
「Here’s What We Learned About Page Speed」, https://backlinko.com/page-speed-stats
Copyright© M&Aクラウド
レスポンス速度について
6
TTFB(Time To First Byte)
● サーバから最初のバイトがブラウザに到達するまでの時間
● 要するに、以下の要素の合計
○ ネットワーク的距離
■ ユーザの近くにサーバを置く
○ サーバにおける処理時間
■ PHPのコードの改善
Copyright© M&Aクラウド
レスポンス速度について
7
極限まで早くしたいか?
エンジニアとしては追い求めたい
Copyright© M&Aクラウド
レスポンス速度について
8
ビジネス視点
● ユーザに提供するのは速度だけではない
● 使いやすい機能を開発する時間も大事
● サイト速度は大事だが、工数をかけすぎてはいけない
● 速度改善で今後の機能提供がしづらくなるのも
NG
Copyright© M&Aクラウド
今日使う例について
9
Copyright© M&Aクラウド
今回の例
10
管理画面における一覧の例
ユーザ情報だけの一覧
Copyright© M&Aクラウド
今回の例
11
内部的な既存実装の前提①
UserRepository を通して User Entity の List を取得
Infra/UserRepository@getList()
UserRepository@getList()
UserQueryService
Infra Repository Implementation
Domain Repository Interface
Application Layer
Copyright© M&Aクラウド
今回の例
12
こういう管理画面を表示させたい
もともと時計の列は無くて、今回機能追加したい
Copyright© M&Aクラウド
作りたい Data Transfer Object(以下DTO)
13
Copyright© M&Aクラウド
今回の例
14
内部的な既存実装の前提②
● Watch も独立した Entity として存在する
● Watch の中に所有者情報として一つのUser Id
● 簡略化のための前提
○ 所有者は1人とする
○ 1人1個とする
Copyright© M&Aクラウド
今回の例 - 愚直にやったパターン
15
● Repositoryは対象のEntityまたはそのリストしか返せないという制約があるとする
● DTOを作るのに foreach を回すので N+1 回のSQL発行
UserRepository@getList() WatchRepository@get(): Watch
UserQueryService
① User Entity List取得
② foreach で Watch Entity を1個ずつN回取得
Domain Repository Interface
Infra/UserRepository@getList()
Infra Repository Implementation
WatchRepository@get()
Copyright© M&Aクラウド
今回の例 - 愚直にやったパターン
16
N+1問題の何が悪いのか?
● SQL実行が1個 0.02sで完了するとしても
● 300回直列で実行したら6秒かかる
● TTFB
○ サーバ処理
■ SQL実行 => ここだけで6秒
■ その他PHP処理
○ ネットワーク通信
Copyright© M&Aクラウド
改善方法
17
改修方法案
1. キャッシュ
2. ページネーション
3. Command Query Separation
4. Hash Map Attachment法(New!)
Copyright© M&Aクラウド
改善案1. キャッシュを使う
18
Copyright© M&Aクラウド
1. キャッシュ
19
DBの前段に memcached などキャッシュを差し込む
UserRepository@getList() WatchRepository@get()
UserQueryService
① User Entity List 取得
② foreach で Watch Entity を1個ずつN回取得
Domain Repository Interface
Infra/UserRepository@getList()
Infra Repository Implementation
WatchRepository@get()
CachedWatchRepository@get()
設計への影響: 低
Copyright© M&Aクラウド
1. キャッシュ
20
● 実はあんまり解決になってないかも(
SQL実行が重いケースを除く)
● AWS でのあるネットワーク条件下での例
○ backサーバからmemcachedに接続速度を計測
● time_total は 0.016s
● これが300回直列で叩かれるとそれだけで4.8s になる
● キャッシュもDBもネットワーク上に存在するなら、いくら
memcachedやredisが早くても無意味
curl でDBやキャッシュに接続 , https://qiita.com/yamotuki/items/2d1c74c3253e9c3b0562
CURLでWEBサイトのパフォーマンス測定 , https://sites.google.com/site/kanta01web/techmemo-2/curldewebsaitonopafomansuceding
Copyright© M&Aクラウド
改善案2. ページネーションを入れる
21
Copyright© M&Aクラウド
2. ページネーション
22
● N + 1のNを減らしてしまおうという発想
● 1ページに表示する件数をN=100件までなど制限する
● メリット
○ TTFBの改善効果「中」& 設計への影響「中」
○ ブラウザレンダリングの軽量化に効果が高い(本発表趣旨からややズレる)
● デメリット:
○ 仕様として一覧性が重要なケースだと使いづらい
○ Ctrl + F でのページ内検索が使えなくなる
○ 検索機能を追加したり工数がかかることも
Copyright© M&Aクラウド
改善案3. Command Query Separation
23
Copyright© M&Aクラウド
3. Command Query Separation
24
Infra/UserRepository@getList()
UserRepository@getList()
UserQueryService UserPort@getDTOList()
Infra
Domain
Application Layer
UserAdapter@getDTOList()
最初からDTOの形で取得
Infra層で join などしてDTOに直接入れる
注記: 本発表の本題からズレるので、
CQSとCQRSについての詳細議論はしません。
● こちらなど参照: https://qiita.com/hirodragon/items/6281df80661401f48731
Copyright© M&Aクラウド
3. Command Query Separation
25
● メリット
○ TTFBへの効果「大」
○ N+1の解決策にはなっている
● デメリット
○ 設計への影響「大」。既存の設計と食い違う
○ 取得が Repository と Port&Adapter で2箇所に散らばる
● コードを書くときの辛さ
○ 今までのEntityを使ったコードを使いまわせないので大変
○ フィールドの多いDTOを組み上げる処理を書くだけで日が暮れる
● コードを拡張するときの辛さ
○ DBのフィールドを変更したときに忘れずに
2箇所直さないといけないので大変
Copyright© M&Aクラウド
3. Command Query Separation
26
● すでにRepositoryパターンが入っているアプリケーションにおいてという前提で、できれば導
入しない方が望ましい
● 弊社では過去に一部導入を試してみたが、辛いのでそれ以降はどうしても必要なパターン以
外は導入しないようにしている
Copyright© M&Aクラウド
基本に立ち返る
27
設計の目的ってなんだっけ?
● 目的
○ 機能を追加したり削除するのが簡単に行えるようにすること
● 誰のため?
○ ユーザのため: より良い機能を素早く提供する
○ 開発者のため: 機能を追加するのに辛い気持ちにならないこと
Copyright© M&Aクラウド
基本に立ち返る
28
具体的にどういう手法だったら良い?
● 一つの意図の改修をするのに処理が散らばっていないこと
○ いわゆる「凝集度が高い」状態
● 速度改善の目的を達成するために不必要な複雑性を持ち込みたくない
○ 既存の設計をできるだけ変えないことで保守コストを抑えたい
○ 簡単に導入できて高い効果を得たい
Copyright© M&Aクラウド
改善案4: Hash Map Attachment 法
(独自命名)
29
Copyright© M&Aクラウド
4. Hash Map Attachment法
30
何が問題だったんだっけ?
UserRepository@getList() WatchRepository@get(): Watch
UserQueryService
① User Entity List 取得 ② foreach で Watch Entity を1個ずつN回取得
Domain
Application Layer
Copyright© M&Aクラウド
4. Hash Map Attachment法
31
UserRepository@getList() WatchRepository@getList(): WatchList
UserQueryService
① User Entity List取得
② Watch List を1回だけ取得
Domain
get がN回走るからよくないので、予め getList で取得しちゃおう
Copyright© M&Aクラウド
4. Hash Map Attachment法
32
● 新たに出る問題点
○ Watchリスト内を array_search(O(n))で探すとする
○ User List のN回のループの中で、array_searchをやるので、O(n^2)になる
○ 仮に N+1 問題を解決できたとしても以下の計算量
■ 1000件の2重ループは 10^6
● (多分)ここら辺までは1秒以内に収まることも多い
■ 10000件とかは現実的な応答速度に収まるか未知
これだけでいいのか?
「プログラミングコンテスト攻略のためのアルゴリズムとデータ構造」
,
https://www.amazon.co.jp/dp/B00U5MVXZO/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1&asin=B00U5MVXZO&revisionId=&format=4&depth=1
Copyright© M&Aクラウド
4. Hash Map Attachment法
33
● Hash Map からの get は O(1)で高速
● あらかじめ Watch List を Hash Map に変換(PHPでは key value array)
○ key が User Id
○ value が Watch Entity
● User List ループ(O(n))で対応する Watch を Hash Map 経由で取得(O(1))
○ ループ回してもO(n)の計算量になる
「みんなのデータ構造」
, https://www.amazon.co.jp/gp/product/4908686068/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1
Hash Map を使おう
Copyright© M&Aクラウド
コード例
34
Copyright© M&Aクラウド
終わりに
35
Hash Map Attachment法という命名について
● Hash Map を元のリストにくっつける(Attachment)する
● 社内の啓蒙のために私がつけた名前なのでググっても他の記事は出ません
○ 詳細はこちら https://tech.macloud.jp/entry/2021/03/24/154426
● 近い発想は Laravel Eloquent の eager loading (with関数)で使われてます
● 適用レイヤが違うので便宜的に違う名前をつけました
Copyright© M&Aクラウド
終わりに
36
● アプリケーションをキメラ化させない
○ 銀の弾丸はない
○ 今あるアプリケーションや状況にあわせた、
ROIの高い設計を導入しましょう
● Hash Map Attachment 法も全てのアプリケーションで推奨するものではありません
● 設計の目的を忘れてはならない
○ ユーザのため
○ 開発者のため
振り返り
Copyright© M&Aクラウド 37
● 採用してます
○ https://www.wantedly.com/projects/513494
● Twitter
○ https://twitter.com/yamotuki
Copyright© M&Aクラウド 38
フィードバックお願いします!
https://joind.in/event/php-conference-japan-2021

More Related Content

PDF
WebRTCの技術解説 公開版
PPTX
WPF MVVM Review
PDF
ネットワーク運用自動化の実際〜現場で使われているツールを調査してみた〜
PPTX
設計・構築においてのドキュメントの重要性について
PDF
なぜネットワーク運用自動化が進まないのか Whitebox switch編
PDF
分散ワークフローエンジン『Digdag』の実装 at Tokyo RubyKaigi #11
PPTX
Kof2017 シラサギ導入
PDF
MaxScaleを触ってみた
WebRTCの技術解説 公開版
WPF MVVM Review
ネットワーク運用自動化の実際〜現場で使われているツールを調査してみた〜
設計・構築においてのドキュメントの重要性について
なぜネットワーク運用自動化が進まないのか Whitebox switch編
分散ワークフローエンジン『Digdag』の実装 at Tokyo RubyKaigi #11
Kof2017 シラサギ導入
MaxScaleを触ってみた

What's hot (20)

PDF
iPhoneでリアルタイムマルチプレイを実現!Photon Network Engine
PPTX
今から始めるWebClient(JSUG勉強会 2020年その6 LT大会)
PDF
ソフトウェアでのパケット処理あれこれ〜何故我々はロードバランサを自作するに至ったのか〜
PDF
実践!OpenTelemetry と OSS を使った Observability 基盤の構築(CloudNative Days Tokyo 2022 発...
PDF
實踐 Clean Architecture(實作高可用性的軟件架構)
PDF
バイトコードって言葉をよく目にするけど一体何なんだろう?(JJUG CCC 2022 Spring 発表資料)
PDF
レガシーコードの複雑さに立ち向かう~ドメイン駆動設計のアプローチ
PDF
.NET 7期待の新機能
PDF
[Cloud OnAir] Google Cloud で実践するマイクロサービスアーキテクチャ 2019年2月21日 放送
PPTX
Mongo dbを知ろう
PDF
PostgreSQL Unconference #5 ICU Collation
PDF
Accelerate SDN/NFV Network ~ネットワーク高速化のアレコレ~ - OpenStack最新情報セミナー 2016年3月
PDF
SMTPのSTARTTLSにおけるTLSバージョンについて
PDF
「スキルなし・実績なし」 32歳窓際エンジニアがシリコンバレーで働くようになるまで
PDF
オススメの標準・準標準パッケージ20選
PDF
「GraphDB徹底入門」〜構造や仕組み理解から使いどころ・種々のGraphDBの比較まで幅広く〜
PDF
3週連続DDDその2 深いモデルの探求(ドメイン駆動設計 第3部)
PDF
Nutanix Community Edition 5.18 徹底解説
PDF
Mercari JPのモノリスサービスをKubernetesに移行した話 PHP Conference 2022 9/24
PDF
世界と日本のDNSSEC
 
iPhoneでリアルタイムマルチプレイを実現!Photon Network Engine
今から始めるWebClient(JSUG勉強会 2020年その6 LT大会)
ソフトウェアでのパケット処理あれこれ〜何故我々はロードバランサを自作するに至ったのか〜
実践!OpenTelemetry と OSS を使った Observability 基盤の構築(CloudNative Days Tokyo 2022 発...
實踐 Clean Architecture(實作高可用性的軟件架構)
バイトコードって言葉をよく目にするけど一体何なんだろう?(JJUG CCC 2022 Spring 発表資料)
レガシーコードの複雑さに立ち向かう~ドメイン駆動設計のアプローチ
.NET 7期待の新機能
[Cloud OnAir] Google Cloud で実践するマイクロサービスアーキテクチャ 2019年2月21日 放送
Mongo dbを知ろう
PostgreSQL Unconference #5 ICU Collation
Accelerate SDN/NFV Network ~ネットワーク高速化のアレコレ~ - OpenStack最新情報セミナー 2016年3月
SMTPのSTARTTLSにおけるTLSバージョンについて
「スキルなし・実績なし」 32歳窓際エンジニアがシリコンバレーで働くようになるまで
オススメの標準・準標準パッケージ20選
「GraphDB徹底入門」〜構造や仕組み理解から使いどころ・種々のGraphDBの比較まで幅広く〜
3週連続DDDその2 深いモデルの探求(ドメイン駆動設計 第3部)
Nutanix Community Edition 5.18 徹底解説
Mercari JPのモノリスサービスをKubernetesに移行した話 PHP Conference 2022 9/24
世界と日本のDNSSEC
 
Ad

Similar to repositoryパターンを維持しながら n+1問題を起こさないようにする方法論 (20)

PDF
BPStudy20121221
PDF
Mvc conf session_4_ono
PPTX
20110607
PPTX
初心者向け負荷軽減のはなし
PDF
eZ Publish 2012年4月勉強会 - eZ Publish設計ベストプラクティス
PDF
Nds#24 単体テスト
PDF
オフラインWebアプリの再到来で今、再び注目されるAPIの本命 ーJavaScript SQL-like database
PDF
Hadoopによるリクルートでの技術調査とその活用
PPTX
コーディング不要! Entity Framework 6.1.3 + ASP.NET MVC 5 サンプル アプリケーション構築 手順書
PPTX
20080213
PDF
Webアプリを並行開発する際のマイグレーション戦略
PDF
XAML と C# を使った Windows ストアアプリ(LOB)構築のためのtips Prism 4.5 & Kona project 等のご紹介
PDF
GCP本格採用で遭遇した課題とマイクロサービス的解決
PDF
Google cloudinside3
PDF
eZ Publish勉強会2013年3月「eZ Publishの構築を簡単に!」
PDF
Daisukei vsug ef
PDF
ADO.NETとORMとMicro-ORM -dapper dot netを使ってみた
PDF
Web技術勉強会 20100925
PDF
eZ Publish 2012年5月勉強会 - サイトアクセス
PPTX
Spring I/O 2015 報告
BPStudy20121221
Mvc conf session_4_ono
20110607
初心者向け負荷軽減のはなし
eZ Publish 2012年4月勉強会 - eZ Publish設計ベストプラクティス
Nds#24 単体テスト
オフラインWebアプリの再到来で今、再び注目されるAPIの本命 ーJavaScript SQL-like database
Hadoopによるリクルートでの技術調査とその活用
コーディング不要! Entity Framework 6.1.3 + ASP.NET MVC 5 サンプル アプリケーション構築 手順書
20080213
Webアプリを並行開発する際のマイグレーション戦略
XAML と C# を使った Windows ストアアプリ(LOB)構築のためのtips Prism 4.5 & Kona project 等のご紹介
GCP本格採用で遭遇した課題とマイクロサービス的解決
Google cloudinside3
eZ Publish勉強会2013年3月「eZ Publishの構築を簡単に!」
Daisukei vsug ef
ADO.NETとORMとMicro-ORM -dapper dot netを使ってみた
Web技術勉強会 20100925
eZ Publish 2012年5月勉強会 - サイトアクセス
Spring I/O 2015 報告
Ad

repositoryパターンを維持しながら n+1問題を起こさないようにする方法論