,
转载注明出处
动机
最近进行的项目很大,分为许多模块,但由于开源技术使用的语言不同,模块使用的语言可能不同,但基本上是使用Java和Python实现的。 如果每个模块都需要交互,就会出现问题。 模块不能像Jar包或Python模块那样部署。 Java有其JVM,Python有其解释器,独立调用只能使用朴素方案。 但是,native显然与操作系统有关,不知道改变环境会产生什么样的兼容性问题。
具体问题还是要具体分析,需要考虑的因素很多。 在这个实际项目中,要考虑效率的因素如下。
单输入文本的处理时间
网络传输时间
机器配置
经过测试,输入文本处理时间的网络传输时间,而且没有高配置的机器,如果使用朴素方法,可能需要跑一些模块,机器可能不会负荷,所以考虑分布式构建提高效率。
设计分布式系统需要考虑机器之间的交互。 最简单、最常见的是使用互联网协议,如http协议。 虽然这是一个APP应用层协议,可能并不高效,但是为了简单起见,如果网络传输效率几乎可以忽略,我们选择了此APP应用层协议。
虽然http协议仅用作通信协议,但数据传输格式仍需规范。 传统上有xml和几种序列化方式,近年来流行更轻量通用的json格式,广泛用于web数据传输。 在本文中,选择json格式。
于是我朝着这个方向调查,找到了json-rpc 2.0标准。
JSON-RPC 2.0概述
JSON-RPC is a stateless, 轻型远程处理模块呼叫(RPC )。protocol.primarilythisspecificationdefinesseveraldatastructuresandtherulesaroundatastructures nosticinthanage ceptscanbeusedwithinthesameprocess,over sockets,over http,orinmanyvariousmessagepassingenvironments.ituses
JSON-RPC是一种无状态、轻量级的远程过程调用(RPC )协议。 本规范主要围绕其处理方法定义了一些数据结构和规则。 此概念可用于在同一进程、套接字或HTTP之间或许多其他消息传递环境中传输数据。 将JSON(RFC4627 )用作数据格式。
那么,这里关键词: JSON,HTTP。
既然是规范,就应该被很多人应用,因为有详细的文档,所以不需要自己写详细的交互式文档。
说明规格中定义的对象所需的成员。
jsonrpc
astringspecifyingtheversionofthejson-RPC协议. must be exactly ' 2.0 '。
方法
astringcontainingthenameofthemethodtobeinvoked.methodnamesthatbeginwithewordrpcfollowedbyaperiodcharacter (u 002 EOR ascii 46 ) thodsandextensionsandmustnotbeusedforanythingelse。
参数化
astructuredvaluethatholdstheparametervaluestobeusedduringtheinvocationofthemethod.thismembermaybeomitted。
id
anidentifierestablishedbytheclientthatmustcontainastring,Number,ornullvalueifincluded.ifitisnotincludeditisassssumedtobeanatobeanananated
theservermustreplywiththesamevalueintheresponseobjectifincluded.thismemberisusedtocorrelatethecontextbetweeenthetwooobjects。
rpc调用启动时,服务器必须返回响应(通知除外)。 将显示响应
成一个单一的对象,包含下列的成员:jsonrpc
指定JSON-RPC版本的字符串,它必须是“2.0”。
result
当调用成功时,该成员是必须的。
如果调用方法出现错误时,必须不包含该成员。
该成员的值由服务器上调用的方法决定。
error
当调用发生错误时,该成员是必须的。
在调用期间如果没有错误产生,必须不包含该成员。
该成员的值必须是一个5.1节定义的对象。
id
该成员是必须的。
它的值必须与请求对象中的id成员的值相同。
如果检查请求对象中的id时发生错误(如:转换错误或无效的请求),它必须为Null。
必须包含result或error成员,但是两个成员都必须不能同时包含。
Java Server
既然是使用http协议,那就需要一个web容器是装载。(不装载也可以,自己去实现一个http容器咯,或者去找开源的,其实也挺大的)
Java有一段时间没用了,以前用Java是做web开发,用经典的Spring框架做对象管理,SpringMVC管理整个web框架,数据层框架用Hibernate或者JPA等。听说最近有个框架很火,叫Spring Boot,它能够快速地构建web应用,而且配置纯Java化,通过一个函数即可启动,像Python的Flask那样的方便,实质它默认使用的底层容器还是Tomcat,简化了我们的操作而已。
用传统的web应用构建方式的成本跟学习Spring Boot框架的成本之间衡量了一下,选择了后者,因为前者再用也是没有什么收益,后者却能体验到新框架,而且现在的框架网站上的Quick Start都很容易实现。但是提高效率的方法不应是单个单个地学习,而是联系起来学习,所以我直接去github上找java jsonrpc的项目。于是定位到了一个叫jsonrpc4j的开源项目,Star299,肯定没找错了。
直接看它的Wiki,还真有Spring Boot的Quick Start。
这里省点力,直接贴:
Server
Configuration
To get the entire system working, you need to define the AutoJsonRpcServiceImplExporter bean in your @Configuration class:
package example.jsonrpc4j.springboot;
import com.googlecode.jsonrpc4j.spring.AutoJsonRpcServiceImplExporter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ApplicationConfig {
@Bean
public static AutoJsonRpcServiceImplExporter autoJsonRpcServiceImplExporter() {
AutoJsonRpcServiceImplExporter exp = new AutoJsonRpcServiceImplExporter();
//in here you can provide custom HTTP status code providers etc. eg:
//exp.setHttpStatusCodeProvider();
//exp.setErrorResolver();
return exp;
}
}
Service
Then create your service interface. My example is a simple calculator endpoint:
package example.jsonrpc4j.springboot.api;
import com.googlecode.jsonrpc4j.JsonRpcParam;
import com.googlecode.jsonrpc4j.JsonRpcService;
@JsonRpcService("/calculator")
public interface ExampleServerAPI {
int multiplier(@JsonRpcParam(value = "a") int a, @JsonRpcParam(value = "b") int b);
}
And implement your interface like this:
package example.jsonrpc4j.springboot.api;
import com.googlecode.jsonrpc4j.spring.AutoJsonRpcServiceImpl;
import org.springframework.stereotype.Service;
@Service
@AutoJsonRpcServiceImpl
public class ExampleServerAPIImpl implements ExampleServerAPI {
@Override
public int multiplier(int a, int b) {
return a * b;
}
}
测试:
curl -H "Content-Type:application/json" -d '{"id":"1","jsonrpc":"2.0","method":"multiplier","params":{"a":5,"b":6}}' http://localhost:8080/calculator
Python Server
这里我使用Flask-jsonrpc模块,直接pip安装。
有点尿急,也直接贴吧:
Create your application and initialize the Flask-JSONRPC.
from flask import Flask
from flask_jsonrpc import JSONRPC
app = Flask(__name__)
jsonrpc = JSONRPC(app, '/api')
Write JSON-RPC methods.
@jsonrpc.method('App.index')
def index():
return u'Welcome to Flask JSON-RPC'
All code of example run.py.
$ python run.py
* Running on http://0.0.0.0:5000/
Test:
$ curl -i -X POST \
-H "Content-Type: application/json; indent=4" \
-d '{
"jsonrpc": "2.0",
"method": "App.index",
"params": {},
"id": "1"
}' http://localhost:5000/api
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 77
Server: Werkzeug/0.8.3 Python/2.7.3
Date: Fri, 14 Dec 2012 19:26:56 GMT
{
"jsonrpc": "2.0",
"id": "1",
"result": "Welcome to Flask JSON-RPC"
}
如果是Python调用它,可以
>>> from flask_jsonrpc.proxy import ServiceProxy
>>> server = ServiceProxy('http://localhost:5000/api')
>>>
>>> server.App.index()
{'jsonrpc': '2.0', 'id': '91bce374-462f-11e2-af55-f0bf97588c3b', 'result': 'Welcome to Flask JSON-RPC'}
Flask-jsonrpc有一个优点就是它有一个api管理页面:
Flask-jsonrpc API管理界面
交互方法
以上我们可以看到我们已经可以通过http协议,加上一些json字符串就可以实现调用了。
在实际项目中,我们只需要实现客户端使用语言的jsonrpc 2.0规范的http调用方法即可,如上一节中的Python使用ServiceProxy对象调用。
还有一定值得注意的是,交互的对象必须要能转为json格式,否则需要自己写转json字符串的方法。
总结
总感觉这是个笨笨的方法,是因为http协议笨重吗?
反正我觉得比native好,少侵入代码,又能形成分布式,而且有个好处就是,前端应用可以直接用js调用。
其实RPC调用就是一个将模块服务化的过程,一个模块能够向多个模块提供服务,例如可以想一些公共功能服务化,就不需要重复代码。
由于分布式知识有限,不能进行更多方法的对比,日后如果有所学习,一定会更新。