微服務性能優化之thrift改造


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

改造完成!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM