Xây dựng Login gRPC API với Node.js và Express (Phần 1)


Lời nói đầu
gRPC là công nghệ giao tiếp máy chủ-máy khách (client-server) phát triển bởi Google. Nó được thiết kế để tối ưu hóa hiệu suất và độ tin cậy trong việc giao tiếp giữa các dịch vụ phân tán, đặc biệt là trong môi trường microservices.

gRPC là gì?
gRPC là một framework RPC mã nguồn mở, hiện đại và hiệu năng cao mà có thể chạy trên bất kỳ môi trường nào. Framework này được Google khởi công phát triển vào năm 2015, đến 08/2016 thì được phát hành chính thức. Đây được cho là một thế hệ tiếp theo của RPC (Remote Procedure Calls) đặc biệt là trong mô hình Microservices.

Vì sao cần gRPC?
Ví dụ 2 service đang trao đổi JSON

Dưới thời huy hoàng và phát triển rực rỡ từ REST API, cơ bản là giao tiếp giữa client và server đã được giải quyết khá tốt. Nhưng dưới thời đại Microservices, rõ ràng chúng ta cần một phương pháp tốt hơn để tăng tải và thông lượng giữa các services.

Có thể các bạn sẽ không thấy đây là một vấn đề chẳng đáng để bận tâm xử lý, đặc biệt khi hệ thống có ít services, ít server/node. Ở đây chúng ta đang nói đến rất nhiều services và tải đang rất cao. Ví dụ vài trăm service và tải đâu đó ở ngưỡng trên 100k CCU – Concurrent users (số lượng user đang hoạt động cùng một thời điểm).

Khi đó nếu một request cần phải tổng hợp dữ liệu qua nhiều services. Ở mỗi đầu service khi nhận các request trung gian này, chúng phải encode và decode liên tục (VD: JSON data). Việc này có thể gây quá tải cho các CPU. Lẽ ra CPU nên dành cho việc khác quan trọng hơn là chỉ vì en/code dữ liệu trung gian.

Ý tưởng về việc làm thế nào để các service giao tiếp với nhau với tốc độ cao nhất, giảm tải encode/decode data chính là lý do thúc đẩy gRPC ra đời.

RPC không phải REST API

Hẳn là các bạn đang tự hỏi tại sao không phải gAPI, gREST mà lại là gRPC. Vì đơn giản là framework này chuyên dành cho RPC. Mà RPC là “thủ tục gọi từ xa” (Remote Procedure Call). 

RPC có từ rất lâu rồi, trước khi có REST API rất nhiều. Hồi đó lập trình viết hàm, gọi hàm trên một codebase (local procedure).

Nhưng rồi cũng sẽ có lúc những procedure này cần tái sử dụng nhiều hơn, hoặc “cách ly” nó để có tải cao hơn. Như vậy việc sử dụng lời gọi từ xa (remote call) là đương nhiên.

Bạn có thể dùng kỹ thuật lập trình mạng thông thường để gởi và nhận các gói tin thực hiện RPC. Tuy nhiên các developer luôn khao khát những phương thức dễ dàng hơn, chuẩn hoá hơn. Từ khi REST API ra đời và trở nên phổ biến, RPC xài luôn REST API để implement phương thức giao tiếp. Cái này được gọi là: RPC-based APIs.

Sự khác biệt lớn nhất đó là:
  • REST API: Client và Server cần trao đổi state thông qua các resource được trả về. Do đó các response trả về thường là một resource.
  • RPC: Client cần server thực hiện tính toán hoặc trả về một thông tin cụ thể nào đó. Bản chất giống y như ta đang gọi hàm, chỉ là hàm đó ở máy chủ khác hoặc service khác. Từ đó response trả về chỉ là kết quả của “hàm” thôi, không hơn, không kém.
Về mindset, nếu bạn đang muốn lấy thông tin users với ID = 1. REST API trả về full resource object user với ID = 1. Nhưng nếu bạn muốn tính tổng thu nhập của user = 1 trong tháng này, với RPC thì trả về 1 số tổng thu nhập là đủ.

Nhưng REST API thường trả về 1 resource nào đó có chứa thông tin tổng thu nhập của user (VD là resource user có thêm key “total_revenue”).

Nếu bạn vẫn chưa hiểu khác nhau chỗ nào, không sao hết, việc này không quan trọng. Nhưng hãy nhớ về các method của REST API chỉ tập trung vào tạo mới, đọc, sửa và xoá resource. Nếu vậy muốn resource làm một cái gì đó hoặc tính toán cụ thể cái gì đó thì chính là RPC-base APIs.

Hình dáng của RPC-base APIs trong thực tế:
  • POST /songs/:id/play (play bài hát, thành công thì return true hoặc 1)
  • GET /songs/:id/calculate_total_views (trả về con số tổng lượt xem của bài hát)

gRPC hoạt động như thế nào?

Quay lại với câu chuyện tăng tải cho cả hệ thống nhiều services (hay Microservices), Google đã phát triển 2 thứ:
  1. Một giao thức mới để tối ưu các connection, đảm bảo dữ liệu đi trao đổi liên tục với ít băng thông nhất có thể.
  2. Một định dạng dữ liệu mới để 2 đầu service (hoặc client và server) có thể hiểu được các message của nhau mà ít phải encode/decode.
Đầu tiên Google phát triển một giao thức thay thế cho HTTP/1.1 với tên gọi SPDY. Sau này giao thức này được open source thậm chí chuẩn hoá, lấy làm nền móng cho giao thức HTTP/2. Khi có HTTP/2 rồi thì giao thức SPDY ngừng phát triển. gRPC chính thức hoạt động trên HTTP/2 luôn từ sau năm 2015.

HTTP/2 sẽ hoạt động rất tốt với binary thay vì là text. Vì thế Google phát minh kiểu dữ liệu binary mới với tên gọi: Protobuf (tên đầy đủ là Protocol Buffers).

Một số lưu ý trong gRPC
  • gRPC nên dùng để giao tiếp backend to backend. CPU không gánh nhiều cost cho encode/decoding mỗi đầu nữa. Tuy nhiên đặc tính mỗi đầu cần import file model chung (gen từ protobuf file) nên nếu update thì phải update đủ. Việc này vô tình tạo dependency cho các bên sử dụng, có thể nhiều bạn sẽ không thích điều này.
  • gRPC thường được đấu nối vào service mesh (hoặc sidecar trong Microservices), để có thể xử lý connection HTTP/2 cũng như monitoring nó tốt hơn.
  • gRPC support streaming 2 đầu nên rất được lòng các fan streaming system, event sourcing (stream event). VD: gRPC được sử dụng trong: vitess, neo4j vì lý do trên.
  • gRPC nếu dùng cho frontend-backend thì thật sự rất cân nhắc. Connection statefull tạo nhiều sự khó chịu trong scale tải hoặc bạn có thể bị Head of line blocking (HOL).
  • gRPC vẫn có thư viện gRPC Gateway chính chủ của Google. Tức là các bạn vẫn có thể chạy 1 port http/1 cho REST và 1 port http/2 của gRPC đồng thời. Như vậy không phải là không có cách để quay về REST thân quen, nhưng đương nhiên là đi qua proxy service nên cồng kềnh hơn.

Kết thúc phần 1 các bạn xem tiếp phần 2 tại đây

Nhận xét

Bài đăng phổ biến từ blog này

Cài đặt SSL cho website sử dụng certbot

Xây dựng một hệ thống comment real-time hoặc chat đơn giản sử dụng Pusher

CÁC BÀI TẬP SQL CƠ BẢN - PART 1

Xây dựng một hệ thống tracking hành vi người dùng (phần 1)

Xây dựng một hệ thống tracking hành vi người dùng (phần 2)

Enterprise architecture trên 1 tờ A4

Web caching (P2)

Bàn về async/await trong vòng lặp javascript

Web caching (P1)

Cài đặt môi trường để code website Rails