Network: REST/gRPC và DNS
8. REST vs gRPC
8.1 REST
REST (Representational State Transfer) không phải là protocol — đây là tập hợp nguyên tắc thiết kế API do Roy Fielding đề xuất năm 2000. Ý tưởng cốt lõi: mọi thứ là resource, và bạn thao tác resource đó bằng HTTP verbs.
HTTP Verbs và ý nghĩa:
GET /users → list users (safe, idempotent)
GET /users/1 → get user 1 (safe, idempotent)
POST /users → create user (not safe, not idempotent)
PUT /users/1 → replace user 1 (idempotent)
PATCH /users/1 → partial update (not always idempotent)
DELETE /users/1 → delete user 1 (idempotent)
Safe nghĩa là không thay đổi state. Idempotent nghĩa là gọi nhiều lần cho kết quả giống một lần — quan trọng cho retry logic.
HTTP Status Codes:
2xx: Success
200 OK, 201 Created, 204 No Content
3xx: Redirect
301 Moved Permanently, 302 Found, 304 Not Modified
4xx: Client Error
400 Bad Request, 401 Unauthorized, 403 Forbidden
404 Not Found, 409 Conflict, 429 Too Many Requests
5xx: Server Error
500 Internal Server Error, 502 Bad Gateway, 503 Service Unavailable
8.2 gRPC
gRPC (Google Remote Procedure Call) là framework RPC dùng Protocol Buffers để serialize data và HTTP/2 để truyền tải. Thay vì thiết kế xung quanh resources như REST, gRPC thiết kế xung quanh actions (remote procedure calls).
syntax = "proto3";
service UserService {
rpc GetUser (GetUserRequest) returns (User);
rpc ListUsers (ListUsersRequest) returns (stream User); // server streaming
rpc CreateUsers (stream UserRequest) returns (Summary); // client streaming
rpc Chat (stream Message) returns (stream Message); // bidirectional
}
message User {
int32 id = 1;
string name = 2;
string email = 3;
}
8.3 Protocol Buffers Wire Format
Protobuf encode data thành binary với cấu trúc [tag][value] cho mỗi field. Tag mã hóa cả field number lẫn kiểu dữ liệu. Kết quả nhỏ hơn JSON đáng kể.
Wire types:
0 = Varint (int32, int64, bool, enum)
1 = 64-bit (double, fixed64)
2 = Length-delimited (string, bytes, embedded messages)
5 = 32-bit (float, fixed32)
Ví dụ: User{id: 150, name: "Alice"}
Field 1 (id=150):
Tag = (1 << 3) | 0 = 0x08
Value 150 as varint: 0x96 0x01
Field 2 (name="Alice"):
Tag = (2 << 3) | 2 = 0x12
Length = 5, Bytes = 41 6c 69 63 65
Wire: 08 96 01 12 05 41 6c 69 63 65 → 10 bytes
JSON: {"id":150,"name":"Alice"} → 24 bytes
8.4 gRPC 4 loại streaming
gRPC hỗ trợ 4 kiểu giao tiếp, tất cả đều chạy trên HTTP/2 streams:
1. Unary — giống REST request/response
Client ──── request ────► Server
Client ◄─── response ─── Server
2. Server Streaming — server gửi nhiều messages
Client ──── request ────► Server
Client ◄─── stream ────── Server (nhiều messages)
Use case: download file chunks, live price feed
3. Client Streaming — client gửi nhiều messages
Client ──── stream ────► Server (nhiều messages)
Client ◄─── response ─── Server (sau khi nhận xong)
Use case: upload file chunks, batch inserts
4. Bidirectional Streaming — hai chiều đồng thời
Client ─── stream ──────► Server
Client ◄── stream ────── Server
Use case: chat, collaborative editing, game
8.5 REST vs gRPC — Khi nào dùng gì?
| REST | gRPC | |
|---|---|---|
| Protocol | HTTP/1.1 hoặc HTTP/2 | HTTP/2 bắt buộc |
| Format | JSON (human-readable) | Protobuf (binary, nhỏ hơn ~3-10x) |
| Schema | Optional (OpenAPI) | Bắt buộc (.proto file) |
| Streaming | Hạn chế | Native, 4 loại |
| Browser support | Tốt | Cần grpc-web proxy |
| Code generation | Hạn chế | Tuyệt vời (nhiều ngôn ngữ) |
| Debugging | Dễ (curl, browser) | Cần tool (grpcurl, Postman) |
| Use case | Public API, mobile | Microservices internal, high-perf |
9. DNS — Hệ thống phân giải tên miền
9.1 Kiến trúc phân cấp
DNS là hệ thống phân tán phân cấp. Không ai biết hết mọi domain — mỗi tầng chỉ biết tầng dưới nó.
Root Servers (13 logical, ~1000 physical)
→ Biết địa chỉ của các TLD servers
TLD Servers (Top-Level Domain)
.com, .org, .net, .vn...
→ Biết địa chỉ Authoritative servers của từng domain
Authoritative Name Servers
ns1.example.com, ns2.example.com
→ Biết IP thực sự của example.com và các subdomain
Recursive Resolver (ISP hoặc 8.8.8.8, 1.1.1.1)
→ Đứng giữa client và DNS hierarchy
→ Cache kết quả để tránh lặp lại toàn bộ chain
9.2 DNS Resolution Flow
Khi bạn gõ một domain lần đầu, browser phải đi qua toàn bộ chain. Sau đó kết quả được cache ở nhiều tầng để tránh lặp lại.
Browser muốn biết IP của "www.example.com":
1. Check browser cache (TTL còn không?)
2. Check OS cache (/etc/hosts, DNS cache)
3. Hỏi Recursive Resolver (8.8.8.8):
Resolver ──── "www.example.com?" ────────────────► Root Server
Resolver ◄─── "Hỏi .com TLD: 192.5.6.30" ─────── Root Server
Resolver ──── "www.example.com?" ────────────────► .com TLD Server
Resolver ◄─── "Hỏi ns1.example.com: 205.251.x.x" .com TLD Server
Resolver ──── "www.example.com?" ────────────────► ns1.example.com
Resolver ◄─── "IP là 93.184.216.34, TTL=3600" ─── ns1.example.com
4. Resolver cache kết quả 3600s (1 giờ)
5. Trả về client: 93.184.216.34
Tổng: ~50-200ms lần đầu, gần như 0ms nếu đã cached
9.3 DNS Record Types
| Record | Mô tả | Ví dụ |
|---|---|---|
| A | IPv4 address | example.com → 93.184.216.34 |
| AAAA | IPv6 address | example.com → 2606:2800::1 |
| CNAME | Alias to another name | www → example.com |
| MX | Mail server | example.com → mail.example.com (priority 10) |
| TXT | Text (SPF, DKIM, verification) | "v=spf1 include:..." |
| NS | Name server | example.com → ns1.example.com |
| SOA | Start of Authority | Zone metadata |
| SRV | Service locator | _grpc._tcp.example.com |
| PTR | Reverse DNS (IP→name) | 34.216.184.93.in-addr.arpa → example.com |
| CAA | Certificate Authority Authorization | "0 issue letsencrypt.org" |
9.4 DNS over HTTPS (DoH) và DNS over TLS (DoT)
DNS truyền thống dùng port 53, plaintext — ISP có thể đọc mọi DNS query của bạn, và MITM attack có thể giả mạo response.
DoT (DNS over TLS, port 853): encrypt DNS query trong TLS. ISP không đọc được nội dung, nhưng vẫn thấy kết nối đến port 853 — dễ block.
DoH (DNS over HTTPS, port 443): wrap DNS query trong HTTP/2 request. Không thể phân biệt với HTTPS thông thường → khó block hơn nhiều. Firefox và Chrome mặc định dùng DoH qua Cloudflare 1.1.1.1.
9.5 DNSSEC
DNS spoofing (hay cache poisoning) là kỹ thuật attacker chèn response giả mạo vào DNS cache — client hỏi bank.com, nhận về IP của attacker.
DNSSEC giải quyết bằng cách ký số toàn bộ DNS records, tạo chain of trust từ Root → TLD → Authoritative. Resolver có thể verify signature trước khi tin tưởng response.
Lưu ý quan trọng: DNSSEC không mã hóa — nó chỉ xác thực. ISP vẫn có thể đọc nội dung DNS query.