クライアント側で気にすべき点
Dataloaderを使う
自分の環境では一番有効だった手段。
Dataloader
導入には以下の手順を踏む。
- batching用の関数(keyのリストを受け取ってvalueのリストを返す)を定義してあげる。
// この例ではkeyはaddressというstring, valueはany (LocationというGraphQL型が入っている)
type BatchLocation = (addresses: string[]) => Promise<any[]>
const batchLocations: BatchLocation = async addresses => {
const locations = await locationBinding.query.locations({ where: {address_in: addresses}}) //ここは適宜変えてください。
const locationMap: { [key: string]: any } = {}
// return locations.
locations.forEach(element => {
locationMap[element.address] = element;
});
return addresses.map(address => locationMap[address])
}
const batchLoader = new DataLoader<string, any>(batchLocations);
- resolverの中で上記batch用関数を呼ぶ
location: {
resolve: async (parent: any, args: any, context: any, info: any) => {
let location = await batchLoader.load(<string>parent.address) //ここ
return location
}
}
参考動画。
https://www.youtube.com/watch?v=_FQ1ZEWIn2s
apollo-linkは何を使う?
こんなに種類が。。。
- 生のHttpLink(link1)
- 生のHttpLinkで重複排除だけしてみる(link2)
- ちょっと凝ってBatchHttpLinkを使ってさらに重複排除してみる(link3)
- HTTPLinkDataloaderを使う(link4)
import { HttpLink } from 'apollo-link-http'
import { BatchHttpLink } from 'apollo-link-batch-http'
import { HTTPLinkDataloader } from 'http-link-dataloader' // not applicable
import { DedupLink } from 'apollo-link-dedup'
import fetch from 'node-fetch'
const link1 = new HttpLink({uri, fetch})
const link2 = new DedupLink().concat(new HttpLink({uri, fetch}))
const link3 = new DedupLink().concat(new BatchHttpLink({uri, fetch}))
const link4 = new HTTPLinkDataloader({uri})
基本的なふるまいの傾向です。
- BatchHttpLinkは、HttpLinkに比べ、レイテンシが劣化、スループットは向上
- DedupLinkは、重複が多そうなときに効果ありそう
- HTTPLinkDataloaderは効果がよく分からない(というかまともに動かない。。。)
ほかにもこんな手が。
- apollo-link-stateを使う
参考
https://www.youtube.com/watch?v=_FQ1ZEWIn2s
https://github.com/facebook/dataloader
https://medium.com/slite/avoiding-n-1-requests-in-graphql-including-within-subscriptions-f9d7867a257d
https://medium.com/@gajus/using-dataloader-to-batch-requests-c345f4b23433
サーバ側で気にすべき点
- キャッシュを使う