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
760
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
今ならAmazon ECSのサービス間通信をどう選ぶか / Selection of ECS Interservice Communication 2025
tkikuc
21
3.9k
猫と暮らす Google Nest Cam生活🐈 / WebRTC with Google Nest Cam
yutailang0119
0
110
AIと”コードの評価関数”を共有する / Share the "code evaluation function" with AI
euglena1215
1
140
iOS 26にアップデートすると実機でのHot Reloadができない?
umigishiaoi
0
120
Google Agent Development Kit でLINE Botを作ってみた
ymd65536
2
220
“いい感じ“な定量評価を求めて - Four Keysとアウトカムの間の探求 -
nealle
1
8.3k
Composerが「依存解決」のためにどんな工夫をしているか #phpcon
o0h
PRO
1
250
Kotlin エンジニアへ送る:Swift 案件に参加させられる日に備えて~似てるけど色々違う Swift の仕様 / from Kotlin to Swift
lovee
1
260
CursorはMCPを使った方が良いぞ
taigakono
1
240
新メンバーも今日から大活躍!SREが支えるスケールし続ける組織のオンボーディング
honmarkhunt
3
5.9k
関数型まつりレポート for JuliaTokai #22
antimon2
0
160
PostgreSQLのRow Level SecurityをPHPのORMで扱う Eloquent vs Doctrine #phpcon #track2
77web
2
500
Featured
See All Featured
Facilitating Awesome Meetings
lara
54
6.4k
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
194
16k
Six Lessons from altMBA
skipperchong
28
3.9k
Bootstrapping a Software Product
garrettdimon
PRO
307
110k
How to train your dragon (web standard)
notwaldorf
94
6.1k
Making Projects Easy
brettharned
116
6.3k
Writing Fast Ruby
sferik
628
62k
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
29
9.5k
Navigating Team Friction
lara
187
15k
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
357
30k
4 Signs Your Business is Dying
shpigford
184
22k
We Have a Design System, Now What?
morganepeng
53
7.7k
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%ある