.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的简单好多,没有依赖。

原文地址:https://www.cnblogs.com/kokyu02/p/12500485.html