[轉載] Thrift.net介紹和使用

1、 什麼是 RPC

Restful 採用 Http 進行通信,優勢是開放、標準、簡單、兼容性升級容易;html

缺點是性能略低。在 QPS 高或者對響應時間要求苛刻的服務上,能夠用 RPC(Remote Procedure Call),RPC 因爲採用二進制傳輸、TCP 通信,因此一般性能更好。java

.Net Core 下的 RPC(遠程方法調用)框架有 gRPC、Thrift 等,都支持主流的編程語言。linux

RPC 雖然效率略高,可是耦合性強,若是兼容性處理很差的話,一旦服務器端接口升級,客戶端就要更新,即便是增長一個參數,而 rest 則比較靈活。web

最佳實踐:對內一些性能要求高的場合用 RPC,對內其餘場合以及對外用 Rest。好比 web 服務器和視頻轉碼服務器之間通信能夠用 restful 就夠了,轉帳接口用 RPC 性能會更高一些。apache

Thrift架構編程

img

圖中,TProtocol(協議層),定義數據傳輸格式,例如:c#

  • TBinaryProtocol:二進制格式(默認傳輸格式);
  • TCompactProtocol:壓縮格式;
  • TJSONProtocol:JSON格式;
  • TSimpleJSONProtocol:提供JSON只寫協議, 生成的文件很容易經過腳本語言解析;
  • TDebugProtocol:使用易懂的可讀的文本格式,以便於debug

TTransport(傳輸層),定義數據傳輸方式,能夠爲TCP/IP傳輸,內存共享或者文件共享等)被用做運行時庫。windows

  • TSocket:阻塞式socker;
  • TFramedTransport:以frame爲單位進行傳輸,非阻塞式服務中使用;
  • TFileTransport:以文件形式進行傳輸;
  • TMemoryTransport:將內存用於I/O,java實現時內部實際使用了簡單的ByteArrayOutputStream;
  • TZlibTransport:使用zlib進行壓縮, 與其餘傳輸方式聯合使用,當前無java實現;

Thrift支持的服務模型服務器

  • TSimpleServer:簡單的單線程服務模型,經常使用於測試;
  • TThreadPoolServer:多線程服務模型,使用標準的阻塞式IO;
  • TNonblockingServer:多線程服務模型,使用非阻塞式IO(需使用TFramedTransport數據傳輸方式);

2、 Thrift 基本使用

參考資料:http://www.javashuo.com/article/p-nvuouklh-bd.htmlrestful

一、 下載thrift http://thrift.apache.org/

把thrift-***.exe解壓到磁盤,更名爲thrift.exe(用起來方便一些)

二、 編寫一個UserService.thrift文件(IDL)

namespace csharp RuPeng.ThriftTest1.Contract

service UserService{
   SaveResult Save(1:User user)     
   User Get(1:i32 id)     
   list<User> GetAll()
} 

enum SaveResult {     
  SUCCESS = 0,  
  FAILED = 1,  
}  

struct User {
    1: required i64 Id;
    2: required string Name;
    3: required i32 Age;
    4: optional bool IsVIP;
    5: optional string Remark;
}

service定義的是服務類,enum 是枚舉,struct是傳入或者傳出的複雜數據類型(支持對象級聯)。

語法規範 http://thrift.apache.org/docs/idl

根據thrift語法生成C#代碼

cmd -> thrift.exe -gen csharp UserService.thrift

建立一個類庫項目 ThriftTest1.Contract,做爲客戶端和服務器之間的共用協議,把上一步生成的代碼放進項目。

三、 建立服務器端項目 ThriftTest1.Server,建一個控制檯項目(放到 web 項目中或者在 Linux中用守護進程運行起來(SuperVisor等,相似Windows下的「Windows服務」)也能夠)。

ThriftTest1.Server項目引用ThriftTest1.Contract

建立項目:ApplicationExtenssion.cs

編寫實現類 UserServiceImpl.cs

public class UserServiceImpl : UserService.Iface
{
    public User Get(int id)
    {
        User u = new User();
        u.Id = id;
        u.Name = "用戶" + id;
        u.Age = 6; return u;
    }

    public List<User> GetAll()
    {
        List<User> list = new List<User>();
        list.Add(new User { Id = 1, Name = "yzk", Age = 18, Remark = "hello" });
        list.Add(new User { Id = 2, Name = "rupeng", Age = 6 });
        return list;
    }

    public SaveResult Save(User user)
    {
        Console.WriteLine($"保存用戶,{user.Id}"); return SaveResult.SUCCESS;
    }
}

修改Program下的Main函數 啓動服務器端

TServerTransport transport = new TServerSocket(8800);//監聽8800端口
var processor = new RuPeng.ThriftTest1.Contract.UserService.Processor(new UserServiceImpl());//設置實現類
TServer server = new TThreadPoolServer(processor, transport);
server.Serve();

監聽8800端口

經過比較TSimpleServer、TThreadedServer、TThreadPoolServer,發現TSimpleServer只能同時響應一個客戶端,TThreadedServer則維護了一個clientQueue,clientQueue最大值是100,TThreadPoolServer則用的是用線程池響應多個客戶請求,生產環境毫不能用TSimpleServer。

四、建立客戶端項目也引用ThriftTest1.Contract項目

調用方法

using (TTransport transport = new TSocket("localhost", 8800))
    using (TProtocol protocol = new TBinaryProtocol(transport))
    using (var clientUser = new UserService.Client(protocol))
{
    transport.Open();
    User u = clientUser.Get(1);
    Console.WriteLine($"{u.Id},{u.Name}");
}

3、一個服務器中放多個服務

0.9.1以前只支持一個服務器一個服務,這也是建議的作法。以後支持多路服務在thrift中增長一個服務

修改UserService.thrift文件 添加如下內容 而後從新生成替換

service CalcService{ 
     i32 Add(1:i32 i1,2:i32 i2)
}

服務器:

1.建立CalcServiceImpl文件實現CalcService服務

2.修改Main方法以下:

TServerTransport transport = new TServerSocket(8800);
var processorUserService = new RuPeng.ThriftTest1.Contract.UserService.Processor(new UserServiceImpl())
var processorCalcService = new RuPeng.ThriftTest1.Contract.CalcService.Processor(new CalcServiceImpl());
var processorMulti = new TMultiplexedProcessor();
processorMulti.RegisterProcessor("userService", processorUserService);
processorMulti.RegisterProcessor("calcService", processorCalcService);
TServer server = new TThreadPoolServer(processorMulti, transport);
server.Serve();

客戶端:

using (TTransport transport = new TSocket("localhost", 8800))
    using (TProtocol protocol = new TBinaryProtocol(transport))
    using (var protocolUserService = new TMultiplexedProtocol(protocol, "userService"))
    using (var clientUser = new UserService.Client(protocolUserService))
    using (var protocolCalcService = new TMultiplexedProtocol(protocol,"calcService"))
    using (var clientCalc = new CalcService.Client(protocolCalcService))
{
    transport.Open();
    User u = clientUser.Get(1);
    Console.WriteLine($"{u.Id},{u.Name}");
    Console.WriteLine(clientCalc.Add(1, 2));
}

原文地址:https://blog.csdn.net/qq_18145031/article/details/82802158

相關文章
相關標籤/搜索