<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      NetCore版RPC框架NewLife.ApiServer

      微服務和消息隊列的基礎都是RPC框架,比較有名的有WCF、gRPC、Dubbo等,我們的NewLife.ApiServer建立在網絡庫NewLife.Net之上,支持.Net Core,追求輕量級和高性能,只有最簡單的遠程調用功能。

      現在是網絡系列文章的第五篇,前面四篇快速過了一遍網絡庫基本用法,也做了壓力測試并給出數字 2266萬tps

      本章正式進入應用層面,并且采用.Net Core作為例程,說明我們一開始就支持.Net Core,也算是回答了很多支持者的疑問。

       

      老規矩,先上代碼:https://github.com/NewLifeX/NewLife.Net (例程RpcTest)

      ApiServer源碼:https://github.com/NewLifeX/X/tree/master/NewLife.Core/Remoting

      ApiServer實在太小了,就讓它和Net一起分別作為X組件核心庫的一個目錄。

       

      一、 背景

      ApiServer開始于2014年,我們為了建立物聯網云平臺,解決云端、硬件設備端、手機端、網頁端相互通信,而建立的一套完整的通信體系。

      公司業務需要,在ApiServer上建立了包括服務治理、注冊發現、負載均衡、設備鑒權、通信加密、壓縮、P2SP網絡、WebSocket等等一系列模塊。

      這一套物聯網云平臺已經用在很多家公司上,根據NewLife兩年解封慣例,大概在2019年開源放出大部分源碼。

      本文所指的ApiServer,僅指開源的RPC部分。

      2017年4月1日晚,我們想知道ApiServer的表現,做了一次最大并發數測試,目標是單節點支持100萬設備接入。

      租用60臺阿里云ECS,實際測試單節點最大支持84.5萬模擬設備接入,設備端的心跳包(5~60s) 拖垮了32核服務端。

       

      二、功能特點

      先看看例程最終效果:

      ApiServer主要特點如下:

      1. 支持.Net Core/Net40/Net45,這個最近太熱門了,其實X組件絕大部分功能都支持.Net Core
      2. 多年積累。從2014年起,遇到并解決了很多問題,也去掉了很多可選功能,只保留必要功能
      3. 性能尚可。網絡庫2266tps,ApiServer在40核服務器上單客戶端帶業務測試得到16萬tps
      4. 簡單易用。高仿MVC的Controller風格,支持上下文和執行前后過濾器,客戶端直接Invoke,無需生成Stub代碼,參數無需完全一致,便于多版本兼容
      5. 容易調試。默認通信參數和返回采用Json封送,打開編碼器日志后,遠程調用的收發一目了然。(網絡庫的高性能就是用來給Json浪費的……)
      6. 大包請求。支持收發大數據包(如1M~1000M),特殊服務接口避開Json序列化,直接走二進制。
      7. 支持異常。服務接口拋出的異常,能夠封裝傳遞到客戶端

       

      三、服務端例程

      新建.Net Core 2.0項目RpcTest,我們把服務端客戶端代碼寫到一起。

      服務暴露高仿MVC,一個控制器內可以暴露多個服務方法

      /// <summary>自定義控制器。包含多個服務</summary>
      class MyController
      {
          /// <summary>添加,標準業務服務,走Json序列化</summary>
          /// <param name="x"></param>
          /// <param name="y"></param>
          /// <returns></returns>
          public Int32 Add(Int32 x, Int32 y) => x + y;
      
          /// <summary>RC4加解密,高速業務服務,二進制收發不經序列化</summary>
          /// <param name="pk"></param>
          /// <returns></returns>
          public Packet RC4(Packet pk)
          {
              var data = pk.ToArray();
              var pass = "NewLife".GetBytes();
      
              return data.RC4(pass);
          }
      }

      這里暴露了兩個服務,分別是 加法My/Add 和 加密My/RC4 ,控制器名稱加上方法名,作為尋址路徑。

      不使用Api特性時,控制器類的所有共有方法都將暴露成為服務。

      返回值比較簡單支持,該什么類型就什么類型。理論上來說,支持Json序列化的類型,都可以作為參數和返回類型。

       

      服務方法也可以指定名稱,支持方法過濾接口

      /// <summary>用戶控制器。會話獲取,請求過濾</summary>
      [Api("User")]
      class UserController : IApi, IActionFilter
      {
          /// <summary>會話。同一Tcp/Udp會話多次請求共用,執行服務方法前賦值</summary>
          public IApiSession Session { get; set; }
      
          [Api(nameof(FindByID))]
          public User FindByID(Int32 uid, Boolean deleted)
          {
              // Session 用法同Web
              var times = Session["Times"].ToInt();
              times++;
              Session["Times"] = times;
      
              // 故意制造異常
              if (times >= 2)
              {
                  // 取得當前上下文
                  var ctx = ControllerContext.Current;
      
                  throw new ApiException(507, "[{0}]調用次數過多!Times={1}".F(ctx.ActionName, times));
              }
      
              var user = new User
              {
                  ID = uid,
                  Name = Rand.NextString(8),
                  Enable = deleted,
                  CreateTime = DateTime.Now,
              };
      
              return user;
          }
      
          /// <summary>本控制器執行前</summary>
          /// <param name="filterContext"></param>
          public void OnActionExecuting(ControllerContext filterContext)
          {
              // 請求參數
              var ps = filterContext.Parameters;
      
              // 服務參數
              var cs = filterContext.ActionParameters;
      
              foreach (var item in ps)
              {
                  if (cs != null && !cs.ContainsKey(item.Key))
                      XTrace.WriteLine("服務[{0}]未能找到匹配參數 {1}={2}", filterContext.ActionName, item.Key, item.Value);
              }
          }
      
          /// <summary>本控制器執行后,包括異常發生</summary>
          /// <param name="filterContext"></param>
          public void OnActionExecuted(ControllerContext filterContext)
          {
              var ex = filterContext.Exception;
              if (ex != null && !filterContext.ExceptionHandled)
              {
                  XTrace.WriteLine("控制器攔截到異常:{0}", ex.Message);
              }
          }
      }

      這里控制器和方法都加上了Api特性,特別指定了名稱,公開服務 User/FindByID。

      這里有個硬傷,如果不加Api特性,默認會把 OnActionExecuting/OnActionExecuted兩個方法也暴露成為服務。

       

      實現Api接口,是為了得到Session,這個不是必須的,因為控制器上下文ControllerContext.Current也可以得到這個Session。

      這個Session代表著網絡會話,可以取得各種跟網絡相關的東西,甚至包括直接向客戶端發送數據。

      當然,也可以當做Web的Session來使用,內置有一個字典。

      同一客戶端的Api多次請求,都共用同一個Session對象,可用于做身份驗證,從某種層面上來講,ApiServer是“有狀態”的。

       

      動作過濾接口IActionFilter,讓我們能夠在本控制器所有服務執行前后進行攔截,包括參數預處理和異常攔截。

      服務參數采用Json序列化封送,所以客戶端服務端可以不必要求嚴格一致,跟Http類似,這一點在多版本管理上非常重要,不會說你加了個參數就強制要求所有客戶端跟著升級。

      服務方法內的各種異常,都將會被攔截并送到客戶端,ApiException異常將會得到特殊處理,它包括了一個異常代碼,也送到客戶端。

      沒有異常代碼的各種異常,都將使用默認錯誤代碼500.

       

      最后實例化ApiServer

      static void TestServer()
      {
          // 實例化RPC服務端,指定端口,同時在Tcp/Udp/IPv4/IPv6上監聽
          var svr = new ApiServer(1234);
          // 注冊服務控制器
          svr.Register<MyController>();
          svr.Register<UserController>();
      
          // 指定編碼器
          svr.Encoder = new JsonEncoder();
          svr.EncoderLog = XTrace.Log;
      
          // 打開原始數據日志
          var ns = svr.Server as NetServer;
          ns.Log = XTrace.Log;
          ns.LogSend = true;
          ns.LogReceive = true;
      
          svr.Log = XTrace.Log;
          svr.Start();
      
          _server = svr;
      
          // 定時顯示性能數據
          _timer = new TimerX(ShowStat, ns, 100, 1000);
      }

      中間打開的各種日志,純屬為了便于展示通信過程,實際應用中務必去除!

      ApiServer采用手工注冊控制器的方式,避免了復雜的MVC路由系統。

      內置有一個控制器ApiController,它的All服務用于向客戶端返回所有可用服務列表。

      服務端建立起來后,可以用碼神工具的Api工具調試,(https://github.com/NewLifeX/X/tree/master/XCoder

      四、客戶端例程

      為了便于使用,封裝一個客戶端類

      /// <summary>自定義業務客戶端</summary>
      class MyClient : ApiClient
      {
          public MyClient(String uri) : base(uri) { }
      
          /// <summary>添加,標準業務服務,走Json序列化</summary>
          /// <param name="x"></param>
          /// <param name="y"></param>
          /// <returns></returns>
          public async Task<Int32> AddAsync(Int32 x, Int32 y)
          {
              return await InvokeAsync<Int32>("My/Add", new { x, y });
          }
      
          /// <summary>RC4加解密,高速業務服務,二進制收發不經序列化</summary>
          /// <param name="pk"></param>
          /// <returns></returns>
          public async Task<Packet> RC4Async(Packet pk)
          {
              return await InvokeAsync<Packet>("My/RC4", pk);
          }
      
          public async Task<User> FindUserAsync(Int32 uid, Boolean enable)
          {
              return await InvokeAsync<User>("User/FindByID", new { uid, enable });
          }
      }

      其實這個類不是必須的,看個人喜好吧。

      static async void TestClient()
      {
          var client = new MyClient("tcp://127.0.0.1:1234");
      
          // 指定編碼器
          client.Encoder = new JsonEncoder();
          client.EncoderLog = XTrace.Log;
      
          // 打開原始數據日志
          var ns = client.Client;
          ns.Log = XTrace.Log;
          ns.LogSend = true;
          ns.LogReceive = true;
      
          client.Log = XTrace.Log;
          client.Open();
      
          // 定時顯示性能數據
          _timer = new TimerX(ShowStat, ns, 100, 1000);
      
          // 標準服務,Json
          var n = await client.AddAsync(1245, 3456);
          XTrace.WriteLine("Add: {0}", n);
      
          // 高速服務,二進制
          var buf = "Hello".GetBytes();
          var pk = await client.RC4Async(buf);
          XTrace.WriteLine("RC4: {0}", pk.ToHex());
      
          // 返回對象
          var user = await client.FindUserAsync(123, true);
          XTrace.WriteLine("FindUser: ID={0} Name={1} Enable={2} CreateTime={3}", user.ID, user.Name, user.Enable, user.CreateTime);
      
          // 攔截異常
          try
          {
              user = await client.FindUserAsync(123, true);
          }
          catch (ApiException ex)
          {
              XTrace.WriteLine("FindUser出錯,錯誤碼={0},內容={1}", ex.Code, ex.Message);
          }
      }

      這里做了4次不同調用,模擬了常見場景。

       

      五、總結

      編譯后跑起來就是開頭的效果,感興趣的同學還可以到Linux上試試,也可以新建Net40/Net45項目,同樣可用。

      并且,Net40項目還可以在樹莓派上跑,基于Mono,碼神工具(WinForm)也支持。

       

      RpcTest例程概括性講解了ApiServer的用法,大家可以去嘗試、擴展。

      實際工作中,我們正準備用于建立一個每天數十億次調用的微服務系統。

       

      我是大石頭,打1999年起,19年老碼農。目前在物流行業從事數據分析架構工作,日常工作都是億萬數據的讀寫使用。歡迎大家一起C#大數據!

      posted @ 2018-05-14 00:10  大石頭  閱讀(8847)  評論(29)    收藏  舉報
      主站蜘蛛池模板: 少妇人妻偷人精品免费| 亚洲中文字幕国产精品| 丰满少妇被猛烈进出69影院| 免费AV片在线观看网址| 成人拍拍拍无遮挡免费视频| 国产精品三级在线观看无码| 国产高清午夜人成在线观看,| 国产高清av首播原创麻豆| 亚洲女同性同志熟女| 国产永久免费高清在线| 水蜜桃av导航| 久久永久视频| 幻女free性俄罗斯毛片| 国产 麻豆 日韩 欧美 久久| 一边吃奶一边摸做爽视频| 四虎成人精品国产永久免费| 亚洲欧美日韩综合久久久| 国产揄拍国产精品| 亚洲av无码之国产精品网址蜜芽| 亚洲国产精品无码久久电影| 亚洲香蕉av一区二区蜜桃| 米泉市| 国产不卡精品视频男人的天堂| 少妇又爽又刺激视频| 色欲久久人妻内射| 亚洲乱熟乱熟女一区二区| 午夜免费福利小电影| 日本无码欧美一区精品久久| 不卡一区二区国产在线| 国产精品视频第一第二区| 国产精品久久欧美久久一区| 双腿张开被5个男人调教电影| 国产亚洲一在无在线观看| 日本又色又爽又黄的a片吻戏| 少妇激情一区二区三区视频| 国产精品亚洲二区在线播放| 亚洲欧美日韩精品久久| 久久涩综合一区二区三区| 国产av一区二区三区| 久久精品夜色噜噜亚洲aa| 国产永久免费高清在线观看|