微服務性能優化之thrift改造

在我當前所作的web項目中,採用先後端分離模式前端經過Django 提供restful接口,後端採用微服務架構,微服務之間的調用採用jsonrpc,因爲微服務之間的調用很頻繁,致使前端獲得的響應很慢,因此就不得不作性能優化。前端

JSON-RPC是一種基於JSON的跨語言遠程調用協議。比xml-rpc、webservice等基於文本的協議傳輸數據格小;可是JSON格式的解析開銷太大。python

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/grpcgit

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/github

經過實踐代表,thrift的性能是最好的,Thrift性能明顯優於gRPC,性能差距也在兩倍以上,因此接下來說解thrift rpc的改造。web

性能優化以前使用的jsonrpc:apache

# 須要安裝django-json-rpc
pip install django-json-rpc
# 配置文件添加jsonrpc到INSTALLED_APPS
INSTALLED_APPS = [                                                                                                                                                                                                                                                     ...
   'jsonrpc',                                                                                                                                                                                                                                                                     ...
]
url.py配置路由:
django

 

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以下 :json

服務端編寫:# 須要安裝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)

改造完成!

相關文章
相關標籤/搜索