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
700
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
Beyond ORM
77web
11
1.6k
AWSのLambdaで PHPを動かす選択肢
rinchoku
2
400
動作確認やテストで漏れがちな観点3選
starfish719
5
580
[JAWS-UG横浜 #80] うわっ…今年のServerless アップデート、少なすぎ…?
maroon1st
0
140
SpringBoot3.4の構造化ログ #kanjava
irof
1
210
Amazon Nova Reelの可能性
hideg
0
240
[JAWS-UG横浜 #79] re:Invent 2024 の DB アップデートは Multi-Region!
maroon1st
0
120
traP の部内 ISUCON とそれを支えるポータル / PISCON Portal
ikura_hamu
0
230
Alba: Why, How and What's So Interesting
okuramasafumi
0
230
混沌とした例外処理とエラー監視に秩序をもたらす
morihirok
18
3k
2025.01.17_Sansan × DMM.swift
riofujimon
2
630
PHPとAPI Platformで作る本格的なWeb APIアプリケーション(入門編) / phpcon 2024 Intro to API Platform
ttskch
0
410
Featured
See All Featured
The Cost Of JavaScript in 2023
addyosmani
47
7.3k
GraphQLの誤解/rethinking-graphql
sonatard
68
10k
A Tale of Four Properties
chriscoyier
157
23k
VelocityConf: Rendering Performance Case Studies
addyosmani
327
24k
Writing Fast Ruby
sferik
628
61k
The Invisible Side of Design
smashingmag
299
50k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
33
2.7k
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
28
4.5k
Become a Pro
speakerdeck
PRO
26
5.1k
Building an army of robots
kneath
302
45k
Building a Modern Day E-commerce SEO Strategy
aleyda
38
7.1k
Fontdeck: Realign not Redesign
paulrobertlloyd
82
5.3k
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%ある