一文带你了解使用Nodejs开发RPC服务

一、RPC协议

在使用Nodejs开发RPC服务之前,首先先要了解一下什么是RPC协议。

RPC(Remote Procedure Call,远程过程调用)是一种通过网络从远程计算机请求服务的协议,通俗来讲,一次RPC调用就是,客户端A把需要请求的服务名,以及服务对应的参数通过网络传到服务端,由服务端执行服务后,将结果通过网络返回给客户端的过程。

如下图所示(图片源自网络),一个完整的RPC架构里面包含了四个核心的组件,分别是Client ,Server,Client Stub以及Server Stub。

名称 作用
client 服务的调用方。
server 真正的服务提供者。
client stub 存放服务端的地址消息,再将客户端的请求参数打包成网络消息,然后通过网络远程发送给服务方。
server stub 接收客户端发送过来的消息,将消息解包,并调用本地的方法。

一文带你了解使用Nodejs开发RPC服务_第1张图片
由于RPC协议是基于TCP协议的,所以相比于我们常用的HTTP协议,RPC协议能够更快速,更稳定地提供服务。而这些特性,在一些使用serverless的场景下(在大公司serverless的场景居多),就变得非常有优势了。

举例来说,某大型互联网公司需要打通所有的内部系统的登录功能,开发一个“统一登录平台”。那么在这种场景下,不论是从服务效率、服务稳定性,还是从代码可接入性、代码可维护性的角度看,使用RPC开发“统一登录平台”相关的服务,都比使用HTTP协议方便得多。

二、RPC框架

在网络上,有着各种各样的开源的RPC框架,这些RPC框架把我们从“直接操作TCP协议中传输的buffer”中解放出来,能够较为方便地搭建RPC服务。

下面是一些比较常用的RPC框架的对比(图片源自网络):
一文带你了解使用Nodejs开发RPC服务_第2张图片
各个框架的具体区别就不在这里介绍了,各位可以百度一下。

我们直接来关注主题,如果要使用Nodejs开发RPC服务的话,使用thrift是一个不错的选择。它既提供了跨语言的支持,又拥有着不错的性能,而且序列化方式是支持二进制和json的,非常适合使用Nodejs进行开发。

三、使用thrift框架结合Nodejs开发RPC服务

3-1、thrift框架简介

首先贴一下thrift的官网及官方文档:点击这里
在这里我们可以找到thrift框架的详细介绍,以及使用Nodejs结合thrift框架开发RPC服务的相关信息。

Thrift是Facebook开源的一种高效的、支持多种编程语言的RPC的框架。它采用接口描述语言定义并创建服务,支持可扩展的跨语言服务开发,所包含的代码生成引擎可以在多种语言中(如 C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, Smalltalk 等)创建高效的服务,其传输数据采用二进制格式,相对 XML 和 JSON 体积更小,对于高并发、大数据量和多语言的环境更有优势。

3-2、安装thrift

操作系统 安装方式
windows 官网直接下载安装即可
macos 推荐使用brew安装,终端执行brew install thrift

3-3、接口描述语言

thrift通过使用“接口描述语言”来编写跨语言的RPC服务规范文件,然后在终端使用thrift命令将这些服务规范文件编译成对应语言的代码文件。

举个例子,我们生成一个user.idl文件,这个文件定义了User的结构,以及UserService提供的两个方法。

struct User{  
 1: string id,  
 2: string name,  
 3: i16 age,  
}

service UserService{  
 void addUser(1: User user),  
 User getUser(1: string id),  
}  

然后使用thrift --gen js:node user.idl命令,将这个文件编译为js文件。
一文带你了解使用Nodejs开发RPC服务_第3张图片
我们可以看到编译出了两个js文件,user_types.js定义了User的类型,而UserService.js则提供了addUser和getUser的方法。

3-4、编写thrift的接口描述语言

thrift的接口描述语言支持以下几种数据类型:

类型 描述
bool 布尔值
byte 8位有符号整数
i16 16位有符号整数
i32 32位有符号整数
i64 64位有符号整数
double 64位浮点数
string UTF-8编码的字符串
binary 二进制串
struct 定义的结构体对象
list 有序元素列表
set 无序无重复元素集合
map 有序的key/value集合
exception 异常类型
service 具体对应服务的类

通过使用这些数据类型,我们可以在idl文件中实现定义结构体对象,定义服务,定义异常的功能,并可以将idl文件编译成对应语言的源代码。

3-5、编写第一个RPC服务

第一步,编写一个user.idl文件:

struct User{  
 1: string id,  
 2: string name,  
 3: i16 age,  
}

service UserService{  
 void addUser(1: User user),  
 User getUser(1: string id),  
}  

第二步,使用thrift --gen js:node user.idl命令,将这个文件编译为js文件。

第三步,使用npm install thrift --save安装nodejs的thrift依赖(我安装的是0.12.0版本)

第四步,编写RPC客户端(client.js)文件和服务端(server.js)文件:
client.js

const thrift = require('thrift');
const UserService = require('./gen-nodejs/UserService.js');
const ttypes = require('./gen-nodejs/user_types');

const connection = thrift.createConnection('localhost', 7911);
const client = thrift.createClient(UserService, connection);

connection.on('error', function (err) {
  console.error(err);
});

function addUser(user) {
  client.addUser(user, function (err) {
    if (err) {
      console.error(err);
    } else {
      console.log("user added", user.id);
    }
  });
}

function getUser(userId) {
  client.getUser(userId, function (err, response) {
    if (err) {
      console.error(err);
    } else {
      console.log("get user", response);
    }
  })
}

const user = new ttypes.User({
  id: '2',
  name: "shadowingszy",
  age: 22
});
addUser(user)

getUser('2')

server.js

const thrift = require('thrift');
const UserService = require('./gen-nodejs/UserService.js');

const users = {};
const server = thrift.createServer(UserService, {
  addUser: function (user, result) {
    users[user.id] = user
    console.log("[ADD_USER] add:", user, " current:", users)
    result(null)
  },
  getUser: function (id, result) {
    console.log("[GET_USER] get:", id)
    result(null, users[id])
  }
});

server.listen(7911);
console.log('server start');

第五步,目前的目录结构如下:
一文带你了解使用Nodejs开发RPC服务_第4张图片
然后先执行node server.js启动服务端程序。
然后执行node client.js启动客户端程序。

我们可以看到,终端已经成功进行了一次RPC调用了。
在这里插入图片描述

你可能感兴趣的:(前端,node.js,javascript,rpc)