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
connect-go で面倒くささと戦う / 2024-08-27 #newmo_layerx_go
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
izumin5210
August 27, 2024
Programming
2.4k
2
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
connect-go で面倒くささと戦う / 2024-08-27 #newmo_layerx_go
newmo × LayerX "Go"同 勉強会
https://layerx.connpass.com/event/323385/
izumin5210
August 27, 2024
More Decks by izumin5210
See All by izumin5210
開発体験を左右するライブラリの API 設計 - GraphQL スキーマ構築ライブラリから考える #tskaigi
izumin5210
2
1.7k
izumin5210のプロポーザルのネタ探し #tskaigi_msup
izumin5210
2
860
AI Agent の開発と運用を支える Durable Execution #AgentsInProd
izumin5210
8
2.8k
AI Agent Tool のためのバックエンドアーキテクチャを考える #encraft
izumin5210
6
2.2k
Building AI Agents with TypeScript #TSKaigiHokuriku
izumin5210
6
1.8k
Web エンジニアが JavaScript で AI Agent を作る / JSConf JP 2025 sponsor session
izumin5210
4
3.4k
AI Coding Meetup #3 - 導入セッション / ai-coding-meetup-3
izumin5210
0
3.7k
Web フロントエンドエンジニアに開かれる AI Agent プロダクト開発 - Vercel AI SDK を観察して AI Agent と仲良くなろう! #FEC余熱NIGHT
izumin5210
3
1.2k
TypeScript を活かしてデザインシステム MCP を作る / #tskaigi_after_night
izumin5210
5
930
Other Decks in Programming
See All in Programming
Semantic Version 単位で戦略を柔軟に変えて、パッケージアップデートを自動化する
daitasu
0
220
Oxlintのカスタムルールの現況
syumai
6
1.1k
AI 時代のソフトウェア設計の学び方
masuda220
PRO
29
12k
These Five Tricks Can Make Your Apps Greener, Cheaper, & Nicer
hollycummins
0
280
Why Laravel apps break—Mastering the fundamentals to keep them maintainable
kentaroutakeda
1
350
AIチームを指揮するOSS「TAKT」活用術 / How to Use “TAKT,” an OSS Tool for Orchestrating AI Teams
nrslib
6
880
Copilot CLI の継戦能力を高める コンテキスト管理
nozomutu
1
1.2k
Agentic UI
manfredsteyer
PRO
0
140
Observability in Practice:Grafana 與 Edge Device SRE 的那些事
blueswen
0
160
依存関係から依存物へ―Dependencyという言葉の歴史をひも解く
j_lee
0
110
LLMによるContent Moderationの本番運用の裏側と品質担保への挑戦
suikabar
2
570
Language Server 使ってる? 〜VSCode と Zed の場合〜 / Are you using a Language Server? ~For VS Code and Zed~
handlename
0
780
Featured
See All Featured
Stewardship and Sustainability of Urban and Community Forests
pwiseman
0
220
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
52
6k
svc-hook: hooking system calls on ARM64 by binary rewriting
retrage
2
290
Documentation Writing (for coders)
carmenintech
77
5.4k
SEO in 2025: How to Prepare for the Future of Search
ipullrank
3
3.5k
A better future with KSS
kneath
240
18k
AI: The stuff that nobody shows you
jnunemaker
PRO
8
710
AI Search: Implications for SEO and How to Move Forward - #ShenzhenSEOConference
aleyda
1
1.3k
The Mindset for Success: Future Career Progression
greggifford
PRO
0
360
Marketing to machines
jonoalderson
1
5.4k
Leveraging Curiosity to Care for An Aging Population
cassininazir
1
270
Understanding Cognitive Biases in Performance Measurement
bluesmoon
32
2.9k
Transcript
© LayerX Inc. connect-go で面倒くささと戦う 2024-08-27 newmo × LayerX "Go"同
勉強会 @izumin5210
© LayerX Inc. 2 ▸ Wantedly, Inc. (2018-04 - 2022-08)
▸ LayerX (2022-09-) ‐ バクラク事業部 Platform Engineering 部 Enabling Team ‐ Backend と Web Frontend 中心にやってます ▸ 最近気になっているパッケージは github.com/pingcap/tidb/parser 画像を入れてね whoami @izumin5210
はじめに 前提になるプロダクト「バクラク」とアーキテクチャ概要
4 © LayerX Inc. 今日の話の前提: バクラクについて LayerX Company Deck https://speakerdeck.com/layerx/company-deck?slide=23
© LayerX Inc. 5 ▸ プロダクト: お客様に1つのパッケージとして価値を提供するソフトウェア製品 ‐ (「バクラク申請」など、右下の図における ◦
を指すイメージ) ▸ サービス: 論理的あるいは物理的に分けられた1つのサーバアプリケーション ‐ マイクロサービス・アーキテクチャにおける 「サービス」という単語と概ね同等 発表内での用語の定義 今日の話の前提: 用語の定義
6 © LayerX Inc. 今日の話の前提: バクラクのバックエンド API の移り変わり Product1 Webapp
Product2 Webapp Product1 Service Product2 Service OpenAPI GraphQL ▸ 初期のプロダクトは go-swagger, gqlgen などでバックエンドサーバを作っていた
7 © LayerX Inc. 今日の話の前提: バクラクのバックエンド API の移り変わり Product1 Webapp
Product2 Webapp Product1 Service Product2 Service Product3 Webapp Product3 Service OpenAPI GraphQL
8 © LayerX Inc. 今日の話の前提: バクラクのバックエンド API の移り変わり Product1 Webapp
Product2 Webapp Product1 Service Product2 Service Product3 Webapp Product3 Service こっちの情報も見せたい… こっちの情報を使いたい… OpenAPI GraphQL
9 © LayerX Inc. 今日の話の前提: バクラクのバックエンド API の移り変わり Product1 Webapp
Product2 Webapp Product1 Service Product2 Service Product3 Webapp Product3 Service OpenAPI GraphQL GraphQL Gateway GraphQL Connect ▸ 初期のプロダクトは go-swagger, gqlgen などでバックエンドサーバを作っていた ▸ プロダクトやプロダクト間連携が増えてきたことに対応するため、 GraphQL Gateway (!= BFF, Node.js 製)を構築し、バックエンドに connect-go を使い始めた
Connect #とは
© LayerX Inc. 11 ▸ gRPCと互換性をもつ、 HTTP APIを実装するためのフレームワーク ▸ gRPC
Protocolとの完全な互換性に加え、 human-readable and debuggableなConnect Protocolをサポート ‐ JSONやProtobufをHTTP/1.1の上でやりとりできる(片方向通信の場合) 💡豆知識 “Connect” がプロジェクト名だが、文脈からわかりづらいときなどは “Connect RPC” と表記してもいいらしい* Connect #とは Connect #とは * https://connectrpc.com/docs/faq
© LayerX Inc. 12 protobuf-go のコード生成 Connect #とは message GreetRequest
{ string name = 1; } こういうmessage定義から… type GreetRequest struct { // private fields Name string `::.` } こういう構造体定義が生成される
© LayerX Inc. 13 connect-go のコード生成 Connect #とは service GreetService
{ rpc Greet(GreetRequest) returns (GreetResponse) {} } こういうサービス定義から…
© LayerX Inc. 14 connect-go のコード生成 Connect #とは type GreetServiceClient
interface { // クライアントがリクエストするときの interface Greet(context.Context, *connect.Request[v1.GreetRequest]) (*connect.Response[v1.GreetResponse], error) } type GreetServiceHandler interface { // サーバが実装することになる interface Greet(context.Context, *connect.Request[v1.GreetRequest]) (*connect.Response[v1.GreetResponse], error) } こういうのを生成してくれる (un)marshal など「いつもの」な処理はConnectがやってくれる
© LayerX Inc. 15 (いろんなところで話しまくってるので圧縮してお届け 📦) ▸ Why APIスキーマ ‐
自然言語によらず、機械同士・人間同士いずれのコミュニケーションにも使えるプロトコルになる ‐ サーバ・クライアントいずれもコード生成できる場合が多く、スキーマと実装の乖離を防ぐことができる ▸ Why Protobuf ‐ スキーマ記述が簡素で可読性が高い(e.g. OpenAPI と比較し情報密度が高くなりやすい, 一般的なプログラミング言語っぽい, etc.) ‐ 互換性を保ちやすい, 互換性が壊れたことを機械的に検知できる ‐ 拡張性の高さ ‐ message(データ, リソース, モデル)を考える方向に思考が働きやすい(cf. OpenAPI だと operation にベタ書きしちゃう) ▸ Why gRPC ‐ Protobuf で記述した interface の実装に集中できる(json.Unmarshal のような「いつもの」コードは不要) などなど Why APIスキーマ, Why Protobuf, Why gRPC Connect #とは 今さらProtocol Buffersと、手に馴染む道具の話 https://qiita.com/yugui/items/160737021d25d761b353 Protocol Buffers によるプロダクト開発のススメ - API 開発の今昔 https://www.wantedly.com/companies/wantedly/post_articles/309513
© LayerX Inc. 16 ▸ Go 実装の出来がいい ‐ サーバは net/http.Handler,
クライアントは net/http.Client であり 利用可能な 3rd party パッケージの幅が広い ▸ HTTP/1.1 かつ application/json なリクエストを投げられる ‐ ローカル開発で雑にデバッグできて便利! ‐ 特別なクライアント実装がなくても使えるので、応用が効きやすい(後述) 👉 いずれも gRPC(grpc-go) の抱える複雑性を低減してくれそう Why Connect(connect-go) Connect #とは
© LayerX Inc. 17 ▸ スキーマ駆動自体は gRPC でもできる ▸ 一方で、プロトコルからくる仕様・実装により別の複雑性が発生していた
▸ Connect(connect-go) を使うことで、その gRPC の複雑さを回避するぞ! …というのが今日の内容です Why Connect(connect-go) Connect #とは
バクラクでの Connect 応用例 1 非同期API・非同期ジョブ
© LayerX Inc. 19 非同期API・非同期ジョブ バクラクでの Connect 応用例: 非同期API・非同期ジョブ ▸
スキーマがないことが多い ‐ そのジョブのペイロードの struct を定義してても、安易に変えるとデプロイの間で壊れたり ‐ caller と callee が同じサービスならまだマシだが、別だったらスキーマないと地獄 ▸ ローカル等での雑デバッグ面倒になりがち ‐ (テストを書こうという話もありつつ…)手元でシュッと動かしたいときに面倒になりがち ‐ REPL がある言語ならやりやすいんだけど…
© LayerX Inc. 20 非同期API・非同期ジョブにもConnectを バクラクでの Connect 応用例: 非同期API・非同期ジョブ Publisher
Connect server service GreetService { rpc Greet(GreetRequest) returns (GreetResponse) {} } 行き先(GreetService/Greet)と ペイロード(GreetRequest)を キューに詰める Subscriber Worker
© LayerX Inc. 21 非同期API・非同期ジョブにもConnectを バクラクでの Connect 応用例: 非同期API・非同期ジョブ Publisher
Connect server Subscriber Worker キューから取り出した内容を見て Subscriber が適切な Connect Server を呼ぶ Connect Protocol でリクエストすればいいだけ ここがConnectによる通信になる
© LayerX Inc. 22 この仕組みがなぜ嬉しいか バクラクでの Connect 応用例: 非同期API・非同期ジョブ Publisher
Connect server Subscriber Worker ▸ 非同期でもちゃんとスキーマ定義できる ‐ 雑に json.Marshal するのではなく、 同期APIと同じメンタルモデルで型定義を。 非同期ジョブ・非同期APIもAPI! ▸ 雑デバッグが楽! ‐ Publisher がまだなくてもおもむろに cURL で動かせる!
バクラクでの Connect 応用例 2 ローカルでの起動を楽にする
© LayerX Inc. 24 ローカルでの起動がどんどん大変になる問題 バクラクでの Connect 応用例: ローカルでの起動を楽にする TenantService
CardTransactionService WorkflowService NotificationService ▸ プロダクトが発展する、あるいは増えると サービスも増える ▸ いまの開発に必要なのはこれとこれと… と 起動していくのは面倒 ▸ ポート番号を予約してくのも面倒
© LayerX Inc. 25 ローカルでは1つのHTTP serverに 全Connect serverを乗せる バクラクでの Connect
応用例: ローカルでの起動を楽にする TenantService NotificationService CardTransactionService 論理的には別のサービス ローカルでは物理的には1つのサービス TenantService NotificationService CardTransactionService 社内ではgo-allと呼ばれています
© LayerX Inc. 26 ローカルでは1つのHTTP serverに 全Connect serverを乗せる バクラクでの Connect
応用例: ローカルでの起動を楽にする TenantService NotificationService CardTransactionService ▸ ローカルでは全サービスを1つに まとめることで、起動を楽にしている ▸ cURLで雑デバッグしたいときも ポート番号を1つだけ覚えておけばいい ▸ デプロイ時は 論理的なサービス = 物理的なサービス
© LayerX Inc. 27 バクラクでの Connect 応用例: ローカルでの起動を楽にする func HandlerOptions(ctx
context.Context) ([]connect.Option, error) { svc, err := NewServiceHandler(ctx) if err := nil { return nil, err } path, handler := tenantv1connect.NewTenantServiceHandler(svc, /* common options //) return []connect.Option{ connect.WithHandler(path, handler), connect.WithCloseHandler(svc), }, nil } http.Handler と path を生成する関数を各サービスに生成して、
© LayerX Inc. 28 バクラクでの Connect 応用例: ローカルでの起動を楽にする var ServiceHandlerOptions
= map[string]func() ([]connect.Option, error){ tenantv1connect.TenantServiceName: tenant_v1_tenant.HandlerOptions, // 全サービスの HandlerOptions 関数を突っ込んでおく } 全サービスの HandlerOptions 関数を突っ込んだ map をコード生成する あとはこれを使って Connect server を作るだけ
© LayerX Inc. 29 ローカルでは1つのHTTP serverに 全Connect serverを乗せて、ログは頑張って探しやすくする バクラクでの Connect
応用例: ローカルでの起動を楽にする ▸ 「複数サービスのログが1つの stdout で流れてしまう」というデメリット ‐ 読めねえ ▸ バクラクでは Grafana 上でログ・トレースを探せるようにしている ‐ プロセスマネージャ* でログを OpenTelemetry に変換し、Loki, Tempo に投入 ‐ ログだけでいいならシンプルに Promtail + Loki でも可 * エンジニアオンボーディングを改善するツールの紹介 https://tech.layerx.co.jp/entry/2022/12/12/131507
バクラクでの Connect 応用例 2.5 ローカルでの起動を楽に・かつ速くする
© LayerX Inc. 31 全サービスを1つにまとめると、ビルドはどんどん重くなる バクラクでの Connect 応用例: ローカルでの起動を速くする ▸
あらゆるサービスをひとまとめにビルドしようとすると、当然ながら重くなる ▸ ローカルでは、いま開発中のサービス以外の要因で待たされたくない ‐ いま開発中 is … リクエストが来たサービス? 👉 リクエストが来たサービスだけビルドする!
© LayerX Inc. 32 ビルドはどんどん重くなっていくので、 部分的にビルドできるようにする バクラクでの Connect 応用例: ローカルでの起動を速くする
▸ メインの port を listen してるプロセスがリクエストを受けたら、 ‐ 対象のサービスをビルドし ‐ Unix domain socket を listen する形で起動して ‐ そこにリクエストを流す! ▸ 最小限しかビルドしないので速い! ▸ これも go-all と似たような感じで実装を生成する
バクラクでの Connect 活用術 3 デプロイもちょっと楽にする
© LayerX Inc. 34 ローカルでは1つのHTTP serverに 全Connect serverを乗せる バクラクでの Connect
応用例: デプロイもちょっと楽にする TenantService NotificationService CardTransactionService ▸ ローカルでは全サービスを1つに まとめることで、起動を楽にしている 👉 全サービスを1バイナリにまとめてるなら AWS 上でも1バイナリだけでいいのでは?
© LayerX Inc. 35 1つのバイナリに全Connect serverを乗せて、 起動時に出し分ける バクラクでの Connect 応用例:
デプロイもちょっと楽にする ▸ 全てのサービスをまとめたバイナリをAWS 上でも動かせば、 1度ビルドしたバイナリは使い回せる! ‐ ビルド時間, ストレージなどの節約になる! ▸ 実際は振る舞いがちょっと違うので、モードを2つに分けている* ‐ 全サービスが起動するモードと、特定のサービスのみ起動するモード * connect\-go による複数サービスの開発とユニバーサルバイナリによる改善 https://tech.layerx.co.jp/entry/2023/07/18/173901
バクラクでの Connect 活用術 3 デプロイをさらに楽にする
© LayerX Inc. 37 ローカルでは1つのHTTP serverに 全Connect serverを乗せる バクラクでの Connect
応用例: デプロイをさらに楽にする TenantService NotificationService CardTransactionService ▸ デプロイ時は 論理的なサービス == 物理的なサービス 👉 …じゃなくてもいいのでは?
© LayerX Inc. 38 複数の論理的なサービスを1つのデプロイメントにまとめる バクラクでの Connect 応用例: デプロイをさらに楽にする TenantService
CardTransactionService NotificationService ▸ 非機能要件面で分ける理由がない場合は、 1つのデプロイメントに 複数の論理的なサービスを乗せることも可 WorkflowService
バクラクでの Protobuf 活用術 もはや Connect あんまり関係ないが、 Protobuf 自体も便利!
© LayerX Inc. 40 ▸ データを定義してそこから必要な実装を生やすシリーズ ‐ e.g. FeatureFlag, 権限・ロール
▸ Protobuf の message, enum から GraphQL の型を生成 ▸ Protobuf Message に sql.Scanner & driver.Valuer を実装し、 JSON 表現で DB に格納してくれるコードを生成する ▸ サービス間通信の認証情報は Protobuf で payload 定義し、署名を付けている ‐ JWT 的な感じだが、Protobuf なのでサイズを抑えることができる ▸ Connect のサービス定義から Go のサービス実装の scaffolding バクラクでの Protobuf 活用例
まとめ
© LayerX Inc. 42 まとめ もともとのモチベーション ▸ スキーマ駆動自体は gRPC でもできる
‐ 一方で、プロトコルからくる仕様・実装により別の複雑性が発生していた ▸ Connect(connect-go) を使うことで、その gRPC の複雑さを回避するぞ! Connect によって… ▸ 非同期ジョブ・非同期 API にも Connect を使い、通常の API と同じ開発体験に ▸ ローカルでは全サービスのプロセスを1つにまとめて、起動を楽に ‐ さらにそのうち必要なサービスのみビルドすることで、起動を高速に ▸ 本番でも複数の論理サービスを1つの物理サービスにまとめることでインフラも楽に ▸ その他 Protobuf にいろいろやってもらって、いろいろ便利に