1. REST API Cơ Bản
HTTP Methods Cơ Bản
GET /api/v1/users # Đọc data
POST /api/v1/users # Tạo mới
PUT /api/v1/users/123 # Cập nhật toàn bộ (replace)
DELETE /api/v1/users/123 # Xóa
PATCH - Cập nhật một phần thay vì toàn bộ resource:
PATCH /api/v1/users/123
{"email": "newemail@example.com"} # Chỉ thay đổi email
Thiết Kế URL Chuẩn
✅ RESTful:
GET /users (collection)
GET /users/123 (item)
GET /users/123/orders (nested resource)
❌ Không RESTful:
GET /getUsers
POST /createUser
GET /user-details?id=123
Status Codes Cần Biết
Success (2xx):
200: GET requests
201: POST tạo mới thành công
204: DELETE thành công (no content)
Client Errors (4xx) - Phổ biến nhất:
400: Bad request (validation lỗi, json lỗi, missing required fields )
401: Chưa đăng nhập
403: Đã đăng nhập nhưng không có quyền
404: Không tìm thấy
Server Errors (5xx) - Cơ bản:
500: Lỗi server (lỗi code)
502: Bad gateway (proxy/load balancer lỗi)
503: Service unavailable (bảo trì/quá tải)
Status Codes Nâng Cao & Ứng Dụng
3xx Redirection - Chuyển hướng và caching:
// 301: API version migration
GET /api/v1/users → 301 Moved Permanently → /api/v2/users
// 304: Resource chưa thay đổi (caching)
If-None-Match: "etag-12345" → 304 Not Modified (tiết kiệm bandwidth)
400 vs 409 vs 422 - Phân biệt lỗi client:
400 Bad Request - Request malformed
409 Conflict - Xung đột business rules hay data (User A updated docuemnt A version 1 thành version 2, User B update document A version thì sẽ bị conflict)
422 Unprocessable Entity - Data không hợp lệ sai format/logic sai
Quy tắc phân biệt:
400: Request không parse được (syntax, structure)
409: Xung đột với business rules/dữ liệu hiện có
422: Request parse được nhưng validation fail
Khi nào cần chi tiết 409/422?
- Banking/Financial systems cần client biết chính xác lỗi để retry logic (409: account locked - không retry, 422: invalid format - fix và retry).
- E-commerce APIs cần frontend handle khác nhau (409: out of stock - show "sold out", 422: invalid quantity - show validation error).
- Public APIs như GitHub/Stripe cần detailed error codes để third-party developers debug dễ dàng. Còn internal APIs thông thường chỉ cần 400 + descriptive message là đủ.
429 Too Many Requests - Rate limiting protection: GET /api/v1/users → 429 + Retry-After: 3600
- Tại sao cần Rate Limiting: Chống spam/bot, bảo vệ server quá tải, sử dụng công bằng, kiểm soát chi phí.
- Strategies: Per user (1000/hour), per IP (100/min), per API key (tier-based limits).
503 Service Unavailable - Bảo trì hoặc quá tải:
504 Gateway Timeout - Upstream service không phản hồi:
2.Thực Hành - Patterns Thiết Kế API
HTTP Headers Cơ Bản Cần Biết
// Request Headers
Accept: application/json # Client muốn nhận format gì
Content-Type: application/json # Format của request body
Authorization: Bearer eyJhbGciOiJIUzI1NiI # Authentication token
User-Agent: MyApp/1.0.0 # Định danh client
X-Request-ID: req-123456 # Request tracing
// Response Headers
Content-Type: application/json # Format của response
Cache-Control: public, max-age=3600 # Chỉ thị caching
X-RateLimit-Remaining: 999 # Thông tin rate limit
Location: /api/v1/users/124 # Vị trí resource (201 responses)
API Gateway là một thành phần quan trọng trong kiến trúc microservices, đóng vai trò là điểm truy cập duy nhất cho các client. Việc sử dụng API Gateway mang lại sự đánh đổi lớn giữa khả năng kiểm soát tập trung và rủi ro trở thành điểm lỗi duy nhất (Single Point of Failure).
Lợi ích: Kiểm soát tập trung (Centralized Control)
API Gateway hoạt động như một "cổng vào" chính, cho phép bạn quản lý và xử lý các vấn đề chung của hệ thống một cách hiệu quả tại một nơi duy nhất. Điều này giúp các microservices bên trong có thể tập trung hoàn toàn vào logic nghiệp vụ của chúng.
-
Tăng cường bảo mật: Bạn có thể xử lý tập trung việc xác thực và phân quyền (Authentication & Authorization) ngay tại Gateway.
-
Quản lý lưu lượng truy cập: Dễ dàng áp dụng các chính sách như giới hạn tốc độ truy cập (Rate Limiting) để bảo vệ các services khỏi việc bị quá tải.
-
Giám sát và ghi log: Tất cả các request đi qua Gateway đều có thể được ghi log và giám sát, giúp bạn có cái nhìn tổng quan về hiệu suất và tình trạng của toàn bộ hệ thống.
-
Định tuyến linh hoạt: Gateway chịu trách nhiệm định tuyến các request đến đúng microservice. Điều này giúp ẩn đi cấu trúc phức tạp bên trong và cho phép bạn thay đổi vị trí của các services một cách dễ dàng.
-
Chuyển đổi giao thức: Gateway có thể chuyển đổi giao thức giữa client (ví dụ: HTTP/REST) và backend services (ví dụ: gRPC, Message Queue), giúp hệ thống linh hoạt hơn.
Rủi ro: Điểm lỗi duy nhất (Single Point of Failure)
Đây là mặt trái của việc kiểm soát tập trung. Nếu API Gateway gặp sự cố, toàn bộ lưu lượng truy cập đến các microservices sẽ bị chặn. Điều này có thể dẫn đến việc toàn bộ hệ thống trở nên không khả dụng.
Các nguyên nhân có thể gây ra lỗi cho Gateway bao gồm:
-
Lỗi phần mềm hoặc cấu hình.
-
Quá tải tài nguyên (CPU, bộ nhớ) do lượng truy cập tăng đột biến.
-
Tấn công từ chối dịch vụ (DDoS).
Đánh đổi và Giải pháp
Rủi ro về "Điểm lỗi duy nhất" là một sự đánh đổi cần thiết để đổi lấy những lợi ích to lớn của "kiểm soát tập trung". Tuy nhiên, rủi ro này không phải là không thể giải quyết. Các kỹ sư phần mềm thường áp dụng các giải pháp sau để giảm thiểu rủi ro:
-
Tính sẵn sàng cao (High Availability): Triển khai API Gateway dưới dạng một cụm (cluster) với nhiều instance. Sử dụng Load Balancer (cân bằng tải) để phân phối request và tự động chuyển hướng khi một instance gặp lỗi.
-
Độ co giãn (Scalability): Thiết kế Gateway để có thể dễ dàng mở rộng theo chiều ngang (thêm instance) khi lưu lượng truy cập tăng.
-
Triển khai các chính sách bền bỉ: Áp dụng các mẫu thiết kế như Circuit Breaker và Timeout để ngăn chặn Gateway khỏi việc bị quá tải bởi một microservice đang gặp sự cố.
"Sync cho consistency, async cho resilience" là một nguyên tắc cơ bản và cực kỳ quan trọng trong việc thiết kế kiến trúc microservices. Nó tóm gọn cách chúng ta nên lựa chọn phương thức giao tiếp giữa các services để đạt được sự cân bằng giữa tính toàn vẹn dữ liệu và khả năng chịu lỗi.
Đồng bộ (Sync) cho tính nhất quán (Consistency)
Phương thức giao tiếp đồng bộ là khi một service gửi yêu cầu và chờ đợi phản hồi ngay lập tức. Đây là lựa chọn phù hợp khi bạn cần đảm bảo tính nhất quán của dữ liệu một cách tức thời.
-
Tại sao: Khi một service gọi API của một service khác, nó sẽ biết ngay lập tức kết quả của yêu cầu đó (thành công hay thất bại). Nếu service B trả về mã lỗi, service A có thể ngay lập tức xử lý lỗi đó, ví dụ như hoàn tác lại giao dịch hoặc thông báo cho người dùng.
-
Ví dụ: Một hệ thống thương mại điện tử cần xử lý thanh toán. Khi người dùng bấm nút "Thanh toán", service Payment sẽ gọi service Banking để thực hiện giao dịch. Service Payment cần phải chờ phản hồi từ Banking để biết giao dịch có thành công hay không. Phản hồi này đảm bảo rằng trạng thái đơn hàng và tài khoản ngân hàng của người dùng là nhất quán tại thời điểm đó. Nếu giao dịch thất bại, service Payment có thể ngay lập tức thông báo cho người dùng và không tạo đơn hàng.
Bất đồng bộ (Async) cho tính bền bỉ (Resilience)
Phương thức giao tiếp bất đồng bộ là khi một service gửi một thông điệp (message) và không chờ phản hồi. Nó sẽ tiếp tục công việc của mình. Cách tiếp cận này giúp tăng tính bền bỉ và khả năng chịu lỗi của hệ thống.
-
Tại sao: Các services được tách biệt hoàn toàn với nhau. Nếu service B gặp sự cố, service A vẫn có thể gửi thông điệp vào hàng đợi tin nhắn. Thông điệp này sẽ được lưu trữ và xử lý khi service B hoạt động trở lại. Điều này ngăn ngừa "hiệu ứng domino" (cascading failure), khi lỗi của một service không làm sập toàn bộ hệ thống.
-
Ví dụ: Sau khi khách hàng đã đặt đơn hàng thành công, service Order có thể phát ra một sự kiện "đơn hàng đã được tạo" vào một hàng đợi tin nhắn.
-
Service Email Notification sẽ lấy thông điệp này và gửi email xác nhận.
-
Service Inventory sẽ lấy thông điệp này và cập nhật tồn kho. Nếu service Email Notification đang gặp sự cố, việc gửi email sẽ bị hoãn lại, nhưng đơn hàng vẫn được xử lý và tồn kho vẫn được cập nhật khi service này hoạt động trở lại. Điều này giúp hệ thống chính vẫn hoạt động bình thường, đảm bảo trải nghiệm người dùng không bị gián đoạn.
Độ trễ mạng (Network Latency)
-
Thách thức: Trong kiến trúc nguyên khối (monolith), các hàm gọi nhau là các lời gọi trong bộ nhớ, diễn ra gần như tức thì. Ngược lại, trong microservices, một yêu cầu từ người dùng có thể kích hoạt nhiều cuộc gọi mạng giữa các services khác nhau. Mỗi cuộc gọi mạng đều có một độ trễ nhất định. Những độ trễ nhỏ này tích lũy lại có thể làm tăng đáng kể thời gian phản hồi tổng thể của hệ thống.
-
Ví dụ: Khi người dùng truy cập trang chủ, hệ thống cần gọi service A để lấy thông tin sản phẩm, service B để lấy thông tin khuyến mãi và service C để lấy thông tin giỏ hàng. Mỗi cuộc gọi này đều mất thời gian, và tổng thời gian chờ đợi sẽ là tổng hợp của các độ trễ đó, làm ảnh hưởng đến trải nghiệm người dùng.
-
Cách xử lý: Sử dụng các kỹ thuật như caching (bộ nhớ đệm) để giảm số lượng cuộc gọi mạng, sử dụng giao tiếp bất đồng bộ cho các tác vụ không cần phản hồi tức thì, và tối ưu hóa hạ tầng mạng.
Tính nhất quán dữ liệu (Data Consistency)
-
Thách thức: Trong kiến trúc nguyên khối, bạn có một cơ sở dữ liệu duy nhất và có thể sử dụng giao dịch ACID để đảm bảo tính nhất quán dữ liệu tức thời. Trong microservices, mỗi service thường có cơ sở dữ liệu riêng, nên không thể thực hiện một giao dịch duy nhất trên nhiều cơ sở dữ liệu.
-
Đánh đổi: Microservices buộc bạn phải chấp nhận tính nhất quán cuối cùng (eventual consistency) thay vì tính nhất quán tức thời. Dữ liệu sẽ nhất quán sau một khoảng thời gian, nhưng có thể có một khoảnh khắc ngắn hệ thống ở trạng thái không nhất quán.
-
Ví dụ: Khi người dùng đặt hàng, service Order tạo đơn hàng. Sau đó, nó phát ra một sự kiện để service Inventory trừ đi số lượng sản phẩm. Nếu service Inventory đang ngoại tuyến, số lượng tồn kho sẽ không được cập nhật ngay lập tức. Sẽ có một khoảng thời gian ngắn mà dữ liệu giữa hai services không đồng bộ.
-
Cách xử lý: Sử dụng các mẫu thiết kế như Saga Pattern để quản lý các giao dịch phức tạp trên nhiều services và sử dụng Message Queue hoặc Event Bus để đảm bảo các thay đổi dữ liệu được truyền tải một cách đáng tin cậy.
Độ phức tạp vận hành (Operational Complexity)
- Thách thức: Thay vì quản lý một ứng dụng duy nhất, bạn phải quản lý hàng chục hoặc hàng trăm services độc lập. Mỗi service cần được triển khai, giám sát và gỡ lỗi riêng.
Các vấn đề cụ thể:
-
Triển khai (Deployment): Việc tự động hóa quy trình triển khai cho nhiều services là một thách thức lớn.
-
Giám sát (Monitoring): Cần có hệ thống giám sát toàn diện để theo dõi trạng thái, hiệu suất và log của từng service. Logging tập trung và giám sát phân tán (distributed tracing) trở nên vô cùng cần thiết.
-
Gỡ lỗi (Debugging): Khi một lỗi xảy ra, việc truy tìm nguyên nhân qua nhiều services là rất khó khăn nếu không có các công cụ phù hợp.
-
Cách xử lý: Áp dụng một văn hóa DevOps mạnh mẽ, sử dụng các công cụ tự động hóa CI/CD, công nghệ container hóa (Docker, Kubernetes) và các giải pháp giám sát tiên tiến như Prometheus, Grafana, ELK Stack.
Rate Limiting
Cần triển khai cho public API, còn internal API thì vô tư. Hệ thống cloud nào đều có service rate limiting hết. Google Cloud thì có Google Armor, Amazon Cloud thì có AWS WAF (Web Application Firewall), AWS Shield. Thường chỉ triển khai trên môi trường Production và có đội ngũ riêng. Senior Dev, Leader hay Architecters cũng không được phép đụng vào môi trường Production.
Source: here