Node.js 使用 gRPC從定義到實現(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ā)和維護。通過 .proto 文件定義接口后,gRPC 工具會生成相應(yīng)的客戶端和服務(wù)器代碼,大大減少了手動編碼的工作量。
強類型:使用 protobuf 定義服務(wù)接口和消息類型,確保強類型檢查和錯誤檢測。開發(fā)人員可以在編譯時捕捉到許多錯誤,提高代碼的可靠性和可維護性。
靈活的流處理:支持多種通信模式(單次請求-響應(yīng)、服務(wù)端流、客戶端流、雙向流),適應(yīng)不同的使用場景。例如,可以用服務(wù)端流實現(xiàn)數(shù)據(jù)的實時推送,用雙向流實現(xiàn)實時聊天功能。
高效的序列化:Protocol Buffers 是一種高效的二進(jìn)制序列化格式,序列化和反序列化速度快,生成的數(shù)據(jù)體積小,適合高性能場景。
3. 實現(xiàn)邏輯:
- 定義一個服務(wù),指定被調(diào)用的方法(包含參數(shù)和返回類型)。
- 運行 gRPC 服務(wù)器來處理客戶端的調(diào)用。
- 在客戶端擁有一個存根,能夠像服務(wù)端一樣的方法。
4. Node.js:
Node.js 庫從運行時加載的 .proto 文件動態(tài)生成服務(wù)描述和客戶端存根的定義,所以使用此語言時沒必要生成任何特殊代碼。而是在例子客戶端和服務(wù)端里,我們 require gRPC 庫,然后用它的 load() 方法,就可以去加載.proto文件。
5. 為什么 nodejs 推薦動態(tài)加載.proto文件?
使用 @grpc/proto-loader 庫在運行時動態(tài)加載 .proto 文件。這是官方推薦的方法
優(yōu)點:
- 開發(fā)便捷:不需要在每次修改
.proto文件后重新生成代碼,開發(fā)過程更加便捷 - 靈活性:適合快速迭代和頻繁修改
.proto文件的項目 - 減少依賴:不需要安裝
protoc編譯器
缺點:性能:由于在運行時解析 .proto 文件,可能會有一些性能開銷,但通??梢院雎圆挥?/p>
6. RPC 生命周期:
定義服務(wù)的四類方法:
單項 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';
// 用戶實現(xiàn) gRPC 服務(wù)和客戶端的核心庫
let grpc = require('@grpc/grpc-js');
// 加載 .proto 文件
let protoLoader = require('@grpc/proto-loader');
/**
* protoLoader.loadSync(PROTO_PATH, { ... }) 方法
* 從指定的 .proto 文件加載定義,并根據(jù)選項配置進(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ù)器實例
let server = new grpc.Server();
// 2. 將 Greeter 服務(wù)和實現(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';
// 用戶實現(xiàn) gRPC 服務(wù)和客戶端的核心庫
let grpc = require('@grpc/grpc-js');
// 加載 .proto 文件
let protoLoader = require('@grpc/proto-loader');
// 加載 .proto 文件,并且根據(jù)配置項進(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. 核心特點
- 多語言支持:gRPC 支持多種編程語言,包括 C++, Java, Python, Go, Ruby, Node.js 等,使得跨語言的微服務(wù)之間可以無縫通信。
- 基于 HTTP/2:gRPC 使用 HTTP/2 協(xié)議,這帶來了許多優(yōu)點,如多路復(fù)用、流量控制、頭部壓縮和雙向流。
- 使用 Protocol Buffers:gRPC 使用 Protocol Buffers(protobuf)作為接口定義語言(IDL)和消息交換格式。這種二進(jìn)制格式既高效又便于跨語言。
- 自動生成代碼:通過使用
.proto文件定義服務(wù)和消息類型,gRPC 工具鏈可以自動生成客戶端和服務(wù)器端的代碼,大大簡化了開發(fā)工作。 - 全雙工流式處理:gRPC 支持雙向流式處理,這意味著客戶端和服務(wù)器可以在單個連接上獨立地發(fā)送和接收多個消息。
11. 典型應(yīng)用場景
- 微服務(wù)通信:gRPC 非常適合在微服務(wù)架構(gòu)中用來實現(xiàn)高效的服務(wù)間通信。
- 實時通信:通過雙向流處理,gRPC 可以用于實時聊天、數(shù)據(jù)流和其他需要低延遲的應(yīng)用。
- 跨語言通信:gRPC 的多語言支持使其成為異構(gòu)系統(tǒng)中不同語言組件之間通信的理想選擇。
到此這篇關(guān)于Node.js 使用 gRPC:從定義到實現(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-06
優(yōu)化Node.js Web應(yīng)用運行速度的10個技巧
這篇文章主要介紹了優(yōu)化Node.js Web應(yīng)用運行速度的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-02
Dapr+NestJs編寫Pub及Sub裝飾器實戰(zhàn)示例
這篇文章主要為大家介紹了Dapr+NestJs編寫Pub及Sub裝飾器的實戰(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

