Node.js 使用 gRPC從定義到實(shí)現(xiàn)過程詳解
1. 概述:
gRPC(gRPC Remote Procedure Calls)是一個高性能、開源的遠(yuǎn)程過程調(diào)用(RPC)框架,由 Google 開發(fā)。它支持多種編程語言,旨在簡化和優(yōu)化分布式系統(tǒng)中的服務(wù)通信。
2. gRPC的優(yōu)勢:
高性能:使用 HTTP/2 和 protobuf 使得 gRPC 在性能和效率方面表現(xiàn)出色。二進(jìn)制協(xié)議和 HTTP/2 的多路復(fù)用特性使其通信開銷低,速度快。
簡化開發(fā):自動代碼生成和多語言支持簡化了微服務(wù)的開發(fā)和維護(hù)。通過 .proto
文件定義接口后,gRPC 工具會生成相應(yīng)的客戶端和服務(wù)器代碼,大大減少了手動編碼的工作量。
強(qiáng)類型:使用 protobuf 定義服務(wù)接口和消息類型,確保強(qiáng)類型檢查和錯誤檢測。開發(fā)人員可以在編譯時捕捉到許多錯誤,提高代碼的可靠性和可維護(hù)性。
靈活的流處理:支持多種通信模式(單次請求-響應(yīng)、服務(wù)端流、客戶端流、雙向流),適應(yīng)不同的使用場景。例如,可以用服務(wù)端流實(shí)現(xiàn)數(shù)據(jù)的實(shí)時推送,用雙向流實(shí)現(xiàn)實(shí)時聊天功能。
高效的序列化:Protocol Buffers 是一種高效的二進(jìn)制序列化格式,序列化和反序列化速度快,生成的數(shù)據(jù)體積小,適合高性能場景。
3. 實(shí)現(xiàn)邏輯:
- 定義一個服務(wù),指定被調(diào)用的方法(包含參數(shù)和返回類型)。
- 運(yùn)行 gRPC 服務(wù)器來處理客戶端的調(diào)用。
- 在客戶端擁有一個存根,能夠像服務(wù)端一樣的方法。
4. Node.js:
Node.js 庫從運(yùn)行時加載的 .proto
文件動態(tài)生成服務(wù)描述和客戶端存根的定義,所以使用此語言時沒必要生成任何特殊代碼。而是在例子客戶端和服務(wù)端里,我們 require
gRPC 庫,然后用它的 load()
方法,就可以去加載.proto
文件。
5. 為什么 nodejs 推薦動態(tài)加載.proto文件?
使用 @grpc/proto-loader
庫在運(yùn)行時動態(tài)加載 .proto
文件。這是官方推薦的方法
優(yōu)點(diǎn):
- 開發(fā)便捷:不需要在每次修改
.proto
文件后重新生成代碼,開發(fā)過程更加便捷 - 靈活性:適合快速迭代和頻繁修改
.proto
文件的項(xiàng)目 - 減少依賴:不需要安裝
protoc
編譯器
缺點(diǎn):性能:由于在運(yùn)行時解析 .proto
文件,可能會有一些性能開銷,但通??梢院雎圆挥?jì)
6. RPC 生命周期:
定義服務(wù)的四類方法:
單項(xiàng) RPC:
rpc SayHello(HelloRequest) returns (HelloResponse) {}
服務(wù)端流式 RPC:
rpc SayHello(HelloRequest) returns (stream HelloResponse) {}
客戶端流式 RPC:
rpc SayHello(stream HelloRequest) returns (HelloResponse) {}
雙向流式 RPC:
rpc SayHello(stream HelloRequest) returns (stream HelloResponse) {}
截止時間:客戶端可以設(shè)置響應(yīng)的過期時間
RPC 終止
取消 RPC:同步調(diào)用不能被取消
元數(shù)據(jù)集:特殊 RPC
調(diào)用對應(yīng)的信息(鍵值對形式)
流控制
配置
頻道
同步、異步
7. 定義.proto 文件:
關(guān)于 Protocol Buffers
的語法教程請看主頁對應(yīng)文章
// 使用 proto3 語法,不指定的話默認(rèn) proto2 syntax = "proto3"; // 是否需要生成的類拆分為多個 option java_multiple_files = true; // 生成的類所屬的層級 option java_package = "io.grpc.examples.helloworld"; option java_outer_classname = "HelloWorldProto"; option objc_class_prefix = "HLW"; // 定義報名,并于避免命名沖突 package helloworld; // 定義服務(wù) service Greeter { // 定義: // 1. 參數(shù) // 2. 返回類型 rpc SayHello (HelloRequest) returns (HelloReply) {} rpc SayHelloStreamReply (HelloRequest) returns (stream HelloReply) {} } // 結(jié)構(gòu)化數(shù)據(jù):使用 message 定義。 message HelloRequest { string name = 1; // 字段類型 字段名 = 字段編號; } message HelloReply { string message = 1; }
8. 創(chuàng)建 nodejs 的 gRPC 服務(wù)端:
// Protocol Buffers 文件 let PROTO_PATH = __dirname + './helloworld.proto'; // 用戶實(shí)現(xiàn) gRPC 服務(wù)和客戶端的核心庫 let grpc = require('@grpc/grpc-js'); // 加載 .proto 文件 let protoLoader = require('@grpc/proto-loader'); /** * protoLoader.loadSync(PROTO_PATH, { ... }) 方法 * 從指定的 .proto 文件加載定義,并根據(jù)選項(xiàng)配置進(jìn)行解析。 * 使用到 protoLoader 一個 Node.js 模塊 */ let packageDefinition = protoLoader.loadSync( PROTO_PATH, { keepCase: true, // 保持字段名稱的大小寫 longs: String, // 將 Protocol Buffers 中的 long 類型字段解析為 JavaScript 字符串 enums: String, // 將枚舉類型轉(zhuǎn)換為字符串 defaults: true, // 為所有字段設(shè)置默認(rèn)值 oneofs: true // 支持 oneof 字段,這是一種在 Protocol Buffers 中定義的互斥字段 }); /** * grpc.loadPackageDefinition(packageDefinition) 方法 * 將 @grpc/proto-loader 生成的描述加載到 gRPC 庫中, * 將加載的 Protocol Buffers 描述轉(zhuǎn)換為 gRPC 服務(wù)端可以使用的 JavaScript 對象。 * 以創(chuàng)建客戶端和服務(wù)端。 */ let hello_proto = grpc.loadPackageDefinition(packageDefinition).helloworld; /** * 定義 RPC 的方法 */ function sayHello(call, callback) { callback(null, { message: 'Hello ' + call.request.name }); } function main() { // 1. 創(chuàng)建 gRPC 服務(wù)器實(shí)例 let server = new grpc.Server(); // 2. 將 Greeter 服務(wù)和實(shí)現(xiàn)方法添加到 gRPC 服務(wù)器中 server.addService(hello_proto.Greeter.service, { sayHello: sayHello }); /** * 3. 綁定服務(wù)器到指定的地址和端口,并使用不安全的憑據(jù)(沒有 SSL/TLS) * grpc.ServerCredentials.createInsecure(): 創(chuàng)建不安全的服務(wù)器憑據(jù) */ server.bindAsync('0.0.0.0:50051', grpc.ServerCredentials.createInsecure(), (err, port) => { if (err != null) { return console.error(err); } console.log(`gRPC listening on ${port}`) }); } main();
9. 創(chuàng)建 nodejs 的 gRPC 客戶端:
let PROTO_PATH = __dirname + './helloworld.proto'; // 用戶實(shí)現(xiàn) gRPC 服務(wù)和客戶端的核心庫 let grpc = require('@grpc/grpc-js'); // 加載 .proto 文件 let protoLoader = require('@grpc/proto-loader'); // 加載 .proto 文件,并且根據(jù)配置項(xiàng)進(jìn)行解析 let packageDefinition = protoLoader.loadSync( PROTO_PATH, { keepCase: true, // 保持字段名稱的大小寫 longs: String, // 將 Protocol Buffers 中的 long 類型字段解析為 JS 字符串 enums: String, // 將枚舉類型轉(zhuǎn)換為字符串 defaults: true, // 為所有字段設(shè)置默認(rèn)值 oneofs: true // 支持 oneof 字段 }); // 將生成的描述添加到 gRPC 庫中,并輸入可以使用的 JS 對象,來創(chuàng)建服務(wù)端和客戶端 let hello_proto = grpc.loadPackageDefinition(packageDefinition).helloworld; function main() { // 定義 gRPC 服務(wù)器的地址和端口 let target = 'localhost:50051'; // 創(chuàng)建一個客戶端存根,存根(抽象層):hello_proto.Greeter,來調(diào)用遠(yuǎn)程服務(wù) let client = new hello_proto.Greeter(target, grpc.credentials.createInsecure()); let user = 'world'; // 調(diào)用遠(yuǎn)程服務(wù)方法 client.sayHello({ name: user }, function (err, response) { console.log('Greeting:', response.message); }); } main();
10. 核心特點(diǎn)
- 多語言支持:gRPC 支持多種編程語言,包括 C++, Java, Python, Go, Ruby, Node.js 等,使得跨語言的微服務(wù)之間可以無縫通信。
- 基于 HTTP/2:gRPC 使用 HTTP/2 協(xié)議,這帶來了許多優(yōu)點(diǎn),如多路復(fù)用、流量控制、頭部壓縮和雙向流。
- 使用 Protocol Buffers:gRPC 使用 Protocol Buffers(protobuf)作為接口定義語言(IDL)和消息交換格式。這種二進(jìn)制格式既高效又便于跨語言。
- 自動生成代碼:通過使用
.proto
文件定義服務(wù)和消息類型,gRPC 工具鏈可以自動生成客戶端和服務(wù)器端的代碼,大大簡化了開發(fā)工作。 - 全雙工流式處理:gRPC 支持雙向流式處理,這意味著客戶端和服務(wù)器可以在單個連接上獨(dú)立地發(fā)送和接收多個消息。
11. 典型應(yīng)用場景
- 微服務(wù)通信:gRPC 非常適合在微服務(wù)架構(gòu)中用來實(shí)現(xiàn)高效的服務(wù)間通信。
- 實(shí)時通信:通過雙向流處理,gRPC 可以用于實(shí)時聊天、數(shù)據(jù)流和其他需要低延遲的應(yīng)用。
- 跨語言通信:gRPC 的多語言支持使其成為異構(gòu)系統(tǒng)中不同語言組件之間通信的理想選擇。
到此這篇關(guān)于Node.js 使用 gRPC:從定義到實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Node.js 使用 gRPC內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Node.js 8 中的 util.promisify的詳解
本篇文章主要介紹了Node.js 8 中的 util.promisify的詳解,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-06-06nodejs實(shí)現(xiàn)發(fā)送郵箱驗(yàn)證碼功能
這篇文章主要為大家詳細(xì)介紹了nodejs實(shí)現(xiàn)發(fā)送郵箱驗(yàn)證碼功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-04-04優(yōu)化Node.js Web應(yīng)用運(yùn)行速度的10個技巧
這篇文章主要介紹了優(yōu)化Node.js Web應(yīng)用運(yùn)行速度的10個技巧,本文講解了從并行、異步、緩存、gzip 壓縮、客戶端渲染等等技巧,需要的朋友可以參考下2014-09-09解決npm?install版本不匹配問題:?npm?ERR!?code?ETARGET?npm?ERR!?
這篇文章主要介紹了如何解決npm?install版本不匹配問題:?npm?ERR!?code?ETARGET?npm?ERR!?notarget?No?matching?version?found?for,文中給出了詳細(xì)的解決方法,需要的朋友可以參考下2024-02-02Dapr+NestJs編寫Pub及Sub裝飾器實(shí)戰(zhàn)示例
這篇文章主要為大家介紹了Dapr+NestJs編寫Pub及Sub裝飾器的實(shí)戰(zhàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08如何將Node.js中的回調(diào)轉(zhuǎn)換為Promise
這篇文章主要給大家介紹了關(guān)于如何將Node.js中的回調(diào)轉(zhuǎn)換為Promise的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11