好好学习,天天向上

博客园 首页 联系 订阅 管理

在我当前所做的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)

改造完成!

 

posted on 2018-03-19 21:44  Fighting蔚  阅读(3901)  评论(1编辑  收藏  举报