[G1-Sync] Manual knowledge update

This commit is contained in:
Antigravity Agent
2026-05-10 22:08:15 +09:00
parent 21ac3ed255
commit 504fd5fb42
3011 changed files with 380280 additions and 206977 deletions
@@ -0,0 +1,298 @@
---
id: backend-grpc-streaming-deep
title: gRPC Streaming — bidirectional / server / client
category: Coding
status: draft
source_trust_level: B
verification_status: conceptual
created_at: 2026-05-09
updated_at: 2026-05-09
tags: [backend, grpc, streaming, vibe-coding]
tech_stack: { language: "TS / Go", applicable_to: ["Backend"] }
applied_in: []
aliases: [gRPC streaming, bidi, server stream, client stream, Protocol Buffers, Connect-RPC, Buf]
---
# gRPC Streaming Deep
> gRPC 의 큰 차별점. **4 mode: unary, server stream, client stream, bidi**. HTTP/2 + Protobuf.
## 📖 핵심 개념
- HTTP/2 multiplexing.
- Protobuf binary (작은).
- Type-safe (proto → 매 언어).
- Bidi 가 WebSocket 식.
## 💻 코드 패턴
### Proto definition
```protobuf
syntax = 'proto3';
service ChatService {
rpc Send(Message) returns (Ack); // unary
rpc Subscribe(Filter) returns (stream Message); // server stream
rpc Upload(stream Chunk) returns (FileInfo); // client stream
rpc Chat(stream Message) returns (stream Message); // bidi
}
```
### Server (TS, Connect-RPC)
```ts
import { ConnectRouter } from '@connectrpc/connect';
import { ChatService } from './gen/chat_connect';
export default (router: ConnectRouter) =>
router.service(ChatService, {
async send(req) {
return { ack: true };
},
async *subscribe(req) {
for (let i = 0; i < 100; i++) {
yield { text: `msg ${i}` };
await sleep(1000);
}
},
async upload(req) {
let total = 0;
for await (const chunk of req) {
total += chunk.data.length;
}
return { size: total };
},
async *chat(req) {
for await (const msg of req) {
yield { text: 'echo: ' + msg.text };
}
},
});
```
### Client (TS)
```ts
import { createPromiseClient } from '@connectrpc/connect';
const client = createPromiseClient(ChatService, transport);
// Server stream
for await (const msg of client.subscribe({ topic: 'news' })) {
console.log(msg.text);
}
// Client stream
async function* chunks() {
for (const chunk of file) yield { data: chunk };
}
const result = await client.upload(chunks());
```
### Connect-RPC (modern)
```
gRPC + gRPC-Web + Connect protocol 동시.
- Browser 에서 직접 (no envoy).
- HTTP/1.1 + HTTP/2 둘 다.
- TS-friendly.
→ gRPC 의 modern.
```
### Buf (toolchain)
```yaml
# buf.gen.yaml
version: v2
plugins:
- remote: buf.build/connectrpc/es
out: gen
- remote: buf.build/bufbuild/es
out: gen
```
```bash
buf generate
buf lint
buf breaking --against '.git#branch=main'
```
→ gRPC 의 npm.
### Bidi streaming
```ts
// Server
async *chat(reqs) {
for await (const msg of reqs) {
// 매 client message 받음.
yield { reply: process(msg) };
}
}
// Client
async function* messages() {
yield { text: 'hi' };
await sleep(1000);
yield { text: 'how are you?' };
}
for await (const reply of client.chat(messages())) {
console.log(reply);
}
```
→ Real-time bidirectional. Chat / game.
### Server stream use case
```
- Server-sent updates.
- Live data feed.
- Search results (incremental).
- Log streaming.
```
### Client stream use case
```
- Large upload (chunks).
- Sensor data submission.
- Telemetry batch.
```
### Cancellation
```ts
const ac = new AbortController();
setTimeout(() => ac.abort(), 5000);
for await (const msg of client.subscribe({}, { signal: ac.signal })) {
// ...
}
```
→ Stream 중단.
### Error handling
```ts
try {
for await (const msg of stream) {
// ...
}
} catch (e) {
if (e.code === Code.Cancelled) ...;
if (e.code === Code.DeadlineExceeded) ...;
}
```
### Deadline
```ts
const r = await client.send(req, { timeoutMs: 5000 });
```
### Interceptor (middleware)
```ts
const authInterceptor: Interceptor = (next) => async (req) => {
req.header.set('Authorization', `Bearer ${token}`);
return next(req);
};
const transport = createConnectTransport({
baseUrl: '...',
interceptors: [authInterceptor],
});
```
### vs REST
```
REST:
- HTTP/1.1.
- JSON (verbose).
- Stateless.
- 큰 ecosystem.
gRPC:
- HTTP/2 multiplexing.
- Protobuf (작은).
- Streaming native.
- Type-safe (codegen).
→ Internal microservice = gRPC.
Public API / web = REST / GraphQL.
```
### vs WebSocket
```
WebSocket: bidi 만, schema 없음.
gRPC bidi: typed schema + RPC.
→ gRPC 가 strict schema. WS 가 free-form.
```
### vs GraphQL Subscription
```
GraphQL Subscription: query 식 + WS.
gRPC streaming: RPC 식 + HTTP/2.
→ Different model. 같은 use case 가 가능.
```
### Performance
```
gRPC 가 REST 보다 7-10x 빠름 (binary + multiplex).
Streaming = 큰 throughput (multiple parallel).
HTTP/2 head-of-line blocking 가 약간 (TCP level).
→ Internal high-performance.
```
### gRPC-Web
```
Browser 가 native gRPC 안 됨.
- gRPC-Web (Envoy 가 transcode).
- 또는 Connect (native).
→ Connect 가 modern (envoy 없음).
```
### Production
```
- Envoy (proxy).
- gRPC LB (HTTP/2 LB).
- Auth interceptor.
- Tracing (OpenTelemetry).
- Monitoring (latency p99, error rate).
```
### Common pitfall
```
- gRPC LB 가 HTTP/2 aware 안 = sticky.
- Stream 의 backpressure 무시.
- Deadline 없음 = hang.
- Compression 가 default off (큰 payload 가 비효율).
- Schema breaking change.
```
## 🤔 의사결정 기준
| 작업 | 추천 |
|---|---|
| Internal microservice | gRPC |
| Streaming | gRPC bidi |
| Web client | Connect / gRPC-Web |
| Public API | REST + OpenAPI |
| Real-time chat | gRPC bidi 또는 WS |
| File upload | gRPC client stream |
## ❌ 안티패턴
- **gRPC + REST 둘 다 같은 service**: complexity.
- **No deadline**: hang.
- **gRPC + non-HTTP/2 LB**: sticky.
- **모든 거 unary (streaming 안 사용)**: gRPC 의 가치 ↓.
- **Schema breaking change**: client 깨짐.
## 🤖 LLM 활용 힌트
- Connect-RPC 가 modern (browser-friendly).
- Buf 가 toolchain.
- 4 mode (unary, server, client, bidi).
- Internal microservice 의 default.
## 🔗 관련 문서
- [[Backend_gRPC_Patterns]]
- [[Backend_GraphQL_Federation]]
- [[Backend_WebSocket_Production]]