首页 > 其他 > 详细

RPC的入门应用

时间:2020-01-15 13:42:20      阅读:98      评论:0      收藏:0      [点我收藏+]

一、什么是RPC

RPC 的全称是 Remote Procedure Call ,是一种进程间通信方式。它允许程序调用另一个地址空间(通常是共享网络的另一台机器上)的过程或函数,而不用程序员显式编码这个远程调用的细节。即无论是调用本地接口/服务的还是远程的接口/服务,本质上编写的调用代码基本相同。

说起RPC,就不能不提到分布式,这个促使RPC诞生的领域。

假设你有一个计算器接口,Calculator模块,以及它的实现类CalculatorImpl,那么在系统还是单体应用时,你要调用Calculator的add方法来执行一个加运算,直接实例一个CalculatorImpl对象,然后调用add方法就行了,这其实就是非常普通的本地函数调用,因为在同一个地址空间,或者说在同一块内存,所以可以直接实现。

技术分享图片

 

 现在,基于高性能和高可靠等因素的考虑,你决定将系统改造为分布式应用,将很多可以共享的功能都单独拎出来,比如上面说到的计算器,你单独把它放到一个服务里头,让别的服务去调用它。

技术分享图片

这下问题来了,服务A里头并没有CalculatorImpl这个类,那它要怎样调用服务B的CalculatorImpl的add方法呢?

有同学会说,可以模仿B/S架构的调用方式呀,在B服务暴露一个Restful接口,然后A服务通过调用这个Restful接口来间接调用CalculatorImpl的add方法。

很好,这已经很接近RPC了,不过如果是这样,那每次调用时,是不是都需要写一串发起http请求的代码呢?比如
res=requests.get("URL") 
 
但是,两个问题:
1、http协议较为复杂,效率低,相对笨重
2、调用方式不像本地调用简单方便,让调用者感知不到远程调用的逻辑。

二 如何实现RPC

2.1 RPC实现原理

实际情况下,RPC很少用到http协议来进行数据传输,毕竟我只是想传输一下数据而已,何必动用到一个文本传输的应用层协议呢,所以一般会选择直接传输二进制数据

不管你用何种协议进行数据传输,一个完整的RPC过程,都可以用下面这张图来描述:

 
技术分享图片
 

以左边的Client端为例,Application就是rpc的调用方,Client Stub就是我们上面说到的代理对象,也就是那个看起来像是Calculator的实现类,其实内部是通过rpc方式来进行远程调用的代理对象,至于Client Run-time Library,则是实现远程调用的工具包,比如python的socket模块,最后通过底层网络实现实现数据的传输。

这个过程中最重要的就是序列化反序列化了,因为数据传输的数据包必须是二进制的,你直接丢一个python对象过去,人家可不认识,你必须把python对象序列化为二进制格式,传给Server端,Server端接收到之后,再反序列化为python对象。

2.2 python实现RPC

# 客户端

import rpyc

# 参数主要是host, port
conn = rpyc.connect(localhost, 9999)
# test是服务端的那个以"exposed_"开头的方法
print(start)
for i in range(100):
    cResult = conn.root.cal(i)
    print(cResult)
print(end)

conn.close()

# 服务端
from rpyc import Service
from rpyc.utils.server import ThreadedServer


class TestService(Service):

    # 对于服务端来说, 只有以"exposed_"打头的方法才能被客户端调用,所以要提供给客户端的方法都得加"exposed_"
    def exposed_cal(self, num):
        return  num*2

sr = ThreadedServer(TestService, port=9999, auto_register=False)
sr.start()

2.3 GRPC框架

目前流行的开源 RPC 框架还是比较多的,有阿里巴巴的 Dubbo、Facebook 的 Thrift、Google 的 gRPC、Twitter 的 Finagle 等。

gRPC:是 Google 公布的开源软件,基于最新的 HTTP 2.0 协议,并支持常见的众多编程语言。RPC 框架是基于 HTTP 协议实现的,底层使用到了 Netty 框架的支持。
Thrift:是 Facebook 的开源 RPC 框架,主要是一个跨语言的服务开发框架。用户只要在其之上进行二次开发就行,应用对于底层的 RPC 通讯等都是透明的。不过这个对于用户来说需要学习特定领域语言这个特性,还是有一定成本的。
Dubbo:是阿里集团开源的一个极为出名的 RPC 框架,在很多互联网公司和企业应用中广泛使用。协议和序列化框架都可以插拔是极其鲜明的特色。

以使用较为广泛的gRPC为例学习下RPC框架的使用

gRPC 是 Google 开放的一款 RPC (Remote Procedure Call) 框架,建立在 HTTP2 之上,使用 Protocol Buffers。

2.3.1 Protocol Buffers 简介

protocol buffers 是 Google 公司开发的一种数据描述语言,采用简单的二进制格式,比 XML、JSON 格式体积更小,编解码效率更高。用于数据存储、通信协议等方面。

通过一个 .proto 文件,你可以定义你的数据的结构,并生成基于各种语言的代码。目前支持的语言很多,有 Python、golang、js、java 等等。

2.3.2 gRPC 简介

有了 protocol buffers 之后,Google 进一步推出了 gRPC。通过 gRPC,我们可以在 .proto 文件中也一并定义好 service,让远端使用的 client 可以如同调用本地的 library 一样使用。

 
技术分享图片
 

可以看到 gRPC Server 是由 C++ 写的,Client 则分別是 Java 以及 Ruby,Server 跟 Client 端则是通过 protocol buffers 来信息传递。

1. 定义功能函数

calculate.py

# -*- coding: utf-8 -*-
import math


# 求平方
def square(x):
    return math.sqrt(x)

2. 创建 .proto 文件

在这里描述我们要使用的 message 以及 service

syntax = "proto3";

message Number {
    float value = 1;
}

service Calculate {
    rpc Square(Number) returns (Number) {}
}

3. 生成 gRPC 类

这部分可能是整个过程中最“黑盒子”的部分。我们将使用特殊工具自动生成类。

$ pip install grpcio grpcio-tools
$ python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. calculate.proto

你会看到生成来两个文件:

  • calculate_pb2.py ?—? 包含 message(calculate_pb2.Number)
  • calculate_pb2_grpc.py ?—? 包含 server(calculate_pb2_grpc.CalculatorServicer) and client(calculate_pb2_grpc.CalculatorStub)

4. 创建 gRPC 服务端

server.py

# -*- coding: utf-8 -*-
import grpc
import calculate_pb2
import calculate_pb2_grpc
import calculate
from concurrent import futures
import time


# 创建一个 CalculateServicer 继承自 calculate_pb2_grpc.CalculateServicer
class CalculateServicer(calculate_pb2_grpc.CalculateServicer):
    def Square(self, request, context):
        response = calculate_pb2.Number()
        response.value = calculate.square(request.value)
        return response


# 创建一个 gRPC server
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
# 利用 add_CalculateServicer_to_server 这个方法把上面定义的 CalculateServicer 加到 server 中
calculate_pb2_grpc.add_CalculateServicer_to_server(CalculateServicer(), server)
# 让 server 跑在 port 50051 中
print Starting server. Listening on port 50051.
server.add_insecure_port([::]:50051)
server.start()

# 因为 server.start() 不会阻塞,添加睡眠循环以持续服务
try:
    while True:
        time.sleep(24 * 60 * 60)
except KeyboardInterrupt:
    server.stop(0)

启动 gRPC server:

$ python server.py
Starting server. Listening on port 50051.

5. 创建 gRPC 客户端

client.py

 
# -*- coding: utf-8 -*-
import grpc
import calculate_pb2
import calculate_pb2_grpc

# 打开 gRPC channel,连接到 localhost:50051
channel = grpc.insecure_channel(localhost:50051)
# 创建一个 stub (gRPC client)
stub = calculate_pb2_grpc.CalculateStub(channel)
# 创建一个有效的请求消息 Number
number = calculate_pb2.Number(value=16)
# 带着 Number 去调用 Square
response = stub.Square(number)
print response.value

启动 gRPC client:

$ python client.py
4.0

最终的文件结构:

 
技术分享图片

三 总结

RPC 主要用于公司内部的服务调用,性能消耗低,传输效率高,实现复杂。

HTTP 主要用于对外的异构环境,浏览器接口调用,App 接口调用,第三方接口调用等。

RPC 使用场景(大型的网站,内部子系统较多、接口非常多的情况下适合使用 RPC):

  • 长链接。不必每次通信都要像 HTTP 一样去 3 次握手,减少了网络开销。
  • 注册发布机制。RPC 框架一般都有注册中心,有丰富的监控管理;发布、下线接口、动态扩展等,对调用方来说是无感知、统一化的操作。
  • 安全性,没有暴露资源操作。
  • 微服务支持。就是最近流行的服务化架构、服务化治理,RPC 框架是一个强力的支撑。
 
 
 

参考文章:https://www.cnblogs.com/aguncn/p/11520331.html

RPC的入门应用

原文:https://www.cnblogs.com/pyedu/p/12196027.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!