19日目: 勢いでN+1問題対応入れたけど今は不要だった
初めてのGraphQL ―Webサービスを作って学ぶ新世代API
- 作者:Eve Porcello,Alex Banks
- 発売日: 2019/11/13
- メディア: 単行本(ソフトカバー)
GraphQLの怖いところN+1
前回は一つのクエリが重くなることに対する負荷対策を入れた。(実際問題としてできているかは微妙だけど)
今回は、GraphQLで陥りがちなデータベースアクセスのN+1問題について対策する。 N+1問題は、配列の要素で入れ子になった項目を再帰的に取得しにいってしまうためにデータベースに高頻度のアクセスが発生してしまう問題。
これについても対策する機能は用意されている。それがこちら。
コレを使うことで、都度DBアクセスをするのでなく、ある程度まとめて取得しに行くことを実現できる。 で、早速導入をしてみたんだけど、結果的には現時点ではあまり効力を発揮しなさそう。どちらかというと前後の記事を取得するところで必要そうだけど、あちらはちょっと複雑なクエリなので導入を見送り。
導入の仕方
防備録としてもメモしておく。
N+1対策したい対象に対して以下のようにDataLoaderの生成を定義する。もともと配列を返す箇所についてはこちらも同様に配列をしている。intはIDがint型であるため。IDが文字列型ならstringを指定。
//go:generate go run github.com/vektah/dataloaden ArticleLoader int *github.com/hiroyky/legato/domain/dbmodel.Article //go:generate go run github.com/vektah/dataloaden ArticleSliceLoader int []*github.com/hiroyky/legato/domain/dbmodel.Article
生成
$ go generate ./ $ go generate ./...
生成されたDataLoaderを使って呼び出しを行う。
詳細は本日のプルリクで。
18日目:重いGraphQLのクエリを制限する機構を導入
初めてのGraphQL ―Webサービスを作って学ぶ新世代API
- 作者:Eve Porcello,Alex Banks
- 発売日: 2019/11/13
- メディア: 単行本(ソフトカバー)
GraphQLの1クエリは重くできる
GraphQL APIってREST APIと違ってクライント側の裁量が大きいAPIである。REST APIはサーバ側がレスポンス内容を指定するのに対して、GraphQLはクライント側が内容を指定するから。そして、一つのクエリをとても重くすこともできてしまう。
クエリはたとえ1つでもデータベースのあらゆる関連テーブルを走査して、大きな負担をかけてしまう可能性も十分ありえる。
そこで今回は、重いGraphQLクエリを制限する機能を付ける。
Complexity
使っているGraphQLライブラリgqlgenはありがたいことにクエリの重さを算出して、合計値が閾値以上だったらリクエストをキャンセルする機能を持っている。公式では以下のように解説されている。
各種項目について“重さ”を計算させる関数を指定して、その合計値でクエリの重さを比較する感じ。
プルリク
というわけで本日のプルリク。まぁいったんはViewer向けのみで良いでしょw
17日目:日付順でソート
16日目: ページネーションをフロント側にも実装
前回はGraphQL側での改修を行ったので今回はフロントエンドの実装。次のページ・前のページへの遷移を実装した。
というわけで今回のプルリク。 github.com
15日目:前後の記事を取得できるようにGraphQLを拡張する
14日目: Apollo GraphQL Client(vue用)で記事の読み込み
GraphQLのクライアントの作成
GraphQLのクライアントをどうしようかと思ったけど、まずはオーソドックスにApollo Clientを利用することにした。そしてこのVue向けであるこちらを導入。
概ねTypeSciriptにも対応しているようで一安心。 Vueファイルに直接クエリを指定するわけなんだね。
通信部分と表示部分のコードを厳密に分けるのが好みなので、ちょっと違和感あるけどまずはこのまま進める。 毎回画面表示時には必要な項目はサーバからGraphQLで読み込むようにして、Store(vuex)は無しにした方が良いかなぁ。あんまりフロントエンドで状態を持つべきじゃ無いかも、今回は。
というわけで、今日のプルリク。今後もVue apolloを導入するときの参考にしよう。