GraphQLサーバを作る苦しみと解決手法

B5582ce2d9959dfcff0384a07003e188?s=47 mackee
July 21, 2020

 GraphQLサーバを作る苦しみと解決手法

B5582ce2d9959dfcff0384a07003e188?s=128

mackee

July 21, 2020
Tweet

Transcript

  1. GraphQLαʔόΛ࡞Δۤ͠Έ ͱղܾख๏ @mackee_w a.k.a macopy 2020-07-21 ٢঵ࣉ.pm23

  2. ࿩͢͜ͱ • ΋ͱ΋ͱGraphQLʹջٙతͩͬͨਓ͕ • GraphQL͕͢Ͱʹ࢖ΘΕ͍ͯΔϓϩδΣΫτͰͪΐͬͱۤ͠Έ • ࡞Γ௚ͧ͢ʂͱͳͬͨͱ͖ʹ·ͨGraphQLΛ࢖͏ཧ༝

  3. macopy *ʮ ߏ଄ମҠ͠ସ͑ۀʯ * WebΞϓϦέʔγϣϯΤϯδχΞ * ୲౰͸αʔόαΠυ(Perl/Go) * Ϛελσʔλ؅ཧ͕ಘҙͰ͕͢࠷ ۙ͸ͦ͏͍͏࢓ࣄ͕͋Γ·ͤΜ

  4. ࠷ۙͷ͓࢓ࣄ

  5. ࠓ೔ͷओ୊ GraphQL

  6. ΋͔ͯ͠͠٢঵ ࣉpmʹGraphQL ͷ೾͕དྷ͍ͯ Δʁʁʁ

  7. GraphQL͓͞Β͍ • Web޲͚ΫΤϦݴޠ • ಉ͡໾ׂΛ͢Δ΋ͷ: OpenAPI, gRPC, JSON-RPC… • GitHubͳͲͷWeb

    APIͰ࠾༻ྫ͋Γ • `/graphql`Έ͍ͨͳ୯ҰͷΤϯυϙΠϯτʹΫΤϦΛ౤͛Δ • Ϩεϙϯε͸JSON͕Α͘࢖ΘΕΔ(͕ɺผʹԿͰ΋ྑ͍͸ͣ)
  8. GraphQLΛ࢖͏ͱ͖ͷྲྀΕ εΩʔϚ ΫΤϦ ม਺ Ϩεϙϯε POST /graphql

  9. GraphQLɺԿ͕͏Ε͍͠ͷʁ • ܕ͕͋ͬͯૉ੖Β͍͠ • ܕ໊ʹ`!`͕ͭ͘ͱnot nullable • ඞཁͳfieldͷߜΓࠐΈ΍ɺҰॹʹऔΓ͍ͨϦιʔεͷҰׅऔಘ΋Ͱ͖Δ • ࣹӨ΍batch

    requestΈ͍ͨͳ࢓૊ΈΛ࡞Γࠐ·ͣʹࡁΉ • पลπʔϧ/ϥΠϒϥϦ͕͍ͬͺ͍͋ͬͯૉ੖Β͍͠ • GraphiQL, apollo-client/apollo-server ͳͲͳͲ
  10. ͜ͷ”͏Ε͍͠”͸ ୭ͷࢹ఺͔ʁ

  11. αʔό(Perl)୲౰ͷࢲࢹ఺ͰݟΔͱ

  12. GraphQLɺԿ͕͏Ε͍͠ͷʁ • ܕ͕͋ͬͯૉ੖Β͍͠ • ܕ໊ʹ`!`͕ͭ͘ͱnot nullable • ඞཁͳfieldͷߜΓࠐΈ΍ɺҰॹʹऔΓ͍ͨϦιʔεͷҰׅऔಘ΋Ͱ͖Δ • ࣹӨ΍batch

    requestΈ͍ͨͳ࢓૊ΈΛ࡞Γࠐ·ͣʹࡁΉ • पลπʔϧ/ϥΠϒϥϦ͕͍ͬͺ͍͋ͬͯૉ੖Β͍͠ • GraphiQL, apollo-client/apollo-server ͳͲͳͲ ←ͤ΍ͳͰ΋αʔόɺPerl΍ͶΜ… ɹundefେ׻ܴ΍ͶΜ… ↑͑ɺͭ·Γൃߦ͞ΕΔSQL͕ݻఆͰ͖ͳ͍ʁʁ ɹࠔΔͷͰ͸ʁʁʁ ↑ͦΕPerlʹ͋Δͷʁʁʁʁʁ
  13. GraphQLΛຊ֨తʹ࢖͏લ·Ͱͷҹ৅(1) • ΫϥΠΞϯτଆͷૢ࡞ͰσʔλͷऔΓग़͠ํ͕ಈతʹมΘΓ͏Δͷ͸ड ͚ೖΕ͕͍ͨ • ύϑΥʔϚϯενϡʔχϯά͕͔ͳΓ೉͍͠ • RESTful APIʹൺ΂ͯGraphQLͰN+1ͷղܾ͕೉͍͠࿩͸͕͜͜ΩϞ ͩͱࢥΘΕΔ

    • RESTful APIͰฦ͢σʔλͷܗ͕ҰఆͩͱܾΊଧͪνϡʔχϯάͰ͖ Δ GraphQL͸ͦΕ͕ग़དྷͳ͍
  14. GraphQLΛຊ֨తʹ࢖͏લ·Ͱͷҹ৅(2) • GitHub API v4(GraphQL)͕ग़ͨͱ͖ʹΘʔ͍ͱ৮ͬͯΈͨͱ͖ͷײ૝ • GraphQLݴޠΛ֮͑Δͷ͕೉ղ(ʹݟ͑ͨ) • ୯ͳΔJSONͷ೿ੜͰ͸ͳ͍ಠࣗDSL •

    ͪΐͬͱෳࡶͰωετ͕ਂͯ͘ྔ͕ଟ͍ΫΤϦΛൃߦ͢Δͱ500͕ฦ͖ͬͯͨ • ʮGitHubͰ͢Β͜͏ͳΔΜ͔ͩΒզʑʹ͸…ʯ • ͨͿΜࠓ͸ComplexityΛܭࢉͯ͠200Ͱฦͤͳ͍Αͱݴͬͯ͘ΔͷͰ͸ͳ͍͔
  15. ๻͕ٕज़બ୒͢ΔͳΒબ͹ͳ͍ͩΖ͏…

  16. ԑ͕ͳ͍ͱࢥ͍͕ͬͯͨɺ͔͠͠…

  17. ࠓ೥಄ʹҟಈͨ͠ ςʔϚʮࠓ೥ͷલ൒ͷ׆ಈΛৼΓฦΔʯ

  18. ҟಈ௚ޙͷձ࿩ • ʮͳΜ͔͜ͷϖʔδදࣔ͞ΕΔ·Ͱॏ͍͠ɺαʔό΋͘͢͝CPU৯͏ ΜͰ͢ΑͶʯ • ๻ʮͲΕͲΕݟͯΈΔ͔…͋͋׳Ε਌͠ΜͩPerlͩ…ʯ •ʮ͸ͬɺGraphQLͩ…ʯ

  19. ॏ͍ϖʔδΛνϡʔχϯά͢Δ • ͜ͷ࣌఺Ͱ͸Կ͕ݪҼ͔͸Θ͔Βͳ͍ • GraphQLͰ͸ͳ͘ɺΞϓϦέʔγϣϯϩδοΫͷํʹݪҼ͕͋Δ͔΋ • WebΞϓϦαʔόͷCPUΛ৯͏࣌఺ͰDBͰ͸ͳ͍ • …͔͜͠͠ͷ୊ࡐͷൃදͰ͜͜ʹॻ࣌͘఺ͰΦν͕ݟ͍͑ͯΔ •

    ͳʹ͸ͱ΋͋ΕͦͷϖʔδͰୟ͔Ε͍ͯΔAPIΛൈ͖ग़ͯ͠ϑϨʔϜάϥ ϑΛग़ͧ͢
  20. Devel::NYTProfͷ݁Ռ • ԣ͕࣠࣌ؒͰॎ͕ίʔϧελοΫ • ͖Ε͍ͳϏϧ͕ݐͬͨ • ΞϓϦέʔγϣϯϩδοΫ͸੺ ؙ͍ͷ෦෼ • Ϗϧ͕ݐͬͯΔͷ͸Resolverͱݺ

    ͹ΕΔfieldΛղܾ͢ΔϝιουΛ ࠶ؼతʹ୳͍ͯ͠Δ෦෼
  21. PerlͷGraphQL.pm • ࠷ઌ୺ͷϞμϯPerl • Function::Parameters • Return::Type • ܕ͕ΨνΨνʹॻ͔Ε͍ͯΔ •

    ͔͠͠Perl͸ಈతܕ෇͚ݴޠͳͷͰಈతʹ ܕνΣοΫ͠·͢ • ↑͕͜͜ϘτϧωοΫʹͳΔ • ܕνΣοΫΛແޮԽ͢ΔΑ͏ʹ Function::ParametersΛ͍͡ΔͱΫΤϦ୯Ґ Ͱݟͯ3ഒߴ଎Խ͞Εͨ
  22. GraphQL APIͷߴ଎ԽͷҊ • GraphQL.pm͓ΑͼFunction::ParametersΛ͍ͬͯ͡Pull RequestΛग़͢ • ܕνΣοΫແޮԽ͸ຊମΛ͍͡Δ͔͠ແ͍ • ͕ɺ͜ͷPull Request͕Authorʹཧղ͞ΕΔࣗ৴͕ͳ͍…͋ͱͬ͞͞ͱղܾ͍ͨ͠

    • Ωϟογϡ͢Δ • GraphQLͰ࢖ΘΕΔresolver΍Ϧιʔε୯ҐͷΩϟογϡͰ͸ແҙຯ • GraphQLΛύʔεͨ࣌͠఺Ͱෛ͚͕֬ఆ͍ͯ͠Δ • GraphQLΛGraphQL.pmͰύʔε͢ΔલʹϨεϙϯεΩϟογϡΛฦ͢ => ࠾༻
  23. GraphQL͸Ωϟογϡ͕ࠔ೉ͱ͍͏ᷚ • ΤϯυϙΠϯτ͸1Օॴ, ΫΤϦ͸bodyʹ٧ΊΒΕ͍ͯΔͷͰ… • query stringʹΫΤϦΛೖΕͯϨεϙϯεΩϟογϡ͢Δख๏ͳͲ ΋͋ΔΒ͍͠ • nginxͰ͸ͳ͘Perlʹདྷ͔ͯΒΩϟογϡ͢Δ͜ͱʹ͠ɺBody͸ಡΉ

    • ͔͠͠BodyΛGraphQLͱͯ͠ಡΉͱෛ͚ͳͷͰGraphQLͱͯ͠ಡ ·ͳ͍
  24. ΫΤϦΛϋογϡԽͨ͠΋ͷΛredisͰ ϨεϙϯεΩϟογϡ ※ηογϣϯͳͲߟྀ͢Δͱ͔,$variables΋normalize͢ΔͳͲ΋͏গ͠޻෉͕ඞཁ

  25. CPUͷεύΠΫ͕؇࿨͞Εͯ ΊͰͨ͠ΊͰͨ͠

  26. ୈೋষ ͜ͷମݧΛͨ͠ਓ͕ؒ શ෦࡞Γ௚͠Λ΍Δͱ͖ʹ ·ͨGraphQLΛબ΂Δ͔

  27. શ෦࡞Γ௚͠ͷܦҢ • ͜ͷGraphQLΛ࢖͍ͬͯΔ෦෼͸ɺͦΕൈ͖ʹͯ͠΋͔ͳΓࠐΈೖͬ ͨϩδοΫ͕ೖ͍ͬͯΔ • νʔϜ಺Ͱ΋ཧղͰ͖͍ͯΔਓ͕গͳ͍ • ͔͠͠αʔϏεͷ֩ͷ෦෼ͳͷͰ࢓༷มߋ΍ػೳ௥ՃΛόϯόϯೖΕ ͍ͨ •

    ͔ͳΓͰ͔͍ػೳ௥ՃΛ͍ͨ͠ => ࡞Γ௚͔͢…
  28. ࡞Γ௚͍ͭ͢ͰʹGraphQLΛ˓˓͍ͨ͠ • ݱঢ়ͷ࢓૊Έ͸ෳࡶͳGraphQLΫΤϦΛॻ͘ͱWebαʔό͕ॏ͘ͳΔ ಛੑ • ΩϟογϡͰ͖Δͷ΋ඇϩάΠϯϢʔβͰϦΞϧλΠϜੑ͕ແ͍಺༰ͩ ͚Ͱݶք͕͋Δ • ͦ΋ͦ΋GraphQLΛ˓˓ͯ͠ղܾ͍ͨ͠ •

    ◦◦ʹ͸ʮ΍ΊΔʯͱ͔ʮҡ࣋ͨ͠··࢓૊ΈΛม͑Δʯͱ͔ͦͷ΁ Μ͕ೖΓ·͢
  29. ࡞Γ௚͢ଞͷཁҼ • ύϑΥʔϚϯεཁ͕݅ଞͷ෦෼ͱҧ͏ • ि຤ͳͲʹਓ͕ϫοͱདྷͨΒ࢖ΘΕΔ͕ීஈ͸શ͘࢖ΘΕͳ͍ • ࠷ۙ͸ਓ͕૿͑ͯDBෛՙ΋ؾʹͳΓ࢝Ίͨ

  30. GraphQL͸ے͕ѱ͍ͷ͔ʁ • ͜ͷ࿩͚ͩฉ͘ͱʮ΍ͬ΂ۙدΒΜͱ͜ʯͬͯࢥ͏ਓ΋͍Δ͔΋ • ੾Γ෼͚ͯߟ͑Δ • ݱঢ়ͷ࢓૊ΈΑΓ΋͍͍ղ๏͕͋Δͷ͔ • ͦΕͱ΋ •

    GraphQLࣗମ͕ۤ࿑ʹରͯ͠Ϧλʔϯ͕߹ͬͯͳ͍ͷ͔
  31. WebϑϩϯτΤϯυଆͷਓʹҙݟΛฉ͍ͯΈΔ • ʮ͢Ͱʹ։ൃ͕͜ͳΕ͖͍ͯͯΔʯʮπʔϧνΣΠϯͷϊ΢ϋ΢΋ཷ·ͬͯ ͍Δʯ • ͦ΋ͦ΋ϑϩϯτΤϯυଆ͸TypeScriptΛશ໘తʹ࠾༻͍ͯͯ͠GraphQLͱ ૬ੑ͕ྑ͍ • ੈؒʹࣄྫ͕ᷓΕ͍ͯΔ૊Έ߹Θͤ •

    ୅ҊͷgRPC(Web͔Gateway)ͩͱ࢓૊Έ͔Βߏங͢Δ͜ͱʹͳΔ • ʮWebϑϩϯτΤϯυଆͷਓ͕GraphQLҎ֎Λ࠾༻͢Δಈػ͸ͳͦ͞͏ʯ
  32. ಄ΛϦηοτͯ͠GraphQLΛ͏·͘αʔόͰѻ ͏͜ͱΛߟ͑Δ • Perlͷ··͍͘ͷ͸೉ͦ͠͏ • ௚઀ѻ͏ʹ͸GraphQL.pm΄΅Ұ୒ͳͷͰ • खલʹapollo-serverཱͯͯREST APIͱ૬ޓม׵͢ΔͷͳΒ… •

    Go͸ࣄྫ͕গ͚ͩ͋͠ΔͬΆ͍ ϥΠϒϥϦ΋͍͔ͭ͋͘Δ • TypeScriptͰ࢖͑Δ੩తܕͷϝϦοτ΋GoͳΒड͚ΒΕΔ
  33. ͔͠͠GraphQLͷαʔόΛ࡞Δ͜ͱࣗମͷ໰୊ ΋͋Δ • DBʹରͯ͠N+1ΫΤϦ • ωετͨ͠ΓෳࡶͳΫΤϦΛೖΕΒΕͨͱ͖ʹDoSΈ͍ͨʹͳΒͳ͍ ͔ • Ωϟογϡ೉͍͠໰୊ •

    etc…etc…
  34. ͔͠͠GraphQLͷαʔόΛ࡞Δ͜ͱࣗମͷ໰୊ ΋͋Δ • DBʹରͯ͠N+1ΫΤϦ • ωετͨ͠ΓෳࡶͳΫΤϦΛೖΕΒΕͨͱ͖ʹDoSΈ͍ͨʹͳΒͳ͍ ͔ • Ωϟογϡ೉͍͠໰୊ •

    etc…etc… Ұճۤ࿑ͨ͠͠ ͳΜͱ͔ͳΔ͔ͳͱࢥͬͨ
  35. ҰͭҰͭղܾ͍ͯ͘͠աఔ

  36. GraphQLύʔαʔ/Resolver => gqlgen • εΩʔϚ͔ΒResolverΛࣗಈੜ੒͢ΔϥΠϒϥϦ

  37. N+1ͷղ๏ => vektah/dataloaden • ӈͷ໰͍߹Θͤϓʔϧ ͷ෦෼Λࣗಈੜ੒͢Δ ϥΠϒϥϦ • Ұఆ࣌ؒ಺ͷಉ͡ςʔ ϒϧʹର͢ΔΫΤϦΛ

    ·ͱΊΒΕΔ
  38. ෳࡶͳΫΤϦʹର͢Δख๏ • Query Complexity • ΫΤϦͷResolverΛ࣮ߦ͢Δલʹॏ͍ΫΤϦ͡Όͳ͍͔ௐ΂Δ • ۩ମతʹ͸ϖʔδϯάΛڧ੍͢ΔͳͲͯ͠औಘ͢Δ࠷େ݅਺ΛΫΤϦ Ͱ֬ఆͤ͞Δ =>

    ᮢ஋Λ΋͏͚ͯ஄͘ • ϖʔδϯάܗࣜ => Relay Server Specification • Ҿ਺΍ϨεϙϯεܗࣜʹσϑΝΫτελϯμʔυ͕͋ΔͷͰ͜ΕΛ࢖͏
  39. ͜ͷลͷ࢓૊ΈͰٙ໰͸ղফͯ͠ ࠓ͸ຊ൪౤ೖʹ޲͚ͯಈ͍͍ͯΔͱ͜Ζ

  40. ͜͜ͰҰ۟ ྑༀ͸ ɹɹޱʹۤ͠ ɹɹɹɹGraphQL

  41. ·ͱΊ • GraphQLʹର͢Δ఍߅ײ͸Կͩͬͨͷ͔͕গ͠Θ͔ͬͨ • ͨͿΜࠓ·Ͱͷαʔόͷ࡞ΓํΛ੍ݶ͢Δ࢓༷ • ৽͍͠ύϥμΠϜͱ͢ΔͱɺڵຯΛ࣋ͬͯऔΓ૊Ίͨ • ৽͍ٕ͠ज़Λ࠾༻͢Δ͜ͱ͸ɺͦͷٕज़ͷະདྷʹϕοτ͢Δ͜ͱ •

    ϕοτ͢Δͱ͍͏͜ͱ͸ɺ͍͟ͱͳΕ͹OSSʹPull RequestΛग़ͨ͠Γɺϓ ϩδΣΫτ಺ʹ޿ΊΔΑ͏ͳओମతͳಈ͖͕ٻΊΒΕΔ • ͜͏΍ͬͯࣄྫΛग़͢ͷ΋ߩݙ͔΋͠Εͳ͍ͱࢥͬͯ΍ͬͯ·͢
  42. ͓·͚

  43. ͭΒ͍΍ͭ: root queryͷnode • Relay Server Specificationʹྫࣔ͞Εͯ ͍Δ΍ͭ • ผʹඞਢͰ͸ͳ͍͕ɺΫϥΠΞϯτଆ͸

    ͋Δͱศར • ΫϥΠΞϯταΠυͷΩϟογϡߋ৽ͷ ͨΊʹNodeͩͬͨΒͳΜͰ΋ฦͤΔ΍ͭ • αʔόαΠυ͸`ID`͚ͩͰͲͷܕ͔Λ൑ఆ ͠ͳ͚Ε͹ͳΒͳ͍
  44. GitHubͷղ๏ idʹܕ৘ใຒΊࠐΜͰbase64Τϯίʔυ

  45. GitHubͷղ๏ idʹܕ৘ใຒΊࠐΜͰbase64Τϯίʔυ

  46. GitHubͷղ๏ idʹܕ৘ใຒΊࠐΜͰbase64Τϯίʔυ