.Net core使用XRPC創建遠程接口的Actor對象


Actor是一種高並發處理模型,每個Actor都有着自己的狀態有序消息處理機制,所以在業務處理的情況並不需要制定鎖的機制,從而達到更高效的處理能性。XRPC是一個基於遠程接口調用的RPC組件,它可以簡單地實現高性能的遠程接口調用;XRPC在創建遠程接口時是支持針對接口創建對應的Actor實例。當創建接口Actor后,所有Client針對這一例實例Actor的所有方法調用都是有序處理。以下介紹如何在XRPC創建並使用Actor

什么場景適用於Actor

既然每個Actor都有着自己的狀態和順序處理機制,那可以針對這優點進行相關業務的展開;在棋牌游戲中的桌子可以是一個Actor,車票里的每一輛車可以是一個Actor,秒殺里的每一種商品是一個Actor。在這些Actor所有的操作都是有序進行,不存在鎖,也不需要事務(通過EventSourcing來保障)和不會產生死鎖;數據變更全內存操作,通過這樣可以大提高業務的處理性能。

引用XRPC

Install-Package BeetleX.XRPC

定義Actor的RPC服務

XRPC支持的Actor服務功能是建立在EventNext之上,它的好處是直接接口行為的Actor創建,而不是傳統的消息加接收方法,這樣在應用設計和調用上也是非常方便靈活。接下來定義一個簡單的Actor服務

  • 接口定義
    1   public interface IAmountService
    2   {
    3       Task<int> Income(int amount);
    4       Task<int> Payout(int amount);
    5       Task<int> Get();
    6   }
    以上是一個簡單的帳記變更行為接口
  • 實現接口

     1   [Service(typeof(IAmountService))]
     2   public class AmountService : ActorState, IAmountService
     3   {
     4 
     5       private int mAmount;
     6 
     7       public override Task ActorInit(string id)
     8       {
     9           return base.ActorInit(id);
    10       }
    11 
    12       public Task<int> Get()
    13       {
    14           return mAmount.ToTask();
    15       }
    16 
    17       public Task<int> Income(int amount)
    18       {
    19           mAmount += amount;
    20           return mAmount.ToTask();
    21       }
    22 
    23       public Task<int> Payout(int amount)
    24       {
    25           mAmount -= amount;
    26           return mAmount.ToTask();
    27       }
    28   }
  • 啟動對應的RPC服務

          private static XRPCServer mXRPCServer;
    
          static void Main(string[] args)
          {
              mXRPCServer = new XRPCServer();
              mXRPCServer.ServerOptions.LogLevel = LogType.Error;
              mXRPCServer.Register(typeof(Program).Assembly);
              mXRPCServer.Open();
              Console.Read();
          }

    以上代碼是在默認端口9090上綁定RPC服務,可以通過運行日志查看服務啟動情況

創建遠程Actor調用

  • 創建RPC Client
    1 client = new XRPCClient("192.168.2.18", 9090);
    2 client.Connect();
    以上代碼是創建一個RPC客戶端,通過它的Create可以創建接口代理
  • 創建接口Actor實例
    IAmountService henry = client.Create<IAmountService>("henry");
    IAmountService ken = client.Create<IAmountService>("ken");
    以上是針對IAmountService創建了兩個Actor對象,這兩個對象的操作都是相互隔離互不干擾;每個Actor對象中的方法在並發下都是有序執行,並不會產生線程安全問題,所以在不同方法中操作對像的數據成員都不需要鎖來保證數據安全性。

測試

為了更好地驗證Actor的隔離和並發安全性,簡單地並發測試一下

 1             for (int i = 0; i < concurrent; i++)
 2             {
 3                 var task = Task.Run(async () =>
 4                 {
 5                     for (int k = 0; k < requests; k++)
 6                     {
 7                         await henry.Income(10);
 8                         System.Threading.Interlocked.Increment(ref mCount);
 9                     }
10                 });
11                 tasks.Add(task);
12                 task = Task.Run(async () =>
13                 {
14                     for (int k = 0; k < requests; k++)
15                     {
16                         await henry.Payout(10);
17                         System.Threading.Interlocked.Increment(ref mCount);
18                     }
19                 });
20                 tasks.Add(task);
21                 task = Task.Run(async () =>
22                 {
23                     for (int k = 0; k < requests; k++)
24                     {
25                         await ken.Income(10);
26                         System.Threading.Interlocked.Increment(ref mCount);
27                     }
28                 });
29                 tasks.Add(task);
30                 task = Task.Run(async () =>
31                 {
32                     for (int k = 0; k < requests; k++)
33                     {
34                         await ken.Payout(10);
35                         System.Threading.Interlocked.Increment(ref mCount);
36                     }
37                 });
38                 tasks.Add(task);
39             }
40             await Task.WhenAll(tasks.ToArray());
41             double useTime = EventCenter.Watch.ElapsedMilliseconds - start;
42             Console.WriteLine($"Completed count:{mCount}|use time:{useTime}|rps:{(mCount / useTime * 1000d):###.00} |henry:{await henry.Get()},ken:{await ken.Get()}");

兩個程序同時在本機跑了一下,在50並發的情況大概是11萬RPS

服務中的Actor隔離性

服務是通過名稱來實例化接口的不同Actor,同一服務即使多個Client同時對一名稱的Actor進行創建服務也可以保證它的唯一性。

完整示例代碼

https://github.com/IKende/XRPC/tree/master/Samples/Actors


免責聲明!

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



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