文档章节

远程通信协议:从 CORBA 到 gRPC

RiboseYim
 RiboseYim
发布于 2017/10/31 16:10
字数 2037
阅读 138
收藏 5

自从产业界发明机器联网的那一天就已经开始探索最优的远程通信机制。操作系统如 UNIX、Windows 和 Linux 等都有实现远程通信的内部协议,挑战在于如何向开发人员开放一个通信框架。

一、远程调用技术简史

在20世纪90年代,当 TCP/IP 协议日臻成熟变成网络通信的黄金标准时,焦点转移到跨平台通信 —— 一台计算机可以通过某种类型网络在另一台计算机上发起一个动作。例如如 CORBA、DCOM、Java RMI 技术,在核心网络基础设施之上创造了一个对开发者友好的抽象层。这些技术还试图发展出一套与开发语言无关的通信框架,这一点对于客户机/服务器体系结构至关重要。

随着本世纪初 Web 技术的演进,HTTP 逐渐演变为事实上的通信标准。HTTP 结合 XML 提供了一种自我描述、不依赖语言、与平台无关的远程通信框架。这种结合的成果是 SOAP 和 WSDL 标准,它们保证了在各种运行环境和平台之间实现互操作的标准化。

下一个冲击互联网的浪潮是 Web 编程。许多开发人员发现定义 SOAP 标准的 HTTP 和 XML 的组合过于严格。这时 JavaScript 和 JSON 开始流行了。Web 2.0 现象(API 发挥了关键作用), JSON 替代 XML 成为首选的协议。HTTP 和 JSON 这对致命的组合,催生了一个新的非官方标准 REST 。SOAP 要求严格遵守标准和结构定义,仅局限于大型企业应用程序,而 REST 在当代开发人员中很受欢迎。

1.1 HTTP, REST 和微服务

归功于 JavaScript 框架,Node.js 以及文档数据库的发展,REST 在 Web 开发者中广受欢迎。许多应用程序开始基于 REST 实现 ,即使是内部序列化和通信模式领域。但 HTTP 是最有效的消息交换协议吗?即使在同一上下文、同一网络,或者是同一台机器上运行的服务之间?HTTP 的便捷性与高性能之间需要作出权衡,这促使我们回到问题的起点,寻找微服务架构中最优的通信框架。

进入 gRPC 时代 —— 来自谷歌,现代的轻量级通信协议。这是一个高性能的、开源的通用远程过程调用(RPC) 框架,它可以在多种开发语言、任何操作系统上运行。

gRPC 在推出的第一年内就被 CoreOS,Netflix,Square 和 Cockroach Labs 等机构采用。 CoreOS 团队的 Etcd,是一种分布式键/值存储服务,采用 gRPC 实现端通信。电信公司如 Cisco,Juniper 和 Arista 都使用 gRPC 实现数据流遥测和网络设备配置。

1.2 什么是 gRPC ?

当我第一次遇到 gRPC,它使我想到 CORBA。两个框架都基于语言无关的接口定义语言(IDL) 声明服务,通过特定的语言绑定实现。

CORBA 和 gRPC 二者的设计,都是为了使客户端相信服务器在同一台机器。客户机在桩(Stub)上调用一个方法(method),调用过程由底层协议透明地处理。

gRPC 的秘诀在于处理序列化的方式。gRPC 基于 Protocol Buffer,一个开源的用于结构化数据序列化机制,它是语言和平台无关的。Protocol Buffer 的描述非常详细,与 XML 类似。但是它们比其他的协议格式更小,更快,效率更高。任何需要序列化的自定义数据类型在 gRPC 被定义为一个 Protocol Buffer 。

Protocol Buffer 的最新版本是 proto3,支持多种开发语言的代码生成,Java , C++,Python,Ruby , Java Lite , JavaScript,Objective-C 和 C # 。当一个 Protocol Buffer 编译为一个特定的语言,它的访问器(setter 和 getter)为每个字段提供定义。

相比于 REST + JSON 组合 ,gRPC 提供更好的性能和安全性。它极大的促进了在客户端和服务器之间使用 SSL / TLS 进行身份验证和数据交换加密。

为什么微服务开发者需要使用 gRPC ?gRPC 采用 HTTP / 2 以支持高性能的、可扩展的 API 。报文使用二进制而不是文本通信可以保持载荷紧凑、高效。HTTP / 2 请求在一个 TCP 连接上可支持多路复用,允许多个消息并发传送而不影响网络资源利用率。gRPC 使用报头压缩(header compression )来减少请求和响应的大小。

二、gRPC 简介

2.1 创建 gRPC 服务的流程

  1. 在 Protocol Buffer (.proto) 文件中描述服务和载荷结构
  2. 从 .proto 文件生成 gRPC 代码
  3. 用一种开发语言实现服务端
  4. 创建一个客户端调用服务
  5. 运行服务端和客户端

Note:Node.js 客户端不需要生成存根(Stub),只要 Protocol Buffer 文件是可访问的,它就可以直接与服务端对话。

三、gRPC 示例代码

为了进一步熟悉 gRPC,我们将用 Python 语言创建一个简单的计算服务。它将同时被一个 Python 客户端和一个 Node.js 客户端调用。以下测试示例运行在 Mac OS X 。

你可以从 GitHub 库 https://github.com/grpc/grpc/tree/master/examples 访问源代码,在自己的机器上运行示例。

  • 环境准备
// 配置 Python gRPC
python -m pip install virtualenv
virtualenv venv
source venv/bin/activate
python -m pip install --upgrade pip

//安装 gRPC 和 gRPC Tools
python -m pip install grpcio
python -m pip install grpcio-tools

// 配置 Node.js gRPC
npm install grpc --global

//创建目录
mkdir Proto
mkdir Server
mkdir -p Client/Python
mkdir -p Client/Node
  • 创建 Protocol Buffer 文件
//Proto/Calc.proto
syntax = "proto3";

package calc;

service Calculator {
  rpc Add (AddRequest) returns (AddReply) {}
  rpc Substract (SubstractRequest) returns (SubstractReply) {}
  rpc Multiply (MultiplyRequest) returns (MultiplyReply) {}
  rpc Divide (DivideRequest) returns (DivideReply) {}
}

message AddRequest{
  int32 n1=1;
  int32 n2=2;
}
message AddReply{
  int32 n1=1;
}
message SubstractRequest{
  int32 n1=1;
  int32 n2=2;
}
message SubstractReply{
  int32 n1=1;
}
message MultiplyRequest{
  int32 n1=1;
  int32 n2=2;
}
message MultiplyReply{
  int32 n1=1;
}
message DivideRequest{
  int32 n1=1;
  int32 n2=2;
}
message DivideReply{
  float f1=1;
}
  • 生成 Python 服务端和客户端代码
$ python -m grpc.tools.protoc  --python_out=. --grpc_python_out=. --proto_path=. Calc.proto
$ cp Calc_pb2.py ../Server
$ cp Calc_pb2.py ../Client/Python
$ cp Calc.proto ../Client/Node
  • 创建服务端
# Server/Calc_Server.py
from concurrent import futures
import time

import grpc

import Calc_pb2
import Calc_pb2_grpc

_ONE_DAY_IN_SECONDS = 60 * 60 * 24

class Calculator(Calc_pb2.CalculatorServicer):

 def Add(self, request, context):
   return Calc_pb2.AddReply(n1=request.n1+request.n2)

 def Substract(self, request, context):
   return Calc_pb2.SubstractReply(n1=request.n1-request.n2)

 def Multiply(self, request, context):
   return Calc_pb2.MultiplyReply(n1=request.n1*request.n2)

 def Divide(self, request, context):
   return Calc_pb2.DivideReply(f1=request.n1/request.n2)

def serve():
 server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
 Calc_pb2_grpc.add_CalculatorServicer_to_server(Calculator(), server)
 server.add_insecure_port('[::]:50050')
 server.start()

 try:
   while True:
     time.sleep(_ONE_DAY_IN_SECONDS)
 except KeyboardInterrupt:
   server.stop(0)

if __name__ == '__main__':
 serve()
  • 启动服务端
python Calc_Server.py
  • 创建 Python 客户端
# Client/Python/Calc_Client.py

from __future__ import print_function

import grpc
import Calc_pb2
import Calc_pb2_grpc

def run():
 channel = grpc.insecure_channel('localhost:50050')
 stub = Calc_pb2_grpc.CalculatorStub(channel)

 response = stub.Add(Calc_pb2.AddRequest(n1=20,n2=10))
 print(response.n1)
 response = stub.Substract(Calc_pb2.SubstractRequest(n1=20,n2=10))
 print(response.n1)
 response = stub.Multiply(Calc_pb2.MultiplyRequest(n1=20,n2=10))
 print(response.n1)
 response = stub.Divide(Calc_pb2.DivideRequest(n1=20,n2=10))
 print(response.f1)

if __name__ == '__main__':
  run()
  • 创建 Node.js 客户端
//Client/Node/Calc_Client.js
var PROTO_PATH = 'Calc.proto';

var grpc = require('grpc');
var calc_proto = grpc.load(PROTO_PATH).calc;
var params={n1:20, n2:10};

function main() {
 var client = new calc_proto.Calculator('localhost:50050',
                                      grpc.credentials.createInsecure());

 client.divide(params, function(err, response) {
   console.log(response.f1);
 });

 client.multiply(params, function(err, response) {
   console.log(response.n1);
 });

 client.substract(params, function(err, response) {
   console.log(response.n1);
 });

 client.add(params, function(err, response) {
   console.log(response.n1);
 });

}

main();
  • 启动客户端 Node.js/Python
$ python Calc_Client.py
30
10
200
2.0

$ node Calc_Client.js
30
10
200
2.0

扩展阅读:开发语言&代码工程

更多精彩内容扫码关注公众号:RiboseYim's Blog:https://riboseyim.github.io/2017/10/30/Protocol-gRPC/ 微信公众号

© 著作权归作者所有

RiboseYim
粉丝 78
博文 78
码字总数 179042
作品 0
广州
程序员
私信 提问
通过阿里云容器服务K8S Ingress Controller实现gRPC服务访问

gRPC简介 gRPC是Google开源的一个高性能RPC通信框架,通过Protocol Buffers作为其IDL,可以在不同语言开发的平台上使用,同时基于HTTP/2协议实现,继而提供了连接多路复用、头部压缩、流控等...

chenqz
2018/06/01
0
0
访问 gRPC 服务的 Web 客户端 - gRPC-Web

gRPC-Web 即 gRPC for Web Clients。顾名思义,gRPC-Web 是一个 JavaScript 库,使 Web 应用程序能够直接与后端 gRPC 服务通信,不需要 HTTP 服务器充当中介。 gRPC-Web GA 正式版已发布,稳...

匿名
2018/10/26
10.9K
1
gRPC 1.0 发布,来自 Google 的 RPC 框架

一直以来,构建一个高度可扩展且松耦合的系统是很困难的。来自Google的gRPC框架致力于解决这个领域问题。它自去年面世以来收到了社区的大量关注和使用。8月23日Google正式发布了gRPC的1.0版本...

局长
2016/09/06
2.4K
5
思考gRPC :为什么是HTTP/2

背景 gRPC是google开源的高性能跨语言的RPC方案。gRPC的设计目标是在任何环境下运行,支持可插拔的负载均衡,跟踪,运行状况检查和身份验证。它不仅支持数据中心内部和跨数据中心的服务调用,...

横云断岭
2018/07/19
0
0
Nginx 宣布从 1.13.10 开始正式支持 gRPC

最近,NGINX在其博客宣布,Nginx 宣布从 1.13.10 开始正式支持 gRPC 如下是正文翻译: 今天,我们很高兴在NGINX 1.13.10上分享gRPC流量的第一个本地支持。下一个NGINX Plus版本R15将包含对g...

xiaomin0322
2018/05/29
528
0

没有更多内容

加载失败,请刷新页面

加载更多

前端技术之:Prisma Demo服务部署过程记录

安装前提条件: 1、已经安装了docker运行环境 2、以下命令执行记录发生在MackBook环境 3、已经安装了PostgreSQL(我使用的是11版本) 4、Node开发运行环境可以正常工作 首先需要通过Node包管...

popgis
今天
5
0
数组和链表

数组 链表 技巧一:掌握链表,想轻松写出正确的链表代码,需要理解指针获引用的含义: 对指针的理解,记住下面的这句话就可以了: 将某个变量赋值给指针,实际上就是将这个变量的地址赋值给指...

code-ortaerc
今天
4
0
栈-链式(c/c++实现)

上次说“栈是在线性表演变而来的,线性表很自由,想往哪里插数据就往哪里插数据,想删哪数据就删哪数据...。但给线性表一些限制呢,就没那么自由了,把线性表的三边封起来就变成了栈,栈只能...

白客C
今天
43
0
Mybatis Plus service

/** * @author beth * @data 2019-10-20 23:34 */@RunWith(SpringRunner.class)@SpringBootTestpublic class ServiceTest { @Autowired private IUserInfoService iUserInfoS......

一个yuanbeth
今天
5
0
php7-internal 7 zval的操作

## 7.7 zval的操作 扩展中经常会用到各种类型的zval,PHP提供了很多宏用于不同类型zval的操作,尽管我们也可以自己操作zval,但这并不是一个好习惯,因为zval有很多其它用途的标识,如果自己...

冻结not
昨天
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部