Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
GoとGraphQLを使用したサービス開発 / Develop GraphQL service...
Search
Yuki Suwa
November 13, 2021
Programming
0
770
GoとGraphQLを使用したサービス開発 / Develop GraphQL service with Go
Go Conference 2021 Autumn
Yuki Suwa
November 13, 2021
Tweet
Share
Other Decks in Programming
See All in Programming
go test -json そして testing.T.Attr / Kyoto.go #63
utgwkk
3
310
速いWebフレームワークを作る
yusukebe
5
1.7k
私の後悔をAWS DMSで解決した話
hiramax
4
210
Navigating Dependency Injection with Metro
zacsweers
3
990
Rancher と Terraform
fufuhu
2
550
アルテニア コンサル/ITエンジニア向け 採用ピッチ資料
altenir
0
110
ファインディ株式会社におけるMCP活用とサービス開発
starfish719
0
1.7k
デザイナーが Androidエンジニアに 挑戦してみた
874wokiite
0
480
Amazon RDS 向けに提供されている MCP Server と仕組みを調べてみた/jawsug-okayama-2025-aurora-mcp
takahashiikki
1
110
個人軟體時代
ethanhuang13
0
320
Cache Me If You Can
ryunen344
2
1.5k
AIコーディングAgentとの向き合い方
eycjur
0
270
Featured
See All Featured
GraphQLの誤解/rethinking-graphql
sonatard
72
11k
How To Stay Up To Date on Web Technology
chriscoyier
790
250k
Designing for Performance
lara
610
69k
Intergalactic Javascript Robots from Outer Space
tanoku
272
27k
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
30
9.7k
Mobile First: as difficult as doing things right
swwweet
224
9.9k
GitHub's CSS Performance
jonrohan
1032
460k
How STYLIGHT went responsive
nonsquared
100
5.8k
XXLCSS - How to scale CSS and keep your sanity
sugarenia
248
1.3M
How to Ace a Technical Interview
jacobian
279
23k
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
229
22k
A designer walks into a library…
pauljervisheath
207
24k
Transcript
GoとGraphQLを使用したサービス開発 Yuki Suwa (@flum_) Go Conference 2021 Autumn
Agenda 1. 自己紹介 2. 新規事業何が大変か 3. GoやGraphQLの採用理由 4. 実装の課題 5.
工夫していること 6. まとめ
自己紹介 • 諏訪 侑希 • Github: flum1025 • Twitter: @flum_
• Retty株式会社 ◦ RettyOrder開発リーダー ◦ 普段はFrontend, Backendの 設計から実装までやってます • Go歴: 3年
食を通じて 世界中の人々を Happyに。 世界に誇る日本の文化であり、世界中の人々の 暮らしの中心でもある、「食」という分野で、お店を探 す人とお店の人の双方がHappyに なれる、そんな世界を実現したい。その為に、 お店をオススメするというポジティブな感情で 人をつなぐ事がRettyの目標です。 コーポレートビジョン
どういうサービスなのか
どういうサービスなのか Retty Order ユーザー 店員 ①注文 ④提供 ②通知 ③調理
新規事業何が大変か
新規事業何が大変か • 刻々と変化する状況 • 限られたリソースと時間 • ヒアリングだけだと表に出てこない細かい課題や実際のオペレーション
新規事業何が大変か • 刻々と変化する状況 ◦ => 方向転換に耐えうる設計にしたい • 限られたリソースと時間 ◦ =>
複雑な設計にすると運用コストが大きくなる可能性が高い • ヒアリングだけだと表に出てこない細かい課題や実際のオペレーション ◦ => 大きく作ると無駄になる可能性が高い
新規事業としての要件 • スピードが重要なのでなるべくシンプルに早く実装したい ◦ かといって機能開発に振り切ると負債の解消ができず後々死ぬ • 将来的に開発体制をスケールできる設計を目指したい • 金銭を扱うサービスになるのでなるべく安全に実装したい •
お店の根幹を担うサービスになるのでEntityの種類が増えそう
実装方針
実装方針 • スピードが重要なのでなるべくシンプルに早く実装したい ◦ => GraphQLを採用してスキーマ駆動開発 ▪ 実装前にスキーマさえ決めればフロントエンド、バックエンド、アプリを平行して実 装できる
実装方針 • 将来的に開発体制をスケールできる設計を目指したい ◦ => Clean Architectureを採用しドメイン駆動設計 ▪ ドメインモデリングしていれば、モノリスで作ったとしてもスケールしたタイミング で切り出しやすい
実装方針 • 金銭を扱うサービスになるのでなるべく安全に実装したい ◦ => Goを採用し静的に型付けする ◦ => Clean Architectureならレイヤーごとにテストしやすい
実装方針 • お店の根幹を担うサービスになるのでEntityの種類が増えそう ◦ => GraphQLなら欲しいデータをクライアントで定義できる ▪ Resolverさえ実装すればusecaseごとにエンドポイントを用意しなくてよい
RettyにおけるGoとGraphQL
RettyにおけるGoとGraphQL • Rettyでは一部のマイクロサービスとしてGoとGraphQLが採用 されている • 社内での運用実績、知見が少しだが溜まっていた https://engineer.retty.me/entry/2021/06/04/110000
実装上の課題
実装上の課題 Retty Order ユーザー 店員 ①注文 ④提供 ②通知
③調理
通知の課題 • リアルタイム性が求められる • 注文ごとにイベントが発生するため、メッセージ量が多い • 元々はポーリングで実装していた ◦ ポーリングの間隔によってはリアルタイムとは言えない ▪
間隔下げれば下げるほど負荷が高い ◦ データ数が多く全データ取得するには負荷が高い ▪ 一部だけポーリングで取得するような実装もつくれるには作れるが、、
そこでGraphQL Subscription • GraphQL上のPub/Subの仕組み • Mutation等で発生したイベントなどをリアルタイムに購読できる • GraphQL自体はトランスポート層に依存しないので実装は好きな物を選べる ◦ 以下の実装はgqlgenに標準で備わっているため簡単に利用できる
▪ WebSocket ▪ Long Polling(一回のイベント通知のみ) ◦ Transportの実装をカスタムできるので、やろうと思えばServer-Send Event(SSE) やHTTP Streamingでも実装できそう
GraphQL Subscriptionを実装するには • 基本的に世のWebアプリケーションはスケールが前提 • アプリケーションサーバー間でもイベントを共有できる仕組みが必要 ◦ どのサーバーに繋がったとしても同じイベントを購読したい • アプリケーションサーバー間のPub/SubとしてRedisを置くことでどの
サーバーに繋がったとしても同じイベントが購読できる • Subscriptionでは並行処理を多用するのでGoと相性がいい
運用中に起きたこと
Redisのバッファーが詰まる • ある日、注文画面が更新されないという報告が来た • 本番環境にアクセスしたところ、 WebSocketのコネク ションは繋がっており、Authentication, Initializationは 正常にできていた •
しかし、イベントを発生させてみてもメッセージが流れて くる様子がない • Redisのメトリクスをみても負荷が特段高いわけではな く、コネクション数等もかなり余裕があった conneciton_initとSubscriptionクエリが発行されている様子
Redisのバッファーが詰まる
Redisのバッファーが詰まる • GraphQLサーバーのログをみたところ、go-redisの channel is fullというログが発生していた • リソース節約のため同イベントの購読は Redisの Subscribeを使いまわす実装になっていた
• 調査したところネットワークが遅いクライアントがいた場 合、メッセージの送信に時間がかかり bufferを食い潰すこ とがわかった timerを利用してメッセージの送信に時間が かかり過ぎる場合は購読を切る仕組みを作 成
パフォーマンス監視
パフォーマンス監視 • 本番で運用するにはサービスの監視だけではなく、 アプリケーション内部を監視しボトルネック を特定させる必要がある • gqlgenを採用する場合パフォーマンス監視の仕組みを自前で作る必要がある ◦ Apollo Tracingには一応対応している
▪ が、レスポンス(or ログ)を監視して送る仕組みは自分でつくらないといけない ▪ GraphQL以外の部分のTraceとの紐付けができない ◦ 過去にはOpenCensus, OpenTracing等に対応していたっぽいが、メンテしておらず最新のバー ジョンでは利用できない ◦ gqlgenにはプラグインの仕組みがある ▪ 自前でプラグインを作って APMに送る仕組みを作成
gqlgenのパフォーマンス監視 ResponseIntereceptor FieldInterceptor • InterceptResponseを使用すると各 オペレーションの実行時に呼び出せ る • InterceptFieldで各Fieldの実行時に 呼び出せる
• Datadog等を使う場合はContextを 利用してOperationとFieldに親子関 係を持たせられる [Point] InterceptFieldは構造体のFieldからデータを取得する際にも 実行されてしまうので、 Resolver関数が定義されてるものに絞る 構造体のFIeldから取得する場合は親の Field解決時にデータ取得済 みなのでここでトレースする必要はない
gqlgenのパフォーマンス監視
開発で工夫していること
レプリカラグを意識した開発 • Amazon Aurora MySQLを使用している • Aurora MySQLは一般のMySQLよりは低遅延だが、遅延はある ◦ 公式では100ms未満と記載されている
• レプリカラグを意識した開発を強制している ◦ Readerインスタンスに `MASTER_DELAY=1` つけるだけ https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/AuroraUserGuide/A urora.Replication.html
まとめ
こういう実装方針でした • スピードが重要なのでなるべくシンプルに早く実装したい ◦ => GraphQLで解決 • 将来的に開発体制をスケールできる設計を目指したい ◦ =>
Clean Architectureで解決 • 金銭を扱うサービスになるのでなるべく安全に実装したい ◦ => GoとClean Architectureで解決 • お店の根幹を担うサービスになるのでEntityの種類が増えそう ◦ => GraphQLで解決
採用してどうだったか • Go ◦ 良くも悪くもシンプルなので、ロジックに対するレビューに集中できる ◦ コードが冗長になるのはちょっと辛い • CleanArchitecture ◦
ドメインモデリングのために議論が盛んに ▪ レビュー前に議論すると大きな手戻りが減らせるし今後の拡張もしやすくなる ▪ ドメインについてちゃんと考える必要があるのでスコープも小さくなる ◦ テストがしやすいのでテストコードが増えて行きやすい ▪ カバレッジが全てではないが、開発時の安心感は絶大 ▪ テストがあると思い切ったリファクタがしやすいので開発効率を保てる • GraphQL ◦ 新しいデータに依存しない部分はフロントで完結できるので、フロントの開発スピードは早 い カバレッジは90%ある