node.js

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > node.js > Node.js 使用 gRPC

Node.js 使用 gRPC从定义到实现过程详解

作者:ZJ_.

gRPC是一个高性能、开源的远程过程调用(RPC)框架,由 Google 开发,它支持多种编程语言,旨在简化和优化分布式系统中的服务通信,本文给大家介绍Node.js 使用 gRPC从定义到实现过程,感兴趣的朋友跟随小编一起看看吧

1. 概述:

gRPC(gRPC Remote Procedure Calls)是一个高性能、开源的远程过程调用(RPC)框架,由 Google 开发。它支持多种编程语言,旨在简化和优化分布式系统中的服务通信。

2. gRPC的优势:

高性能:使用 HTTP/2 和 protobuf 使得 gRPC 在性能和效率方面表现出色。二进制协议和 HTTP/2 的多路复用特性使其通信开销低,速度快。

简化开发:自动代码生成和多语言支持简化了微服务的开发和维护。通过 .proto 文件定义接口后,gRPC 工具会生成相应的客户端和服务器代码,大大减少了手动编码的工作量。

强类型:使用 protobuf 定义服务接口和消息类型,确保强类型检查和错误检测。开发人员可以在编译时捕捉到许多错误,提高代码的可靠性和可维护性。

灵活的流处理:支持多种通信模式(单次请求-响应、服务端流、客户端流、双向流),适应不同的使用场景。例如,可以用服务端流实现数据的实时推送,用双向流实现实时聊天功能。

高效的序列化:Protocol Buffers 是一种高效的二进制序列化格式,序列化和反序列化速度快,生成的数据体积小,适合高性能场景。

3. 实现逻辑:

4. Node.js:

Node.js 库从运行时加载的 .proto 文件动态生成服务描述和客户端存根的定义,所以使用此语言时没必要生成任何特殊代码。而是在例子客户端和服务端里,我们 require gRPC 库,然后用它的 load() 方法,就可以去加载.proto文件。

5. 为什么 nodejs 推荐动态加载.proto文件?

使用 @grpc/proto-loader 库在运行时动态加载 .proto 文件。这是官方推荐的方法

优点:

缺点:性能:由于在运行时解析 .proto 文件,可能会有一些性能开销,但通常可以忽略不计

6. RPC 生命周期:

定义服务的四类方法:

单项 RPC:

rpc SayHello(HelloRequest) returns (HelloResponse) {}

服务端流式 RPC:

rpc SayHello(HelloRequest) returns (stream HelloResponse) {}

客户端流式 RPC:

rpc SayHello(stream HelloRequest) returns (HelloResponse) {}

双向流式 RPC:

rpc SayHello(stream HelloRequest) returns (stream HelloResponse) {}

截止时间:客户端可以设置响应的过期时间

RPC 终止

取消 RPC:同步调用不能被取消

元数据集:特殊 RPC 调用对应的信息(键值对形式)

流控制

配置

频道

同步、异步

7. 定义.proto 文件:

关于 Protocol Buffers 的语法教程请看主页对应文章

// 使用 proto3 语法,不指定的话默认 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;
// 定义服务
service Greeter {
  // 定义:
  //   1. 参数
  //   2. 返回类型
  rpc SayHello (HelloRequest) returns (HelloReply) {}
  rpc SayHelloStreamReply (HelloRequest) returns (stream HelloReply) {}
}
// 结构化数据:使用 message 定义。
message HelloRequest {
  string name = 1; // 字段类型 字段名 = 字段编号;
}
message HelloReply {
  string message = 1;
}

8. 创建 nodejs 的 gRPC 服务端:

// Protocol Buffers 文件
let PROTO_PATH = __dirname + './helloworld.proto';
// 用户实现 gRPC 服务和客户端的核心库
let grpc = require('@grpc/grpc-js');
// 加载 .proto 文件
let protoLoader = require('@grpc/proto-loader');
/**
 * protoLoader.loadSync(PROTO_PATH, { ... }) 方法
 * 从指定的 .proto 文件加载定义,并根据选项配置进行解析。
 * 使用到 protoLoader 一个 Node.js 模块
 */
let packageDefinition = protoLoader.loadSync(
  PROTO_PATH,
  {
    keepCase: true, // 保持字段名称的大小写
    longs: String, // 将 Protocol Buffers 中的 long 类型字段解析为 JavaScript 字符串
    enums: String, // 将枚举类型转换为字符串
    defaults: true, // 为所有字段设置默认值
    oneofs: true // 支持 oneof 字段,这是一种在 Protocol Buffers 中定义的互斥字段
  });
/**
 * grpc.loadPackageDefinition(packageDefinition) 方法
 * 将 @grpc/proto-loader 生成的描述加载到 gRPC 库中,
 * 将加载的 Protocol Buffers 描述转换为 gRPC 服务端可以使用的 JavaScript 对象。
 * 以创建客户端和服务端。
 */
let hello_proto = grpc.loadPackageDefinition(packageDefinition).helloworld;
/**
 * 定义 RPC 的方法
 */
function sayHello(call, callback) {
  callback(null, { message: 'Hello ' + call.request.name });
}
function main() {
  // 1. 创建 gRPC 服务器实例
  let server = new grpc.Server();
  // 2. 将 Greeter 服务和实现方法添加到 gRPC 服务器中
  server.addService(hello_proto.Greeter.service, { sayHello: sayHello });
  /**
   * 3. 绑定服务器到指定的地址和端口,并使用不安全的凭据(没有 SSL/TLS)
   *    grpc.ServerCredentials.createInsecure(): 创建不安全的服务器凭据
   */
  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. 创建 nodejs 的 gRPC 客户端:

let PROTO_PATH = __dirname + './helloworld.proto';
// 用户实现 gRPC 服务和客户端的核心库
let grpc = require('@grpc/grpc-js');
// 加载 .proto 文件
let protoLoader = require('@grpc/proto-loader');
// 加载 .proto 文件,并且根据配置项进行解析
let packageDefinition = protoLoader.loadSync(
  PROTO_PATH,
  {
    keepCase: true, // 保持字段名称的大小写
    longs: String, // 将 Protocol Buffers 中的 long 类型字段解析为 JS 字符串
    enums: String, // 将枚举类型转换为字符串
    defaults: true, // 为所有字段设置默认值
    oneofs: true // 支持 oneof 字段
  });
// 将生成的描述添加到 gRPC 库中,并输入可以使用的 JS 对象,来创建服务端和客户端
let hello_proto = grpc.loadPackageDefinition(packageDefinition).helloworld;
function main() {
  // 定义 gRPC 服务器的地址和端口
  let target = 'localhost:50051';
  // 创建一个客户端存根,存根(抽象层):hello_proto.Greeter,来调用远程服务
  let client = new hello_proto.Greeter(target,
    grpc.credentials.createInsecure());
  let user = 'world';
  // 调用远程服务方法
  client.sayHello({ name: user }, function (err, response) {
    console.log('Greeting:', response.message);
  });
}
main();

10. 核心特点

11. 典型应用场景

到此这篇关于Node.js 使用 gRPC:从定义到实现的文章就介绍到这了,更多相关Node.js 使用 gRPC内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文