.NET Core 服務調用 RPC


一、REST & RPC

  微服務之間的接口調用通常包含兩個部分,序列化和通信協議。

  常見的序列化協議包括json、xml、hession(二進制序列化 + http協議)、protobuf、text、bytes等;

  通信比較流行的是http、soap、websockect、TCP,RPC通常基於TCP實現,常用框架例如Dubbo,Netty、Spring Cloud、Thrift、gRpc。

附:TCP、HTTP協議的區別:https://www.jianshu.com/p/f4db4eb065bd

  REST:

  嚴格意義上說接口很規范,操作對象即為資源,對資源的四種操作(post、get、put、delete),並且參數都放在URL上,但是不嚴格的說Http+json、Http+xml,常見的http api都可以稱為Rest接口。采用 Http 進行通訊,優點是開放、標准、簡單、兼容性升級容易。

  RPC:

  即我們常說的遠程過程調用,就是像調用本地方法一樣調用遠程方法,通信協議大多采用二進制方式。RPC 雖然效率略高,但是耦合性強,如果兼容性處理不好的話,一旦服務器端接口升級,客戶端就要更新,即使是增加一個參數,而 rest 則比較靈活。

  最佳實踐:

  對內一些性能要求高的場景用 RPC,對內其他場景以及對外用 Rest。比如付款接口用 RPC 性能會更高一些。 

二、REST實例

在Controller中調用實例:

    [Route("api/[controller]")]
    [ApiController]
    public class AreaController : ControllerBase
    {

        private readonly IBasAreService _AreaService;

        public AreaController(IBasAreService AreaService)
        {
            _AreaService = AreaService;
        }

        // GET api/values
        /// <summary>
        /// 取所有的省份
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public async Task<IEnumerable<BasAreaDto>> GetAreasAsync()
        {
            return  await _AreaService.GetAreaByParentCode("-1");
        }

        // GET api/area/H
        [Route("{fcode}")]
        [HttpGet]
        [ProducesResponseType((int)HttpStatusCode.OK)]
        public async Task<ActionResult<IEnumerable<BasAreaDto>>> GetAreaByParentCode(string fcode)
        {
            if (string.IsNullOrEmpty(fcode))
            {
                return BadRequest();
            }
            var item = await _AreaService.GetAreaByParentCode(fcode);

            if (item != null)
            {
                return item;
            }

            return NotFound();
        }
  ……

三、RPC實例

  Thrift 【θrɪft】 是apache的,可以構建28種語言包括C#,可以無縫結合、高效服務。也可以使用gRpc,不過從網上的性能對比來看,Thrift性能要優於gRpc 2倍以上。對比參考文章:https://yq.aliyun.com/articles/268867

  3.1 Thrift的實例

  1)下載Thrigt,地址:http://thrift.apache.org/download

 

   根據網上說的,解壓之后修改名為thrift.exe,因為這樣方便點,后面要敲命令行的。

  2)編寫一個xxx.thrift文件,這是他的中間語言

  

namespace csharp Blake.Test.Contracts

service PaymentService { 
    TrxnResult Save(1:TrxnRecord trxn) 
}

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

struct TrxnRecord { 
    1: required i64 TrxnId; 
    2: required string TrxnName; 
    3: required i32 TrxnAmount; 
    4: required string TrxnType; 
    5: optional string Remark; 
}

  執行命令行操作,如果發現錄入命令時機器上無法操作,我重新下載一個就好了。

thrift.exe -gen csharp TestRpcService.thrift

 

   3)創建三個項目,一個類庫,一個client控制台,一個Service控制台。為了圖省事,大家別見笑。

  

 

 

   a)服務端的實現代碼

  

    public class PaymentServiceImpl : PaymentService.Iface
    {
        public TrxnResult Save(TrxnRecord trxn)
        {
            
            Console.WriteLine("Log : TrxnName:{0}, TrxnAmount:{1}, Remark:{2}", trxn.TrxnName, trxn.TrxnAmount, trxn.Remark);
            return TrxnResult.SUCCESS;
        }
    }
class Program
    {
        private const int port = 8885;

        static void Main(string[] args)
        {
            Console.WriteLine("[Welcome] PaymentService RPC Server is lanuched...");
            TServerTransport transport = new TServerSocket(port);
            var processor = new PaymentService.Processor(new PaymentServiceImpl());
            TServer server = new TThreadedServer(processor, transport);
            // lanuch
            server.Serve();
        }
    }

  b)客戶端代碼

        static void Main(string[] args)
        {
            TestMethod();
            Console.ReadLine();
        }

        private static void TestMethod()
        {
            using (TTransport transport = new TSocket("localhost", 8885))
            {
                using (TProtocol protocol = new TBinaryProtocol(transport))
                {
                    using (var serviceClient = new PaymentService.Client(protocol))
                    {
                        transport.Open();
                        TrxnRecord record = new TrxnRecord
                        {
                            TrxnId = 123123123,
                            TrxnName = "Blake",
                            TrxnAmount = 12,
                            TrxnType = "",
                            Remark = "已付款成功!"
                        };
                        var result = serviceClient.Save(record);

                        Console.WriteLine($"結果為: {result}");

                    }
                }
            }
        }    

  c)執行結果

 

   因為我用的net core3.1,一開始應用包除了問題,后來搜到apache-thrift-netcore。

 

四、總結

  該文章主要是介紹一個RPC和REST的區別和應用場景,同時簡單的介紹一下Thrift的使用。這樣就可以從代碼看出REST的簡單好多,沒有依賴。


免責聲明!

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



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