在我当前所做的web项目中,采用前后端分离模式前端通过Django 提供restful接口,后端采用微服务架构,微服务之间的调用采用jsonrpc,由于微服务之间的调用很频繁,导致前端得到的响应很慢,所以就不得不做性能优化。
JSON-RPC是一种基于JSON的跨语言远程调用协议。比xml-rpc、webservice等基于文本的协议传输数据格小;但是JSON格式的解析开销太大。
GRPC:GRPC是一个高性能、通用的开源RPC框架,由Google主要面向移动应用开发并基于HTTP/2协议(注意是HTTP/2协议,不是我们常使用的HTTP 1_1。HTTP/2协议详细的介绍可以参见官方地址:https://http2.github.io/)标准而设计,基于ProtoBuf(Protocol Buffers)序列化协议开发,且支持众多开发语言。为了支持GRPC的跨语言性,GRPC有一套独立存在IDL语言。不过由于GRPC是Google的开源产品,在信息格式封装方面Google主要还是推广的自己的ProtoBuf,所以GPRC是不支持其他信息格式的(至少ProtoBuf效率是大家有目共睹的)。关于GRPC详细的使用介绍,可以参见官方地址:https://github.com/grpc/grpc
Thrift:Thrift是Facebook的一个开源项目,后来进入Apache进行孵化。Thrift也是支持跨语言的,所以它有自己的一套IDL。目前它支持几乎所有主流的编程语言:C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, OCaml and Delphi and other languages。Thrift可以支持多种信息格式,除了Thrift私有的二进制编码规则和一种LVQ(类似于TLV消息格式)的消息格式,还有常规的JSON格式。Thrift的网络协议建立在TCP协议基础上,并且支持阻塞式IO模型和多路IO复用模型。我们将在后文详细讲解Apache Thrift的使用。Thrift也是目前最流行的RPC框架之一,从网络上各种性能测试情况开,Thrift的性能都是领先的。Thrift的官网地址为:http://thrift.apache.org/
通过实践表明,thrift的性能是最好的,Thrift性能明显优于gRPC,性能差距也在两倍以上,所以接下来讲解thrift rpc的改造。
性能优化之前使用的jsonrpc:
# 需要安装django-json-rpc
pip install django-json-rpc
# 配置文件添加jsonrpc到INSTALLED_APPS
INSTALLED_APPS = [ ...
'jsonrpc', ...
]
url.py配置路由:
from jsonrpc import jsonrpc_site urlpatterns = [ url(r'^rpc/$', jsonrpc_site.dispatch, name='jsonrpc_mountpoint'), ]
views.py编写rpc函数:
from jsonrpc import jsonrpc_method from jsonrpc.proxy import ServiceProxy from user.models import ServiceProvidersAuth @jsonrpc_method('user.is_provider_auth') def get_provider_auth(request, user_id): """ Get provider is authentication by user id. """ provider = ServiceProvidersAuth.objects.filter(user_id=user_id) if provider.exists(): return Response(True) else: return Response(False)
改造为高性能的thrift rpc如下 :
服务端编写:# 需要安装thrift 和django-thrift
pip install thrift
pip install django-thrift
# 修改配置文件settings.py
INSTALLED_APPS = [ # other apps 'django_thrift', # and so on ] # 指定thrift路径和服务 THRIFT = { "FILE": "idl/thrift/user.thrift", "SERVICE": "UserManager" }
在idl/thrift/user.thrift文件里定义thrift的结构:
service UserManager{ bool get_provider_auth(1:i32 user_id) }
在views.py中定义thrift 的具体调用(函数名、参数和返回值类型和thrift文件中定义的一致):
from django_thrift.handler import create_handler from user.models import ServiceProvidersAuth handler = create_handler() @handler.map_function('get_provider_auth') def get_provider_auth(user_id): provider = ServiceProvidersAuth.objects.filter(user_id=user_id) if provider.exists(): return True else: return False
启动thrift rpc命令:
python manage.py runrpcserver --port 9000
客户端编写:
在客户端的thrift的文件中需要拷贝要调用的thrift结构,即:
service UserManager{ bool get_provider_auth(1:i32 user_id) }
其他服务调用,编写通用请求thrift函数utils.py:
import logging import thriftpy from django.conf import settings from thriftpy.rpc import make_client logger = logging.getLogger('django') def request_thrift(service, method, url, port, *args, **kwargs): try: thrift = settings.THRIFT['FILE'] service = getattr(thriftpy.load(thrift, module_name=thrift.replace('.', '_')), service) client = make_client(service, url, port) msg = getattr(client, method)(*args, **kwargs) return msg except Exception as ex: logger.error(str(ex))
然后调用:
# 导入utils模块 from user import utils ret = utils.request_thrift('UserManager', 'get_provider_auth', '127.0.0.1', 9000, 1)
改造完成!