TARS RPC 通訊框架|提供多種遠程調用方式

做者 | Eaton ios

導語 | TARS 中提供了一套高性能 RPC 通訊框架,實現了服務間的高效通訊。RPC 做爲微服務的核心技術,支撐着移動互聯網時代下不斷增加的用戶和海量的請求。爲了知足更多的需求,TARS 支持了同步、異步等多種調用方式。本文將會詳細闡述 TARS 中的幾種遠程調用方式。git

目錄

  • RPC 簡介
  • TARS 服務尋址方式
  • TARS 遠程調用方式github

    • 同步調用
    • 異步調用
    • 單向調用
    • Hash調用

RPC 簡介

RPC,即遠程過程調用,是一種經過網絡向遠程計算機請求服務,而不須要了解底層網絡技術的思想。經過屏蔽消息打包、服務尋址等遠程網絡通訊細節,使遠程調用就像調用本地函數或者本地對象的方法同樣調用遠程計算機的函數。服務器

服務尋址是遠程調用的基礎。實現服務的遠程調用,先要知道服務的地址,找到可調用的服務後,才能對服務發起有效的遠程調用。下面咱們先來了解一下 TARS 中的尋址方式。網絡

TARS 服務尋址方式

TARS 服務的尋址方式,按照服務是否在主控節點 Registry 註冊,一般能夠分爲兩種方式:直接尋址和名字服務(主控路由服務)。app

直接尋址,顧名思義,就是直接指定要調用的服務的地址,例以下面代碼中,咱們直接指定了要調用服務的具體地址,後續的調用都會訪問這個服務。框架

auto prx = comm->stringToProxy<Demo::HelloPrx>(
    "Test.HelloServer.HelloObj@tcp -h 127.0.0.1 -p 8088");
prx->testHello("abc");

名字服務,即咱們只需經過服務的名字就能調用某個服務,而不須要提供服務的具體地址,以下異步

auto prx = comm->stringToProxy<Demo::HelloPrx>("Test.HelloServer.HelloObj");
prx->testHello("abc");

因爲代碼中無需寫具體IP配置,名字服務很大程度上提升了代碼的可維護性。使用名字服務要求服務在主控節點 Registry 註冊,即服務須要經過 TARS 框架部署,原理以下async

客戶端經過調用 stringToProxy 向主控請求要調用服務的地址列表。主控將返回服務地址列表給客戶端,以供客戶端發起服務調用。tcp

遠程調用方式

獲取到服務地址列表後,客戶端將發起服務調用。TARS 中提供了多種調用方式,使開發者可以根據具體的使用場景,選擇合適的調用方式。

  • 同步調用:發起調用後,等待調用返回結果,再繼續執行後續邏輯;
  • 異步調用:發起調用後,馬上執行後續邏輯,經過回調函數處理返回結果;
  • 單向調用:只發起調用,不關心返回結果或被調服務是否接收;
  • Hash 調用:同一用戶的屢次調用都請求同一服務器的服務。

讓咱們用TarsCpp的例子來看看這幾種調用方式是如何使用的。本部分使用的例子中,調用的服務名字爲 Demo.HelloServer.HelloObj,其接口文件 Hello.tars 中接口定義以下

module Demo
{

interface Hello
{
    int testHello(string req, out string rsp);
};

};

接口直接將傳入的字符串返回,實現以下

int HelloServerImp::testHello(const string & req, string & rsp, tars::TarsCurrentPtr current)
{
    rsp = req;
    return 0;
}

關於服務的具體開發和部署流程,請參閱官方文檔,這裏再也不贅述。

同步調用

同步調用是最多見的調用,也是最簡單的調用。顧名思義,就是發起調用後,等待返回結果,可以知足大多數狀況下的需求。

下面是一個客戶端同步調用服務接口 testHello 的例子。調用過程和函數調用相似,經過服務通訊代理對象 prx 調用服務的接口 testHello,獲取返回值。

#include <iostream>
#include "servant/Communicator.h"
#include "servant/ServantProxy.h"

#include "Hello.h"  // Hello.tars 生成的頭文件

using namespace std;
using namespace tars;

static string helloObj = "Demo.HelloServer.HelloObj";

int main(int argc, char *argv[])
{
    CommunicatorPtr comm = new Communicator();
    try
    {
        // 加載配置
        TC_Config conf;
        conf.parseFile("config.conf");
        comm->setProperty(conf);

        // 生成代理
        auto prx = comm->stringToProxy<Demo::HelloPrx>(helloObj);
        
        string rsp;

        // 發起同步調用
        int ret = prx->testHello("Hello", rsp);
        if (ret == 0)
            cout << "Call successfully: " << rsp << endl;
    }
    catch (exception &e)
    {
        cerr << "error: " << e.what() << endl;
    }
    catch(...)
    {
        cerr << "Unknown Error" << endl;
    }
}
TC_Config 是 TARS 中提供的可以用於加載配置的工具類,相關使用方式能夠參考文章 [微服務開源框架TARS 之 基礎組件]()。

編譯執行這個例子,結果以下

$ ./Client
Call successfully: Hello

上述例子中,經過加載配置文件 config.conf 初始化了客戶端的通訊器 comm,配置文件具體內容以下

<tars>
  <application>
    <client>
      # 主控地址
      locator = tars.tarsregistry.QueryObj@tcp -h 127.0.0.1 -t 60000 -p 17890
    </client>
  </application>
</tars>

能夠看到,配置文件中咱們配置了主控的地址。這樣就像前面 TARS 尋址方式中介紹的,咱們就不須要指定服務的地址,可以經過名字服務找到服務。

異步調用

同步調用很簡單很常見,但並不能適應全部場景。但遇到調用的接口耗時比較長,或是接口返回結果對後續邏輯沒有影響等狀況時,使用同步調用會阻塞後續過程,影響應用性能,咱們能夠選擇異步調用。

發起異步調用後,程序會馬上執行後續邏輯,而不關心調用的返回結果。異步調用後,通常會在調用結果返回後,經過註冊回調函數對它處理。TarsCpp 中,回調對象包含兩個回調函數,分別處理調用成功和調用失敗的邏輯。接口 testHello 回調對象的定義以下:

// 定義回調方法
struct HelloCallback : public Demo::HelloPrxCallback
{
    // 異步調用成功邏輯
    virtual void callback_testHello(int ret, const string & rsp)
    {
        cout << rsp << endl;
    }
    // 異步調用失敗邏輯
    virtual void callback_testHello_exception(tars::Int32 ret)
    {
        cout << "callback exception: " << ret << endl;
    }
};

修改前面的同步調用邏輯,咱們能夠經過調用 async_testHello 來進行異步調用,以下

...
        // 加載配置
        TC_Config conf;
        conf.parseFile("config.conf");
        comm->setProperty(conf);

        // 生成代理
        auto prx = comm->stringToProxy<Demo::HelloPrx>(helloObj);

        // 定義遠程回調對象
        Demo::HelloPrxCallbackPtr cb = new HelloCallback;

        // 發起異步調用
        string req = "Hello";
        prx->async_testHello(cb, req);
        cout << "Call testHello async" << endl;
        // 等待調用完成
        sleep(1);
    ...

這裏咱們添加 sleep(1) 等待遠程調用完成並執行回調邏輯。編譯執行這個例子,結果以下

$ ./Client
Call testHello async
Hello

單向調用

顧名思義,單向調用就是單方面發起調用,只管發送數據,徹底不關心調用返回結果。單向調用能夠認爲是不處理返回結果的異步調用的一種。

所以,單向調用的方式和異步調用的方式同樣使用 async_testHello 便可,但不須要定義回調對象,傳入 NULL 便可,以下

...
        string req = "Hello";
        // 發起單向調用
        prx->async_testHello(NULL, req);
    ...

Hash 調用

前面咱們介紹過 TARS 的名字服務,是經過主控獲取對應服務的多個地址列表。所以一個服務能夠部署多臺,請求也是隨機分發到這些服務器上。可是在某些場合下,但願某些請求老是在某一臺服務器上,對於這種狀況 TARS 提供了簡單的方式實現,即 Hash 調用。

假設咱們傳入的參數 Hello 爲用戶 ID,經過 Hash 調用,每次傳入的 ID 值爲 Hello 時,每次Hello用戶請求時,調用到的都是同一臺服務器。

本文hash 調用的例子直接在同步調用的基礎上進行修改。只須要在調用前鏈式調用 tars_hash 便可,修改的部分以下

...

#include "util/tc_hash_fun.h"

    ...

        int ret = prx->tars_hash(hash_new<string>()("Hello"))->testHello("Hello", rsp);
    ...
注意:
這種方式是有必定風險的。若是後臺某臺服務器掛了,這些請求就會遷移到其餘服務器。等到服務器恢復後,會再遷移回來。

tars_hash 參數必須是 int。對於 string 類型來講,能夠像上述例子同樣,使用 TARS 基礎庫(util目錄下)中的 hash_new 方法,具體請參見 util/tc_hash_fun.h.

總結

TARS 除了支持直接尋址,還支持的名字服務路由的方式發現服務,提升了代碼的可維護性。同時提供多種遠程調用方式,開發者可以自由選擇,知足多種場景下的需求。

TARS 能夠在考慮到易用性和高性能的同時快速構建系統並自動生成代碼,幫助開發人員和企業以微服務的方式快速構建本身穩定可靠的分佈式應用,從而令開發人員只關注業務邏輯,提升運營效率。多語言、敏捷研發、高可用和高效運營的特性使 TARS 成爲企業級產品。

TARS微服務助您數字化轉型,歡迎訪問:

TARS官網:https://TarsCloud.org

TARS源碼:https://github.com/TarsCloud

Linux基金會官方微服務免費課程:https://www.edx.org/course/bu...

獲取《TARS官方培訓電子書》:https://wj.qq.com/s2/6570357/...

或掃碼獲取:

QR

相關文章
相關標籤/搜索