RPC架构概述
RPC是远程过程调用(Remote Promote Call)的缩写,是一种进程之间的通讯方式。可以通俗的理解为“调用远程服务时,要能够像在本地调用一样丝滑,让调用者感知不到远程调用的逻辑。”与之相对的是本地过程调用,具体可以这样理解:
我们先假设一个场景:你饿了,想要吃点东西。
本地过程调用
- 去菜市场买菜,买肉,买油盐酱醋;
- 回家切菜、起锅烧油、炒菜;
- 出锅、装盘、大快朵颐。
这就是本地过程调用,你需要完成做菜的所有步骤才能填饱肚子。
远程过程调用
- 你拿起手机点了个外卖;
- 商家把买菜、炒菜、装盘等原本你要做的事儿做完,然后外卖小哥给你送来;
- 大快朵颐。
这就是远程过程调用,你(客户端)只需调用点外卖这个服务,然后原本的过程不必执行,交给商家(远程服务器)来执行,便能完成你的需求。这看起来有点像函数调用,但与之不同的是,在这个场景中调用的函数是不在你的本地执行的。
远程过程调用可以用下图来表示:
RPC与HTTP的区别
通过上文的描述,大家可能觉得RPC与HTTP的远程调用非常像,都是按照某种数据格式进行网络通信,客户端发请求,服务端给响应。没错,在这点来看,两者非常相似,但是还是有一些细微差别。
- RPC并没有规定数据传输格式,这个格式可以任意指定,不同的RPC协议,数据格式不一定相同;
- HTTP中还定义了资源定位的路径,RPC中并不需要;
- RPC需要满足像调用本地服务一样调用远程服务,也就是对调用过程在API层面进行封装。HTTP协议没有这样的要求,因此RPC的请求、响应等细节需要我们自己去实现;
- 从速度上来看,RPC要比HTTP更快,虽然底层都是TCP,但是HTTP协议的信息往往比较臃肿,不过可以采用gzip压缩;
- 从难度上来看,RPC实现较为复杂,HTTP相对比较简单;
- 从灵活性上来看,RPC方式需要在API层面进行封装,限制了开发的语言环境;HTTP更胜一筹,因为它不关心实现细节,跨平台、跨语言。
用Python实现简单的RPC架构demo
使用python实现RPC架构的方式很简单,只需要使用第三方库rpyc即可,首先安装rpyc库:
pip install rpyc
接下来我们写一个小程序,功能是这样的:服务端提供两个整数相加的功能,客户端对这个服务进行调用。
Server
from rpyc import Service
from rpyc.utils.server import ThreadedServer
class TestService(Service):
def exposed_sum(self, num1: int, num2: int) -> int:
'''
实现num1、num2相加
:param num1:
:param num2:
:return:
'''
return num1 + num2
if __name__ == '__main__':
s = ThreadedServer(TestService, port=9999, auto_register=False)
s.start()
Client
import rpyc
conn = rpyc.connect('localhost', 9999)
result = conn.root.sum(1234, 5678)
conn.close()
print('>>>',result)
接下来先运行Server,再运行Client,得到的结果是这样的:
需要注意的是,在Server的TestService类中,可以被外部调用的方法的前缀必须是exposed_,否则将会出现这样的错误:
Traceback (most recent call last):
File "D:/PythonProject/rpc_test/client.py", line 9, in <module>
result = conn.root.sum(1234, 5678)
File "D:\PythonProject\rpc_test\venv\lib\site-packages\rpyc\core\netref.py", line 166, in __getattr__
return syncreq(self, consts.HANDLE_GETATTR, name)
File "D:\PythonProject\rpc_test\venv\lib\site-packages\rpyc\core\netref.py", line 76, in syncreq
return conn.sync_request(handler, proxy, *args)
File "D:\PythonProject\rpc_test\venv\lib\site-packages\rpyc\core\protocol.py", line 464, in sync_request
return self.async_request(handler, *args, timeout=timeout).value
File "D:\PythonProject\rpc_test\venv\lib\site-packages\rpyc\core\async_.py", line 102, in value
raise self._obj
AttributeError: cannot access 'sum'
而客户端记得及时关闭连接,这样,一个简单的RPC架构demo就完成了。