聊聊Python用rpc实现分布式系统调用的那些事

开发 后端 前端 分布式
对于rpc的应用,更加的倾向于基本资源的获取和调用,毕竟单纯的用socket或者是mq,你在程序里面还要做一个解析过来的数据,然后根据过来的数据在做调用。

通俗的讲rpc是什么?

rpc 一般俗称,远程过程调用,把本地的函数,放到远端去调用。

通常我们调用一个方法,譬如: sumadd(10, 20),sumadd方法的具体实现要么是用户自己定义,要么存在于该语言的库函数中,也就说在sumadd方法的代码实现在本地,它是一个本地调用!

“远程调用”意思就是:被调用方法的具体实现不在程序运行本地,而是在别的某个地方(分布到各个服务器),但是用起来像是在本地。

rpc远程调用原理 :

比如 A调用B提供的remoteAdd方法:

首先A与B之间建立一个TCP连接;

然后A把需要调用的方法名(这里是remoteAdd)以及方法参数(10, 20)序列化成字节流发送出去;

B接受A发送过来的字节流,然后反序列化得到目标方法名,方法参数,接着执行相应的方法调用(可能是localAdd)并把结果30返回;

A接受远程调用结果,然后do()。

RPC框架也就是把上线说的具体的细节封装起来,给用户好用的API使用(提示:有些远程调用选择比较底层的socket协议,有些远程调用选择比较上层的HTTP协议);

一般rpc配合http协议的多点,也就是走http的多。 当然还是看应用,我曾经一共的rpc框架是基于zeromq的zerorpc。速度是挺快,server和client都有python的gevent支持,速度没道理慢。(有兴趣的,可以看看有关zerorpc的文章 http://rfyiamcool.blog.51cto.com/1030776/1254000 )最少要比python本身的xml-rpc要快。 rpc over http(基于http的rpc)有两种协议,一种是xml-rpc ,还有一个是 json-rpc。

XML-RPC:XML Remote Procedure Call,即XML远程方法调用,利用http+xml封装进行RPC调用。基于http协议传输、XML作为信息编码格式。一个xml-rpc消息就是一个请求体为xml的http-post请求,服务端执行后也以xml格式编码返回。这个标准面前已经演变为下面的SOAP协议。可以理解SOAP是XML-RPC的高级版本。

JSON-RPC:JSON Remote Procedure Call,即JSON远程方法调用 。类似于XML-RPC,不同之处是使用JSON作为信息交换格式

下面是一个例子,很简单。我们是用python的rpc库SimpleXMLRPCServer 做的测试,创建rpc server,然后注册一些函数,供应别的客户端去调用。

  1. from SimpleXMLRPCServer import SimpleXMLRPCServer   
  2. 原文:xiaorui.cc   
  3. def add(x,y):   
  4.     return x+y   
  5.     
  6. def subtract(x, y):   
  7.     return x-y   
  8.     
  9. def multiply(x, y):   
  10.     return x*y   
  11.     
  12. def divide(x, y):   
  13.     return x/y  
  14.     
  15. # A simple server with simple arithmetic functions   
  16. server = SimpleXMLRPCServer(("localhost"8000))   
  17. print "Listening on port 8000..." 
  18. server.register_multicall_functions()   
  19. server.register_function(add, 'add')   
  20. server.register_function(subtract, 'subtract')   
  21. server.register_function(multiply, 'multiply')   
  22. server.register_function(divide, 'divide')   
  23. server.serve_forever() 
  1. import xmlrpclib   
  2.     
  3. proxy = xmlrpclib.ServerProxy("http://localhost:8000/")   
  4. multicall = xmlrpclib.MultiCall(proxy)   
  5. multicall.add(7,3)   
  6. multicall.subtract(7,3)   
  7. multicall.multiply(7,3)   
  8. multicall.divide(7,3)   
  9. result = multicall()   
  10.     
  11. print "7+3=%d, 7-3=%d, 7*3=%d, 7/3=%d" % tuple(result) 

rpc本来是单任务的,如果任务相对频繁,可以设置成多线程的默认,你不用在调用threading模块什么的,直接引用 。

  1. class AsyncXMLRPCServer(SocketServer.ThreadingMixIn,SimpleXMLRPCServer): pass 

然后rpc初始化的方法换成。

  1. server = AsyncXMLRPCServer((''1111), SimpleXMLRPCRequestHandler) 

这里再说下,和xmlrpc相似的jsonrpc,貌似现在用xmlrpc的,要比jsonrpc的多点。 有时候到国外的it论坛看帖子,xmlrpc用的交多点。其实现在较大的公司,一般干脆直接自己实现了rpc框架,像淘宝Dubbo(朋友有搞过,搞了半天,没有对接成接口,说是有难度,不明觉厉!),百度的xxx(忘名字了)。

  1. import jsonrpc   
  2. server = jsonrpc.Server(jsonrpc.JsonRpc20(), jsonrpc.TransportTcpIp(addr=("127.0.0.1"31415), logfunc=jsonrpc.log_file("myrpc.log")))   
  3. #原文:xiaorui.cc   
  4. # 注册一个函数方法   
  5. def echo(s):   
  6.     return s   
  7.     
  8. def search(number=None, last_name=None, first_name=None):   
  9.     sql_where = []   
  10.     sql_vars  = []   
  11.     if number is not None:   
  12.         sql_where.append("number=%s")   
  13.         sql_vars.append(number)   
  14.     if last_name is not None:   
  15.         sql_where.append("last_name=%s")   
  16.         sql_vars.append(last_name)   
  17.     if first_name is not None:   
  18.         sql_where.append("first_name=%s")   
  19.         sql_vars.append(first_name)   
  20.     sql_query = "SELECT id, last_name, first_name, number FROM mytable" 
  21.     if sql_where:   
  22.         sql_query += " WHERE" + " AND ".join(sql_where)   
  23.     cursor = ...   
  24.     cursor.execute(sql_query, *sql_vars)   
  25.     return cursor.fetchall()   
  26.     
  27. server.register_function( echo )   
  28. server.register_function( search )   
  29.     
  30. # start server   
  31. server.serve() 
  1. # 创建jsonrpc客户端   
  2. import jsonrpc   
  3. server = jsonrpc.ServerProxy(jsonrpc.JsonRpc20(), jsonrpc.TransportTcpIp(addr=("127.0.0.1"31415)))   
  4.     
  5. #调用远端的一个函数   
  6. result = server.echo("hello world")   
  7.     
  8. found = server.search(last_name='Python')  

我做过一些个压力的测试,XMLRPCSERVER的开了async之后,每个连接特意堵塞5秒,他的并发在40个左右 。也就是每秒成功40个左右,剩下的还是在堵塞等待中。 其实他的瓶颈不是在于rpc的本身,是承载rpc的那个basehttpserver,太弱爆了。

wKiom1PIg-qhOXPZAAH7nZDKUJM508.jpg
 

接收请求,调用方法 !

wKioL1PIilzjVjTxAAX07GYu-No166.jpg
 

 现在开源社区这么发达,有不少人都根据rpc的协议,重写了承载rpc的web服务。  比如用flask,tornado,配合uwsgi,你猜咋招了。。。。如果不堵塞连接,那还可以,如果堵塞连接,uwsgi的废材特色就显出来了,以前有文章说过,uwsgi是prework,他会预先启动进程,官方都推荐要根据你的cpu核数或者超线程来开启进程,如果开的太多,你会发现,uwsgi他是驾驭不了那么多进程的。还是看我大tornado,用了@gen.engine之后。轻易飙到500的并发连接。 

(以上是我的吃饱又蛋疼测试,没听过谁会重复调用那么多的堵塞方法,自评 sx行为) 

不多说了,看flask实现xmlrpc服务端的代码,看了下flask xmlrpc的源码,实现的不难。

  1. from flask import Flask   
  2. from flaskext.xmlrpc import XMLRPCHandler, Fault   
  3.     
  4. app = Flask(__name__)   
  5.     
  6. handler = XMLRPCHandler('api')   
  7. handler.connect(app, '/api' 
  8.     
  9. @handler.register   
  10. def woca(name="world"):   
  11.     if not name:   
  12.         raise Fault("fuck...fuck""fuck shencan!")   
  13.     return "Hello, %s!" % name   
  14. 原文:xiaorui.cc   
  15. app.run() 

对于每个连接的超时,有多种的方法,如果你用的是flask,tornado做web server,那就写个装饰器single起来,只是性能不好。 或者是前面挂一个nginx,然后做个client_header_timeout,client_body_timeout,proxy_connect_timeout(你懂的。),如果用的python自带的xml-rpc的话,需要引入socket。

  1. import socket   
  2. socket.setdefaulttimeout() 

再说下rpc安全的问题。

至于安全方面,有兴趣就开个ssl,或者是在程序里面判断下client ip,反正配置都是统一下发的,你重载daemon的时候,也就知道该判断什么ip了。

我个人对于rpc的应用,更加的倾向于基本资源的获取和调用,毕竟单纯的用socket或者是mq,你在程序里面还要做一个解析过来的数据,然后根据过来的数据在做调用。 (alert: 我想触发 add() ,如果是rpc的话,我不用管,只是传过去就行了,到那时mq和socket就需要eval调用函数了),一些复杂的应用还是喜欢用面向资源的rest,也推荐大家用这个,靠谱的。

博文地址:http://rfyiamcool.blog.51cto.com/1030776/1439824

责任编辑:林师授 来源: 51CTO
相关推荐

2021-07-09 05:49:53

分布式代码算法

2021-12-09 10:45:19

分布式事务框架

2023-05-29 14:07:00

Zuul网关系统

2022-04-08 08:27:08

分布式锁系统

2017-12-20 16:15:30

分布式系统架构

2023-02-10 00:04:53

2021-12-15 10:00:21

分布式事务框架

2018-01-23 15:55:23

分布式系统架构

2024-07-05 08:26:54

2015-11-10 17:45:00

分布式系统设计开源模块

2018-04-03 09:27:42

分布式架构系统

2021-02-01 09:35:53

关系型数据库模型

2023-11-29 10:26:52

分布式数据

2023-05-12 08:23:03

分布式系统网络

2018-06-11 11:12:09

秒杀限流分布式

2017-05-10 08:59:18

分布式系统承载量

2024-05-31 08:45:24

2022-06-13 10:01:36

Apollo携程框架

2018-06-19 09:35:51

分布式系统限流

2019-05-05 08:37:39

分布式PyTorchGPU
点赞
收藏

51CTO技术栈公众号