一、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的簡單好多,沒有依賴。