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
Прозрачный 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
170
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
250
Learning Unsung Gotchas of Go - Rashmi Nagpal
gopherconrussia
1
300
Из Python в Go и обратно - Андрей Минкин
gopherconrussia
0
180
Оптимизация работы с PostgreSQL в Go: от 50 до 5000 RPS - Иван Осадчий
gopherconrussia
0
210
Пакет embed: распаковка знаний - Илья Данилкин
gopherconrussia
0
280
За пару мгновений до main() - Олег Ковалев
gopherconrussia
0
170
Тестирование в Go c Ginkgo и Gomega - Александр Егурнов
gopherconrussia
0
150
Building an Autoscaling HTTP Proxy for Kubernetes - Aaron Schlesinger
gopherconrussia
0
160
Designing Pluggable Idiomatic Go Applications – Mark Bates
gopherconrussia
0
81
Other Decks in Programming
See All in Programming
Observability in Practice:Grafana 與 Edge Device SRE 的那些事
blueswen
0
170
才能?センス?知らん、 続けたもん勝ちだ。-- 結婚・出産・癌を越えてなお、私がプロダクトを創り続ける理由
16bitidol
1
280
スマートグラスで並列バイブコーディング
hyshu
0
260
LLMによるContent Moderationの本番運用の裏側と品質担保への挑戦
suikabar
3
750
そのテスト、説明できますか?~LWテスト戦略FW~のご紹介
nakahara
0
160
Signal Forms: Details & Live Coding @enterJS 2026 in Mannheim
manfredsteyer
PRO
0
190
Spec Driven Development | AI Summit Lisbon
danielsogl
PRO
0
210
Oxlintのカスタムルールの現況
syumai
6
1.2k
IBM Bobを活用したレガシーアプリの最新化
oniak3ibm
PRO
1
210
Even G2とAWSで推しのエージェントを召喚しよう!
har1101
1
120
コンテキストの使い捨てをやめる — ビジネスルール駆動開発と miko —
ioki
0
230
技術記事、 専門家としてのプログラマ、 言語化
mizchi
13
6.5k
Featured
See All Featured
How to optimise 3,500 product descriptions for ecommerce in one day using ChatGPT
katarinadahlin
PRO
1
3.6k
GraphQLとの向き合い方2022年版
quramy
50
15k
A designer walks into a library…
pauljervisheath
211
24k
Designing for humans not robots
tammielis
254
26k
Designing Powerful Visuals for Engaging Learning
tmiket
1
430
Building AI with AI
inesmontani
PRO
1
1.1k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
666
130k
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
12
1.7k
The SEO Collaboration Effect
kristinabergwall1
1
490
How to Ace a Technical Interview
jacobian
281
24k
Marketing Yourself as an Engineer | Alaka | Gurzu
gurzu
0
240
WCS-LA-2024
lcolladotor
0
650
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