grpc调用_使用gRPC和协议缓冲区实现远程过程调用

grpc调用

RPC简介 ( Introduction To RPC )

Remote procedure call (RPC) architecture is popular in building scalable distributed client/server model based applications.

远程过程调用(RPC)体系结构在构建可扩展的基于分布式客户端/服务器模型的应用程序中很流行。

RPC allows a client to a make procedure call (also referred to as subroutine call or function call ) to a server on a different address space without understanding the network configuration as if the server was in the same network (making a local procedure call).

RPC允许客户端在不同的地址空间上对服务器进行过程调用(也称为子例程调用函数调用 ),而无需像服务器在同一网络中那样理解网络配置(进行本地过程调用 )。

In this tutorial, we will implement an RPC client/server model using Google's gRPC and Protocol Buffers.

在本教程中,我们将使用Google的gRPC和协议缓冲区来实现RPC客户端/服务器模型。

RPC如何运作 (How RPC Works)

Before we dive into the heart of RPC, let's take some time to understand how it works.

在深入研究RPC的核心之前,让我们花一些时间来了解它是如何工作的。

  1. A client application makes a local procedure call to the client stub containing the parameters to be passed on to the server.

    客户端应用程序对客户端存根进行本地过程调用,其中包含要传递给服务器的参数。
  2. The client stub serializes the parameters through a process called marshalling forwards the request to the local client-time library in the local computer which forwards the request to the server stub.

    客户端存根通过称为封送处理的过程对参数进行序列化,该过程将请求转发到本地计算机中的本地客户端时间库,本地计算机将请求转发到服务器存根。
  3. The server run-time library receives the request and calls the server stub procedure which unmarshalls (unpacks) the passed parameters and calls the actual procedure.

    服务器运行时库接收该请求并调用服务器存根过程,该过程将解组(解包)传递的参数并调用实际过程。
  4. The server stub sends back a response to the client-stub in the same fashion, a point at which the client resumes normal execution.

    服务器存根以相同的方式将响应发送回客户端存根,此时客户端将恢复正常执行。

grpc调用_使用gRPC和协议缓冲区实现远程过程调用_第1张图片

何时以及为何使用RPC ( When and Why to use RPC )

While in the process of building out a scalable microservice architecture and Andela, we are implementing REST to expose API endpoints, through and API gateway, to external applications (mostly web apps in AngularJS and ReactJS). Inter service communication is then handled using RPC.

在构建可伸缩的微服务架构和Andela的过程中 ,我们正在实现REST,以通过API网关将API端点公开给外部应用程序(主要是AngularJS和ReactJS中的Web应用程序)。 然后使用RPC处理服务间通信。

Remote procedure call's data serialization into binary format for inter-process (server to server) communication makes it ideal for building out scalable microservice architecture by improving performance.

远程过程调用将数据序列化为二进制格式以进行进程间(服务器到服务器)通信,使其成为通过提高性能来构建可伸缩微服务体系结构的理想选择。

RPC client and server run-time stubs take care of the network protocol and communication so that you can focus on your application.

RPC客户端和服务器运行时存根负责网络协议和通信,因此您可以专注于应用程序。

RPC与REST。 斗争! ( RPC vs REST. Fight! )

While RPC and REST use the request/response HTTP protocol to send and receive data respectively, REST is the most popular and preferred client-server communication approach.

尽管RPC和REST使用请求/响应HTTP协议分别发送和接收数据,但是REST是最受欢迎的客户端-服务器通信方法。

Before we dive into RPC. Let's make a comparison of the two.

在我们深入到RPC之前。 让我们对两者进行比较。

  • REST as an architectural style implements HTTP protocol between a client and a server through a set of constraints, typically a method (GET) and a resource or endpoint (/users/1).

    REST作为一种体系结构样式,通过一组约束(通常是方法( GET )和资源或端点( / users / 1 ))在客户端和服务器之间实现HTTP协议。
  • RPC implements client and server stubs that essentially make it possible to make calls to procedures over a network address as if the procedure was local. Simply put, RPC exposes methods (say, getUsers()) in the server to the client.

    RPC实现了客户端和服务器存根,从本质上来说,可以通过网络地址对过程进行调用,就像过程是本地的一样。 简而言之,RPC将服务器中的方法(例如getUsers() )公开给客户端。

The choice of architecture to use entirely remains at the discretion of the development teams and the nature of the system. Some developers have argued against comparing the two, and rightfully so because they can work well together.

完全使用体系结构的选择取决于开发团队和系统的性质。 一些开发人员反对将两者进行比较,这是正确的,因为它们可以很好地协同工作。

Read more about how the two compare on this article by Joshua Hartman.

在Joshua Hartman的这篇文章中阅读更多有关两者比较的信息。

使用gRPC和协议缓冲区实现RPC ( Implementing RPC with gRPC and Protocol Buffers )

Google managed gRPC is a very popular open source RPC framework with support of languages such as C++, Java, Python, Go, Ruby, Node.js, C#, Objective-C and PHP.

Google托管的gRPC是一个非常流行的开源RPC框架,支持诸如C ++,Java,Python,Go,Ruby,Node.js,C#,Objective-C和PHP等语言。

gRPC is a modern open source high performance RPC framework that can run in any environment. It can efficiently connect services in and across data centers with pluggable support for load balancing, tracing, health checking and authentication. It is also applicable in last mile of distributed computing to connect devices, mobile applications and browsers to backend services.

gRPC是可以在任何环境中运行的现代开源高性能RPC框架。 它可以通过可插拔的支持来有效地连接数据中心内和跨数据中心的服务,以实现负载平衡,跟踪,健康检查和身份验证。 它也适用于分布式计算的最后一英里,以将设备,移动应用程序和浏览器连接到后端服务。

http://www.grpc.io/about/

http://www.grpc.io/about/

As we mentioned, with gRPC, a client application can directly call methods on a server application on a different network as if the method was local. The beauty about RPC is that it is language agnostic. This means you could have a grpc server written in Java handling client calls from node.js, PHP and Go.

如前所述,使用gRPC,客户端应用程序可以直接在其他网络上的服务器应用程序上调用方法,就像该方法是本地方法一样。 RPC的优点在于它与语言无关。 这意味着您可以使用Java编写的grpc服务器来处理来自node.js,PHP和Go的客户端调用。

gRPC allows you to define a service which specifies the methods that you can call remotely, the parameters that can be passed to the procedure call and the return responses. The server then implements this definitions and creates a new grpc server to handle the procedure calls from the client.

gRPC允许您定义服务,该服务指定可以远程调用的方法,可以传递给过程调用的参数以及返回响应。 然后,服务器将实现此定义,并创建一个新的grpc服务器来处理来自客户端的过程调用。

By default, gRPC implements Protocol Buffers to serialize structured data as well as define the parameters and return responses for the callable methods.

默认情况下,gRPC实现协议缓冲区来序列化结构化数据以及定义参数并返回可调用方法的响应。

使用gRPC框架的优势 ( Advantages Of Using The gRPC Framework )

Before we get into your first RPC application with gRPC, it is good to look at why we should go for gRPC as opposed to other RPC frameworks such as Apache's Thrift.

在使用gRPC进入您的第一个RPC应用程序之前,先了解一下为什么要使用gRPC而不是其他RPC框架(例如Apache的Thrift)是一件好事。

  • gRPC is built on HTTP/2 under it's BSD license. What this means is that the procedure calls get the goodness of HTTP/2 to build real time applications taking advantages of features such as bidirectional streaming, flow control, header compression and multiplexing requests.

    gRPC是在BSD许可下基于HTTP / 2构建的。 这意味着过程调用利用了诸如双向流,流控制,头压缩和多路复用请求等功能,利用HTTP / 2的优势来构建实时应用程序。
  • gRPC's default serialization protocol, Protocol Buffer, also transmits data in binary format which is smaller and faster as compared to good old JSON and XML.

    gRPC的默认序列化协议Protocol Buffer也以二进制格式传输数据,与旧的JSON和XML相比,该格式更小,更快。
  • Protocol buffer's latest version proto3 which makes it easy to define sevices and automatically generate client libraries as we will see later.

    协议缓冲区的最新版本proto3使得定义服务和自动生成客户端库变得容易,我们将在后面看到。

定义示例应用程序 ( Defining Our Sample Application )

We will be building a simple RPC based app that let's you employees know if they are eligible for work leave or not, if they are, we will proceed to grant them leave days. The rundown of how we will achieve this

我们将构建一个简单的基于RPC的应用程序,该应用程序可让您知道员工是否有资格请假,如果符合条件,我们将继续为他们提供请假天数。 我们将如何实现这一目标

  1. Define our protocol buffer message types and service using the proto3 language guide.

    使用proto3语言指南定义我们的协议缓冲区消息类型和服务。
  2. Create a gRPC server (in Node.js) based on the proto file we define and test it out.

    根据我们定义的原型文件创建一个gRPC服务器(在Node.js中)并进行测试。
  3. Create gRPC clients (in Node.js and Python).

    创建gRPC客户端(在Node.js和Python中)。
  4. Make RPC calls from the respective clients to the server.

    从各个客户端到服务器进行RPC调用。

Our project structure will be laid out as follows.

我们的项目结构如下。

├── package.json
├── .gitignore
├── .grpclirc
├── server/
    ├── index.js
├── client/
    ├── node/
    ├── python/
├── proto/
    ├── work_leave.proto

创建协议缓冲区消息类型和服务 ( Creating Protocol Buffer Message Types And Service )

proto/work_leave.proto

proto / work_leave.proto

syntax = "proto3"; //Specify proto3 version.

package work_leave; //Optional: unique package name.

//Service. define the methods that the grpc server can expose to the client.
service EmployeeLeaveDaysService {
  rpc EligibleForLeave (Employee) returns (LeaveEligibility);
  rpc grantLeave (Employee) returns (LeaveFeedback);
}

// Message Type fefinition for an Employee.
message Employee {
  int32 employee_id = 1;
  string name = 2;
  float accrued_leave_days = 3;
  float requested_leave_days = 4;
}

// Message Type definition for LeaveEligibility response.
message LeaveEligibility {
  bool eligible = 1;
}

// Message Type definition for LeaveFeedback response.
message LeaveFeedback  {
  bool granted = 1;
  float accrued_leave_days = 2;
  float granted_leave_days = 3;
}

Let's take a logical walk through of the .proto file.

让我们对.proto文件进行逻辑遍历。

  • First, we define the protocol buffer language syntax we will be using, in this case, proto3

    首先,我们定义将要使用的协议缓冲区语言语法,在这种情况下为proto3
  • Next we define a unique package name for our file to prevent name clashes between protocol message types. Note that this is optional.

    接下来,我们为文件定义一个唯一的包名称,以防止协议消息类型之间的名称冲突。 请注意,这是可选的。
  • Define an RPC service interface that stipulates what parameters each method in the gRPC server takes and returns. In our case, the service name is EmployeeLeaveDaysService

    定义一个RPC服务接口,该接口规定gRPC服务器中每个方法采用和返回的参数。 在我们的例子中,服务名称是EmployeeLeaveDaysService
  • Last but not least, we define a Message Type for each data that we will be transmitting between the client and the server. A Message Type typically consists of a name/value pair where you define a data type, the field name and a unique number tag that identifies the field when serialized into binary format.

    最后但并非最不重要的一点是,我们为要在客户端和服务器之间传输的每个数据定义一个消息类型。 消息类型通常由名称/值对组成,您可以在其中定义数据类型,字段名称和唯一的数字标签,该序列号在序列化为二进制格式时可标识该字段。

Notice how easy it is to interpret the Service method implementations.

请注意,解释Service方法实现很容易。

  • An RPC call to EligibleForLeave takes an Employee object and returns a LeaveEligibility response.

    EligibleForLeave的RPC调用接受一个Employee对象,并返回一个LeaveEligibility响应。
  • An RPC call to grantLeave takes an Employee object and returns a LeaveFeedback response.

    GrantLeave的RPC调用接受一个Employee对象,并返回一个LeaveFeedback响应。

创建和测试服务器 ( Creating And Testing The Server )

With our .proto file in hand, let's go ahead and create our gRPC server. Since our server is written in Node, go ahead and initalize a new node project and install the grpc package.

有了我们的.proto文件,让我们继续创建gRPC服务器。 由于我们的服务器是用Node编写的,因此继续并启动一个新的Node项目并安装grpc软件包。

npm install --save grpc

Next, create a server directory and add the following code to spin up the server.

接下来,创建服务器目录并添加以下代码以启动服务器。

server/index.js

服务器/ index.js

const grpc = require('grpc');

const proto = grpc.load('proto/work_leave.proto');
const server = new grpc.Server();

//define the callable methods that correspond to the methods defined in the protofile
server.addProtoService(proto.work_leave.EmployeeLeaveDaysService.service, {
  /**
  Check if an employee is eligible for leave.
  True If the requested leave days are greater than 0 and within the number
  of accrued days.
  */
  eligibleForLeave(call, callback) {
    if (call.request.requested_leave_days > 0) {
      if (call.request.accrued_leave_days > call.request.requested_leave_days) {
        callback(null, { eligible: true });
      } else {
        callback(null, { eligible: false });
      }-1
    } else {
      callback(new Error('Invalid requested days'));
    }
  },

  /**
  Grant an employee leave days
  */
  grantLeave(call, callback) {
    let granted_leave_days = call.request.requested_leave_days;
    let accrued_leave_days = call.request.accrued_leave_days - granted_leave_days;

    callback(null, {
      granted: true,
      granted_leave_days,
      accrued_leave_days
    });
  }
});

//Specify the IP and and port to start the grpc Server, no SSL in test environment
server.bind('0.0.0.0:50050', grpc.ServerCredentials.createInsecure());

//Start the server
server.start();
console.log('grpc server running on port:', '0.0.0.0:50050');

First, we load the grpc package and load the proto file using the exposed load method and then create a new instance of ther grpc server.

首先,我们使用暴露的load方法加载grpc软件包并加载proto文件,然后创建grpc服务器的新实例。

The server instance gives us access to the following key methods.

服务器实例使我们可以访问以下关键方法。

  • addProtoService

    addProtoService

Takes two parameters, a link to the service name and a list of methods defined in the respective service. The service name is referenced as ...service.

采用两个参数,即指向服务名称的链接和在相应服务中定义的方法列表。 服务名称引用为...service

Each of the defined method takes in a call which contains the payload from the client and a callback function that returns an error and response respectively.

每个定义的方法都接受一个调用,该调用包含来自客户端的有效负载和一个分别返回错误和响应的回调函数。

  • bind

    捆绑

The bind method specifies the IP and port on which to create the server. Since we are on a test environment, we will also create an insecure server(No SSL).

bind方法指定要在其上创建服务器的IP和端口。 由于我们处于测试环境中,因此我们还将创建一个不安全的服务器(无SSL)。

  • start

    开始

The start method simply starts the server.

start方法只是启动服务器。

测试gRPC服务器 (Testing out the gRPC server)

To take our new server for a test drive, let's globally install a CLI grpc client before we proceed to create our own clients.

为了将我们的新服务器用于测试驱动器,让我们先全局安装一个CLI grpc客户端,然后再继续创建自己的客户端。

npm install -g grpcli

Next, let's start our server.

接下来,让我们启动服务器。

node server

To run the client, navigate to the route of your grpc application and run the grpcli command with the path to the protofile, the IP address and port to connect to and a command to start the client as insecured. You can also specify the configurations in a .grpclirc file

要运行客户端,请导航至grpc应用程序的路由,并运行grpcli命令以及原型文件的路径,要连接的IP地址和端口以及以不安全的方式启动客户端的命令。 您也可以在.grpclirc文件中指定配置

grpcli -f proto/work_leave.proto --ip=127.0.0.1 --port=50050 -i

Once a connection is established, you will be able to list all callable methods with rpc list and call methods with rpc call.

建立连接后,您将能够使用rpc list列出所有可调用方法,并使用rpc call rpc list调用方法。

grpc调用_使用gRPC和协议缓冲区实现远程过程调用_第2张图片

Sweet! Now with that working, let's go ahead and create the grpc clients.

甜! 现在,完成这项工作,让我们继续创建grpc客户。

创建客户 ( Creating The Clients )

Like we had mentioned earlier, we will be creating gRPC clients in Node.js and Python just because we can. This will help us appreciate the power of RPC.

就像我们之前提到的那样,我们将尽我们所能在Node.js和Python中创建gRPC客户端。 这将帮助我们欣赏RPC的强大功能。

For each of the clients we will basically confirm if an employee is eligible for leave and if they are, we will proceed to grant them the requested leave days.

对于每个客户,我们基本上都会确认员工是否有资格请假,如果有请假,我们将继续向他们授予所要求的请假天数。

创建节点客户端 ( Creating a Node Client )

Let's go ahead and create an index.js file in client/node and proceed to create our first client.

让我们继续在客户端/节点中创建一个index.js文件,然后继续创建我们的第一个客户端。

const grpc = require('grpc');

const protoPath = require('path').join(__dirname, '../..', 'proto');
const proto = grpc.load({root: protoPath, file: 'work_leave.proto' });

//Create a new client instance that binds to the IP and port of the grpc server.
const client = new proto.work_leave.EmployeeLeaveDaysService('localhost:50050', grpc.credentials.createInsecure());

const employees = {
  valid: {
    employee_id: 1,
    name: 'John Kariuki',
    accrued_leave_days: 10,
    requested_leave_days: 4
  },
  ineligible: {
    employee_id: 1,
    name: 'John Kariuki',
    accrued_leave_days: 10,
    requested_leave_days: 20
  },
  invalid: {
    employee_id: 1,
    name: 'John Kariuki',
    accrued_leave_days: 10,
    requested_leave_days: -1
  },
  illegal: {
    foo: 'bar'
  }
}

client.eligibleForLeave(employees.valid, (error, response) => {
  if (!error) {
    if (response.eligible) {
      client.grantLeave(employees.valid, (error, response) => {
        console.log(response);
      })
    } else {
      console.log("You are currently ineligible for leave days");
    }
  } else {
    console.log("Error:", error.message);
  }
});

Just like we did for the server, we need to load the proto file and the grpc package. We then create a new client instance that binds to our server's address and port.

就像我们对服务器所做的一样,我们需要加载原始文件和grpc软件包。 然后,我们创建一个绑定到服务器地址和端口的新客户端实例。

At this point, we can now directly make calls to the methods defined in our server. As we had mentioned, each method take in a payload parameter and a callback function that returns an error and response respectively.

此时,我们现在可以直接调用服务器中定义的方法。 正如我们已经提到的,每种方法都带有一个有效负载参数和一个分别返回错误和响应的回调函数。

Let's take a look at how this looks like on our terminal.

让我们看看终端上的情况。

simply call

只需致电

node client/node

node client reponse

Simple, but powerful.

简单,但功能强大。

The protocol buffer limits us to how the employee object looks like so an error would be raised if you tried passing the employees.illegal object. Give it a spin for the different employees provided.

协议缓冲区将我们限制为employee对象的外观,因此如果您尝试传递employees.illegal对象,则会引发错误。 尝试一下提供的不同员工。

创建一个Python客户端 ( Creating a Python Client )

To build a Python client, here are a few prerequisites.

要构建Python客户端,这里有一些先决条件。

  • Install Python 2.6 or higher

    安装Python 2.6或更高版本
  • Install pip version 8 or higher, You can upgrade pip with the following command

    安装pip版本8或更高版本,您可以使用以下命令升级pip
python -m pipinstall --upgrade pip
  • Install virtualenvwrapper to setup a virtual environment workspace for your project. Create a new virtualenv and proceed set it as the current environment

    安装virtualenvwrapper为您的项目设置虚拟环境工作区。 创建一个新的virtualenv并将其设置为当前环境
mkvirtualenv grpc_tutorial && workon grpc_tutorial
`
  • Last but not least create client/python/client.py where our Python client code will reside.

    最后但并非最不重要的一点是,在其中创建我们的Python客户端代码所在的client / python / client.py

安装gRPC (Installing gRPC)

In our virtual environment, install the grpc and grpc tools packages

在我们的虚拟环境中,安装grpc和grpc工具包

pipinstall grpcio grpcio-tools

将原始文件编译为Python (Compiling the proto file to Python)

The grpcio-tools module ships with protoc, the protocol buffer compiler as well as plugins for generating server and client code from the service definitions in the proto file.

所述grpcio-tools模块附带protoc,协议缓冲编译器,以及用于从在原文件中的服务定义生成服务器和客户端代码的插件。

Create a generate_pb.py file in client/python and add the following code to compile the protocol buffer file to python.

client / python中创建一个generate_pb.py文件,并添加以下代码以将协议缓冲区文件编译为python。

from grpc.tools import protoc

protoc.main(
    (
      '',
      '--proto_path=../../proto/',
      '--python_out=.',
      '--grpc_python_out=.',
      '../../proto/work_leave.proto'
    )
)

With that, from the python client directory, simply run:

这样,只需在python客户端目录中运行:

python generate_pb.py

This will generate a client/python/work_leave_pb2.py which we will use to create our python client.

这将生成一个client/python/work_leave_pb2.py ,我们将使用它来创建我们的python客户端。

创建客户端 (Creating the client)

in *client/python/client.py *, let's go ahead and load the grpc module and the python protobuf. We then create an insecure channel to bind to the server's address and port and create a stub from the EmployeeLeaveDaysService .

在* client / python / client.py *中,让我们继续并加载grpc模块和python protobuf。 然后,我们创建一个不安全的通道来绑定到服务器的地址和端口,并从EmployeeLeaveDaysService创建一个存根。

import grpc
import work_leave_pb2 as pb


def main():
    """Python Client for Employee leave days"""

    # Create channel and stub to server's address and port.
    channel = grpc.insecure_channel('localhost:50050')
    stub = pb.EmployeeLeaveDaysServiceStub(channel)

    # Exception handling.
    try:
        # Check if the Employee is eligible or not.
        response = stub.EligibleForLeave(pb.Employee(employee_id=1,
                                                     name='Peter Pan',
                                                     accrued_leave_days=10,
                                                     requested_leave_days=5))
        print(response)

        # If the Employee is eligible, grant them leave days.
        if response.eligible:
            leaveRequest = stub.grantLeave(pb.Employee(employee_id=1,
                                                       name='Peter Pan',
                                                       accrued_leave_days=10,
                                                       requested_leave_days=5))
            print(leaveRequest)
    # Catch any raised errors by grpc.
    except grpc.RpcError as e:
        print("Error raised: " + e.details())

if __name__ == '__main__':
    main()

Start the node server and run the python client on a different terminal.

启动节点服务器,并在其他终端上运行python客户端。

grpc调用_使用gRPC和协议缓冲区实现远程过程调用_第3张图片

结论 ( Conclusion )

For the PHP developers, gRPC can only support PHP clients currently. You can therefore not create a gRPC server with PHP.

对于PHP开发人员,gRPC当前仅支持PHP客户端。 因此,您无法使用PHP创建gRPC服务器。

In this tutorial, we have managed to create a gRPC server in Node.js and made RPC calls from a Node.js and Python client based on a protocol buffer definition.

在本教程中,我们设法在Node.js中创建了一个gRPC服务器,并根据协议缓冲区定义从Node.js和Python客户端进行了RPC调用。

For those of you that dare, you may make pull requests to this tutorial's repository for both gRPC clients and servers in all the other supported languages. Make sure to abide to the directory structure.

对于那些胆敢的人,您可以使用所有其他受支持的语言向gRPC客户端和服务器的本教程存储库发出拉取请求。 确保遵守目录结构。

翻译自: https://scotch.io/tutorials/implementing-remote-procedure-calls-with-grpc-and-protocol-buffers

grpc调用

你可能感兴趣的:(python,java,linux,http,tomcat)