Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Прозрачный gRPC-proxy один-ко-многим - Андрей С...
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
GopherCon Russia
April 23, 2021
Programming
190
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Прозрачный gRPC-proxy один-ко-многим - Андрей Смирнов
GopherCon Russia
April 23, 2021
More Decks by GopherCon Russia
See All by GopherCon Russia
Go Profiling from Bottom Up - Felix Geisendörfer
gopherconrussia
0
270
Learning Unsung Gotchas of Go - Rashmi Nagpal
gopherconrussia
1
310
Из Python в Go и обратно - Андрей Минкин
gopherconrussia
0
190
Оптимизация работы с PostgreSQL в Go: от 50 до 5000 RPS - Иван Осадчий
gopherconrussia
0
230
Пакет embed: распаковка знаний - Илья Данилкин
gopherconrussia
0
300
За пару мгновений до main() - Олег Ковалев
gopherconrussia
0
180
Тестирование в Go c Ginkgo и Gomega - Александр Егурнов
gopherconrussia
0
170
Building an Autoscaling HTTP Proxy for Kubernetes - Aaron Schlesinger
gopherconrussia
0
170
Designing Pluggable Idiomatic Go Applications – Mark Bates
gopherconrussia
0
91
Other Decks in Programming
See All in Programming
月間100万人のサービス刷新で、 技術選定をHonoに振り切った話
yutobara
8
6.3k
sbt 2.0: takeoff
eed3si9n
0
140
Rでドレミ/Do-Re-Mi_with_R
florets1
0
130
Augmenting AI with the Power of Jakarta EE
ivargrimstad
0
630
個人開発者よ、Honoを使え(おじさんver)
tanahiro2010
2
250
JRuby: Past, Present, and Future
headius
0
230
AIに “答え“を書かせるのを やめてみた
___akari11
0
120
The Rails Doctrine Decade
koic
2
560
CodeRabbitの効果検証と過ごしてみた3ヶ月
armondando
0
230
UnityでSystem.Net.WebSocketsなWebSocketサーバが動かないのでUnity Monoのコードを覗いてみた / about implementing websocket server with unity mono
drumath2237
1
580
ジョジョの世界をXRで再現する
mofurune
0
150
GemmaをJevのように使ってみる / Use Gemma like Jev
kishida
5
770
Featured
See All Featured
Taking LLMs out of the black box: A practical guide to human-in-the-loop distillation
inesmontani
PRO
3
2.4k
Public Speaking Without Barfing On Your Shoes - THAT 2023
reverentgeek
1
590
Claude Code のすすめ
schroneko
67
230k
What does AI have to do with Human Rights?
axbom
PRO
1
2.4k
Game over? The fight for quality and originality in the time of robots
wayneb77
1
300
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
25
2.1k
Code Reviewing Like a Champion
maltzj
529
40k
Collaborative Software Design: How to facilitate domain modelling decisions
baasie
1
340
For a Future-Friendly Web
brad_frost
184
10k
GraphQLとの向き合い方2022年版
quramy
50
15k
ラッコキーワード サービス紹介資料
rakko
1
5.3M
Self-Hosted WebAssembly Runtime for Runtime-Neutral Checkpoint/Restore in Edge–Cloud Continuum
chikuwait
0
880
Transcript
Transparent gRPC Gateway in Go GopherCon Russia’21 Andrey Smirnov, Talos
Systems
About Andrey Smirnov @smira github.com/smira Go developer since 2014 Working
on Talos: revolutionary OS for clusters
Agenda Why gRPC? Why API gateway? Why Go? First iteration
in Go, problems and solutions. Transparent proxying in Go using gRPC. Cutting and concatenating protobuf messages.
Why gRPC? API, but as easy as calling a function
API Gateway/Proxy gRPC gRPC backend gRPC backend API Gateway
Use Cases for gRPC API Gateway Migrating from monolith to
smaller services (or vice versa) Migrating to new API version Common authentication or authorization layer Logging, traceability, … Non-trivial proxy logic: send one request to many backends, combine responses
gRPC API Gateway Implementation TCP loadbalancer HTTP reverse proxy (e.g.
nginx) ... Implement our own in Go (!)
Ping-pong gRPC service message Ping { string value = 1;
} message Pong { string value = 1; } service TestService { rpc PingPong(Ping) returns (Pong) {} }
Easy! (?) func (s *Proxy) connect() { s.conn = grpc.Dial(...)
s.client = pb.NewTestServiceClient(conn) } func (s *Proxy) PingPong(ctx context.Context, ping *pb.Ping) (*pb.Pong, error) { return s.client.PingPong(ctx, ping) }
gRPC metadata gRPC metadata: headers, trailers Go gRPC Client Metadata:
Metadata Go gRPC Server Metadata: Headers Trailers
Metadata handling md, _ := metadata.FromIncomingContext(ctx) outCtx := metadata.NewOutgoingContext(ctx, md)
var header, trailer metadata.MD resp, err := s.client.Ping(outCtx, ping, grpc.Header(&header), grpc.Trailer(&trailer)) grpc.SendHeader(ctx, header) grpc.SetTrailer(ctx, trailer) return resp, err
Streaming Calls Unary calls Client streaming calls Server streaming calls
Bi-directional streaming
Streaming Service message Counter { int32 counter = 1; }
service TestService { rpc Counter(Empty) returns (stream Counter) {} }
Streaming Proxy (½) ctx, cancel := context.WithCancel(srv.Context()) defer cancel() cli,
err := s.client.Counter(ctx, in) if err != nil { return err } ...
Streaming Proxy (½) for { msg, err := cli.Recv() switch
{ case err == io.EOF: return nil case err != nil: return err } err = srv.Send(msg) if err != nil { return err } }
None
Ways out Code generation Libraries, common code, ...
Protobuf Update (v2) message Ping { string value = 1;
int counter = 2; } message Pong { string value = 1; int counter = 2; } service TestService { rpc PingPong(Ping) returns (Pong) {} }
Version Mismatch gRPC backend API Gateway v1 v2 Ping value:
“foo” counter: 42 Ping value: “foo” counter: 42 Pong value: “bar” counter: 24 Pong value: “bar” counter: 24
Solution grpc.CustomCodec(grpc.Codec) grpc.UnknownServiceHandler(grpc.StreamHandler) grpc.NewClientStream(context.Context, *StreamDesc, *ClientConn, method string)
grpc.Codec type Codec interface { // Marshal returns the wire
format of v. Marshal(v interface{}) ([]byte, error) // Unmarshal parses the wire format into v. Unmarshal(data []byte, v interface{}) error }
Raw Codec type frame struct { payload []byte } func
(c *rawCodec) Marshal(v interface{}) ([]byte, error) { out, ok := v.(*frame) if !ok { return fmt.Errorf("expected frame") } return out.payload, nil } func (c *rawCodec) Unmarshal(data []byte, v interface{}) error { dst, ok := v.(*frame) if !ok { return fmt.Errorf("expected frame")} dst.payload = data return nil }
grpc.UnknownServiceHandler grpc.NewServer( grpc.CustomCodec(proxy.Codec()), grpc.UnknownServiceHandler(handler)) func handler(srv interface{}, serverStream grpc.ServerStream) error
{ fullMethodName, ok := grpc.MethodFromServerStream(serverStream) ... }
grpc.NewClientStream func handler(srv interface{}, serverStream grpc.ServerStream) error { conn, err
= grpc.Dial(addr, grpc.WithCodec(proxy.Codec())) clientStream, err = grpc.NewClientStream( ctx, &grpc.StreamDesc{ ServerStreams: true, ClientStreams: true, }, conn, fullMethodName) // copy clientStream <> serverStream }
Transparent gRPC Proxy Flow API Gateway grpcServerStream grpcClientStream Recv() Recv()
Send() Send()
Proxying one → many Aggregating responses Encoding errors Attributing result
to a backend
Response Metadata message ResponseMetadata { string upstream_node = 1; string
upstream_error = 2; } message Pong { ResponseMetadata metadata = 99; string value = 1; }
Enriching Response gRPC backend node-1 API Gateway Pong value: “bar”
Pong value: “bar” metadata: upstream_node: node_1
Protobuf Glue Pong value: “bar” (1) Pong value: “bar” (1)
metadata: (99) upstream_node: node_1 (1) Pong metadata: (99) upstream_node: node_1 (1) (type: bytes, field: 1, length: 3): “bar” (type: bytes, field: 99, length: N): [(type: bytes, field: 1, length: 6): “node_1”] (type: bytes, field: 1, length: 3): “bar” (type: bytes, field: 99, length: N): [(type: bytes, field: 1, length: 6): “node_1”] protobuf serialization: messages:
Embedding Errors gRPC backend API Gateway Ping value: “foo” Pong
metadata: upstream_node: node_1 upstream_error: ECONNREFUSED connection refused
Server Streaming API Gateway Ping value: “foo” Pong metadata: upstream_node:
node_1 upstream_error: ECONNREFUSED Pong value: “bar” metadata: upstream_node: node_2
Unary Calls API Gateway Ping value: “foo” Pong metadata: upstream_node:
node_1 upstream_error: ECONNREFUSED Pong value: “bar” metadata: upstream_node: node_2
Unary Protobuf Definition message ResponseMetadata { string upstream_node = 99;
string upstream_error = 100; } message Pong { ResponseMetadata metadata = 99; string value = 1; } message PongResponse { repeated Pong messages = 1; }
Protobuf Scissors PongResponse messages: (1) - Pong: value: “bar” (1)
(type: bytes, field: 1, length: N): [(type: bytes, field: 1, length: 3): bar] PongResponse messages: (1) - Pong: value: “bar” (1) metadata: (99) u_node: node_1 (1) (type: bytes, field: 1, length: N’): [(type: bytes, field: 1, length: 3): bar (type: bytes: field: 99, length: K): [(type: bytes: field: 1, length: 6): node_1 ]
grpc-proxy library https://github.com/talos-systems/grpc-proxy https://pkg.go.dev/github.com/talos-systems/grpc-proxy Thank you! @smira (https://github.com/smira) Talos Systems
Q&A