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 with Go
Search
Yuki Suwa
November 13, 2021
Programming
0
600
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
Site Reliability Engineering for GMO
pyama86
6
940
元気予報
suu_mire0726
0
860
本格ローグライク制作にEbitengineを選んでみた
nagainaganawa
0
290
Micro Frontends for Java Microservices - Devnexus 2024
mraible
PRO
0
420
[技育CAMPアカデミア]アイディアを形に!【超入門】スマホアプリ開発〜リリースまでの流れをご紹介
teamlab
PRO
0
350
Designing for tomorrow's programming workflows
honnibal
PRO
2
110
コードレビューで学ぶ!Kotlinオブジェクト指向デザインパターン
akkie76
2
180
Prepare for Jakarta EE 11 - Performance and Developer Productivity
ivargrimstad
0
450
データアナリストが行うDatabricksを活用したETLの自動化事例
shinoa
0
250
Folding Cheat Sheet #3
philipschwarz
PRO
0
110
品質とスピードを両立: TypeScriptの柔軟な型システムをバックエンドで活用する
kosui
8
2.2k
코틀린으로 멀티플랫폼 만들기
pangmoo
0
120
Featured
See All Featured
Put a Button on it: Removing Barriers to Going Fast.
kastner
58
3k
Building Effective Engineering Teams - LeadDev
addyosmani
27
1.8k
Practical Orchestrator
shlominoach
181
9.7k
A Philosophy of Restraint
colly
196
16k
Bootstrapping a Software Product
garrettdimon
PRO
301
110k
The Illustrated Children's Guide to Kubernetes
chrisshort
29
46k
A better future with KSS
kneath
231
16k
Principles of Awesome APIs and How to Build Them.
keavy
120
16k
Optimising Largest Contentful Paint
csswizardry
7
2.3k
Optimizing for Happiness
mojombo
370
69k
Teambox: Starting and Learning
jrom
128
8.4k
Keith and Marios Guide to Fast Websites
keithpitt
408
22k
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%ある