Giới thiệu về GRPC
August 6, 2021Bài viết trước đó mình có giới thiệu về microservices và 3 cách giao tiếp giữa các services, bạn có thể tìm đọc lại tại đây
RPC là một trong số 3 cách giao tiếp đó và bài viết này mình sẽ nói chi tiết hơn và cách thực hiện hóa nó nhé!
Đầu tiên cùng mình đặt vấn đề một chút. Microservices thực tế chỉ là các thành phần được phân chia và chạy một cách độc lập với nhau, nó có tên kỹ thuật một chút là service mà thôi. Trước đó thì bạn có thể thấy các máy tính được kết nối với nhau thông qua mạng LAN (Cái mạng mà bạn nối dây từ máy nọ sang máy kia ý), rộng hơn một chút là mạng internet, ừ thì không cần dây nhưng bạn vẫn kết nối được các máy với nhau từ xa thông qua chúng. Hay như website bạn thấy cũng là việc kết nối giữa client và server giữa trình duyệt web trên máy bạn đang đọc và server chứa mã nguồn và cơ sở dữ liệu của mình. Dù sao đi nữa thì bản chất vấn đề vẫn là trao đổi dữ liệu, giao tiếp thông tin như những chiếc điện thoại nói chuyện với nhau vậy. Phương thức trao đổi các loại có thể khác nhau nhưng chung quy nó sẽ là sử dụng một giao thức nào đó để liên lạc với nhau.
Vấn đề được nảy sinh nếu 2 thành phần cùng loại thì có thể dùng chung giao thức như 2 chiếc điện thoại, 2 chiếc máy tính, thì không nói làm gì, vậy giữa 2 services với nhau, có thể sử dụng nhiều ngôn ngữ khác nhau thì phải làm thế nào? Có thể bạn sẽ nghĩ tới interface, hay public api, một cái adapter nào đó, ổ cắm điện có thể kết nối mọi loại giác cắm. Ý tưởng nảy ra trong đầu bạn lúc này là hoàn toàn chính xác. Nó tóm gọn vào 2 vấn đề chính là làm sao để giao tiếp từ xa giữa các services, và làm sao để không phụ thuộc vào thành phần hay nền tảng của mỗi service.
Với vấn đề đầu tiên là giao tiếp từ xa, RPC ra đời, nó chính xác là viết tắt của từ Remote Procedure Calls, một loại giao thức giúp A giao tiếp được với B từ xa. Hãy nhìn vào hình vẽ để hiểu thêm
Một bên nói một bên nghe, cũng không có gì quá khó hiểu đúng không? Nhưng liệu bạn có thắc mắc chúng trao đổi với nhau bằng gì? Cũng như 2 chiếc điện thoại thì âm thanh chính là dạng tín hiệu truyền từ đầu này sang đầu kia, còn với RPC thì với những năm xưa rất xưa thì nó là xml, một loại định dạng văn bản xưa cũ dưới dạng các thẻ (tag) định danh. Bạn lại hỏi tiếp nó truyền như thế nào? Mình cũng lấy tiếp ví dụ điện thoại thì nó chạy bằng điện, hay hiện đại hơn là sóng thì với RPC nó dùng phương thức http (thực tế thì đây không phải là một dạng truyền duy nhất cũng như điện và sóng vậy)
Trước đây thì Xml RPC này rất phổ biến nhưng mà nó có một nhược điểm chết người chính là lỗ hổng bảo mật. Rồi google bắt đầu phát triển lên, đưa ra một giao thức đi lên từ chính RPC này. Đó chính là gRPC (google Remote Procedure Calls). Nó không những khắc phục được vấn đề bảo mật mà còn khắc phục được vấn đề thứ 2 mà mình nêu ra ở đầu bài viết chính là đa dạng thành phần cũng như nền tảng nhờ việc thay thế Xml bằng loại tín hiệu truyền mới. Dân gian gọi nó là protobuf.
Vậy một số tính năng hay ho của gRPC là gì mà khiến bác đại google đặt tên mình vào tên nó vậy
Đầu tiên phải kể đến là tốc độ truyền nhận. Khi bạn nghe ai đó nói bằng ngôn ngữ khác ngôn ngữ mẹ đẻ chắc bạn sẽ gặp trường hợp phải chững lại vài giây để dịch và hiểu được đầu dây bên kia nói gì. Trong kỹ thuật chuyên ngành thì nó chính là quá trình encode và decode.
Cũng như dạng RPC cũ thì nó dường như mất quá trình chuyển đổi Xml qua lại để có thể hiểu nhau, tuy nhiên gRPC đã sử dụng binary để truyền đi thay vì phải encode chúng thành các ngôn ngữ trung gian JSON/XML. Việc này rõ ràng đã làm tăng tốc giao tiếp các servers lên rất nhiều, giảm overhead cho CPUs. Sự khác biệt quan trọng nhất là gRPC sử dụng bộ đệm giao thức làm ngôn ngữ định nghĩa giao diện cho tuần tự hóa và giao tiếp thay vì JSON / XML. Bộ đệm giao thức có thể mô tả cấu trúc của dữ liệu và mã có thể được tạo từ mô tả đó để tạo hoặc phân tích cú pháp một dòng byte đại diện cho dữ liệu có cấu trúc. Đây là lý do gRPC được ưa thích hơn cho các ứng dụng web đa giác (được triển khai bằng các công nghệ khác nhau). Định dạng dữ liệu nhị phân cho phép giao tiếp nhẹ hơn. gRPC cũng có thể được sử dụng với các định dạng dữ liệu khác, nhưng định dạng ưu tiên là bộ đệm giao thức.
Điểm hay ho tiếp theo chính là giao thức, thay vì http/1 cổ điển thì gRPC giao tiếp binary bằng http/2, đây vốn là giao thức có rất nhiều cải tiến so với http/1.1. Bản thân http/2 cũng được coi như là sự thay thế cho SPDY, giao thức mà cũng chính Google phát triển, open source vào 2012 và ngừng hỗ trợ vào 2015. Lớp truyền tải hoạt động bằng cách sử dụng http/2 trên tcp/ip. Nó cho phép các kết nối có độ trễ thấp hơn (nhanh hơn) có thể tận dụng lợi thế của một kết nối duy nhất từ máy khách đến máy chủ (giúp sử dụng kết nối hiệu quả hơn và có thể sử dụng tài nguyên máy chủ hiệu quả hơn. Http/2 cũng hỗ trợ kết nối hai chiều và kết nối không đồng bộ. Vì vậy, máy chủ có thể liên hệ hiệu quả với máy khách để gửi tin nhắn (phản hồi / thông báo không đồng bộ, v.v.)
Điểm thứ 3 đó là mẫu chuyển đổi định dạng cho rất nhiều các ngôn ngữ (tại thời điểm bài viết này là 11 ngôn ngữ rồi, bạn xem thêm chi tiết về các ngôn ngữ hỗ trợ tại đây https://grpc.io/docs/languages/), đó chính là protobuf (protocol buffers), đây là ngôn ngữ mà gRPC dùng như một default serialization format. Nó không phụ thuộc vào bất cứ ngôn ngữ hay nền tảng nào mà nó giúp cho quá trình biên dịch được nhanh và dễ dàng hơn như những đầu mút endpoint giúp các service có thể nói chuyện được với nhau một cách dễ dàng hơn. Về cơ bản, khi làm việc với protobuf bạn định nghĩa các action, input message, output mesage trong service, sau đó protobuf compiler sẽ generate code ra file theo ngôn ngữ bạn sử dụng. Sau đó bạn sẽ triển khai các action của service như những gì đã bạn đã mô tả.
Ngoài ra thì grpc còn hỗ trợ nhiều dạng phương thức khác nhau để có thể truyền nhận dữ liệu đa dạng hơn cho các bài toàn quyền nhận khác nhau như đồng bộ, bất đồng bộ. Các dạng phương thức đó bao gồm:
– Unary RPCs: Kiểu này giống với các kiểu RPC truyền thống, client gửi một request đến server, đợi server xử lý rồi trả về kết quả cho client.
– Server streaming RPCs: Ở kiểu này, Client gửi một request đến server sau đó đợi server trả về một stream dữ liệu. Client sẽ đọc các message từ stream đó cho đến khi không còn message nào được trả về. Thứ tự các message của mỗi stream được đảm bảo giống nhau giữa Client và Server.
– Client streaming RPCs: Tương tự kiểu Server streaming RPCs, ở kiểu này Client sẽ là phía gửi stream dữ liệu lên server, server sẽ đọc stream dữ liệu đó và thực hiện các xử lý cần thiết, tiếp theo sẽ trả dữ liệu về cho phía Client.
– Bidirectional streaming RPCs: Đây là kiểu method mà dữ liệu được gửi đi theo stream từ cả 2 chiều Client và Server, dữ liệu stream cả 2 chiều là độc lập với nhau, Client và Server có thể xử lý dữ liệu stream đó độc lập. Nghĩa là khi Client gửi 1 message lên server thì server có thể xử lý để thực hiện một tác vụ nào đó (trong khi vẫn nhận các message khác) và gửi kết quả lại cho Client (trong khi Client vẫn đang gửi message khác).
Hay ho thật đó nhưng nó cũng có sự hạn chế chứ.
– Hơi khó khăn trong quá trình tìm lỗi Debug không dữ liệu binary tuy nhiên gần đây thì có một số công cụ khá hay như bloomrpc hỗ trợ giúp bạn tốt hơn(https://github.com/uw-labs/bloomrpc).
– gRPC nếu dùng cho frontend-backend khá hạn chế có thể bạn phải xây dựng gateway hoặc dùng các thư viện đặc thù liên quan như gRPC Gateway (https://github.com/grpc-ecosystem/grpc-gateway) hay gRPC-Web (https://grpc.io/blog/grpc-web-ga/)
– Một số hạn chế về datatype, nguyên nhân chính là protobuf hỗ trợ rất nhiều ngôn ngữ nên khó lòng mà phủ rất cả các kiểu dữ liệu của tất cả các ngôn ngữ được, nên khi ngôn ngữ của bạn làm việc thông qua với datatype mà protobuf sinh code ra sẽ phải ép kiểu hay convert hơi mất công một chút.
– Điều hạn chế cuối cùng nữa là giới hạn đường truyền. Đây là một sự đánh đổi giữa tốc độ và mức dụng lượng đường truyền. Mặc định hiện tại 1 message của grpc tối đa là 4MB. Nên bạn phải cân nhắc chia nhỏ các gói truyền nhận sao cho đảm bảo không vượt quá giới hạn này cũng như đảm bảo được tính toàn vẹn dữ liệu khi nhận.
Ngoài giới hạn về size thì còn một số giới hạn khác về trafic cũng như proxy bạn có thể tìm hiểu tại nguồn chính thống này nhé vì có thể nó sẽ khắc phục và thay đổi trong tương lai (https://cloud.google.com/traffic-director/docs/limitations-proxyless)
Trên đây là bài viết giới thiệu sơ bộ về giao thức grpc giúp bạn có thể giao tiếp giữa các service, mình sẽ cập nhật demo sau cho bài viết này. Cùng theo dõi nhé!
[…] Giới thiệu về GRPC […]
[…] – gRPC + https://blog.ntechdevelopers.com/gioi-thieu-ve-grpc/ [Testing] – Unit test + https://blog.ntechdevelopers.com/unit-test-la-gi/ […]