[orleans2.1]這是你沒玩過的船新版本


  不知不覺orleans就發布到2.1版本的,但是說也奇怪orleans越是完善我發現園子相關的博客就越少,大概是大佬都在美滋滋用在生產環境,不屑於玩demo了吧。

  但是小弟不才還是只會玩demo,所以只能簡單的介紹介紹2.1版本的新玩法了。

  1.新建一個asp.net core的webapi項目,然后引用下面幾個nuget包:

1 Microsoft.Orleans.OrleansRuntime
2 Microsoft.Orleans.CodeGenerator.MSBuild
3 Microsoft.Orleans.Transactions
4 Orleans.Providers.MongoDB
5 OrleansDashboard

  2.包裝一下orleans的silobuilder類,並且繼承IHostedService直接和asp.net core運行在一起

 1     public class SiloWrapper : IHostedService
 2     {
 3         private readonly ISiloHost _silo;
 4         public readonly IClusterClient Client;
 5 
 6         public SiloWrapper()
 7         {
 8             _silo = new SiloHostBuilder()
 9                 .UseLocalhostClustering()
10                 .ConfigureApplicationParts(parts =>
11                     parts.AddApplicationPart(typeof(Grains.IUserGrain).Assembly).WithReferences())
12                     .EnableDirectClient()//2.1新增的功能,單個Host可以直接使用SiloHost的Client,不需要再用ClientBuilder建Client了
13                     .AddMongoDBGrainStorageAsDefault(options =>
14                     {
15                         options.ConnectionString = "mongodb://localhost/OrleansTestApp";
16                     })//配置數據庫
17                     .ConfigureLogging(x =>
18                     {
19                         x.AddConsole();
20                         x.SetMinimumLevel(LogLevel.Warning);
21                     })
22                     .UseDashboard(x =>
23                     {
24                         x.HostSelf = false;
25                     })//HostSelf設置為false
26                     .UseTransactions()//2.1的事務配置簡化了
27                     .Build();
28 
29             Client = _silo.Services.GetRequiredService<IClusterClient>();//把sliohost的IClusterClient暴露出去。
30         }
31 
32         public async Task StartAsync(CancellationToken cancellationToken)
33         {
34             await _silo.StartAsync(cancellationToken);
35         }
36 
37         public async Task StopAsync(CancellationToken cancellationToken)
38         {
39             await _silo.StopAsync(cancellationToken);
40         }
41     }

  3.Startup類配置:

 1     public class Startup
 2     {
 3         public Startup(IConfiguration configuration)
 4         {
 5             Configuration = configuration;
 6         }
 7 
 8         public IConfiguration Configuration { get; }
 9 
10         public void ConfigureServices(IServiceCollection services)
11         {
12             services.AddSingleton<SiloWrapper>();//注入SiloWrapper
13             services.AddSingleton<IHostedService>(x=>x.GetRequiredService<SiloWrapper>());//同時把SiloWrapper注入為IHostedService
14             services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
15             services.AddSingleton(x => x.GetRequiredService<SiloWrapper>().Client);//注入SiloWrapper的Client
16             services.AddServicesForSelfHostedDashboard();//注入orleans的dashboard
17         }
18 
19         public void Configure(IApplicationBuilder app, IHostingEnvironment env)
20         {
21             if (env.IsDevelopment())
22             {
23                 app.UseDeveloperExceptionPage();
24             }
25 
26             app.UseOrleansDashboard(new OrleansDashboard.DashboardOptions { BasePath = "/dashboard"});//設置一下dashboard的訪問路徑
27             app.UseMvc();
28         }
29     }

  4.新建一些Grain類,這里只給出一個后面我會貼代碼地址出來。

    public class UserGrain:Grain<UserInfo>,IUserGrain
    {
        public ValueTask<UserInfo> GetInfo()//同步代碼可以返回ValueTask
        {        
            return new ValueTask<UserInfo>(State);
        }

        public async Task<UserInfo> UpdateInfo(UserInfo info)
        {
            State = info;
            await WriteStateAsync();//更新數據才需要數據庫相關的操作
            return State;
        }

        public async Task<uint> GetBalance()
        {
            var account = this.GrainFactory.GetGrain<IAccountGrain>(this.GetPrimaryKeyLong());//通過GrainFactory訪問其他grain
            return await account.GetBalance();
        }
    }
    [StatelessWorker]
    public class ATMGrain : Grain, IATMGrain//轉賬事務的專用grain
    {
        Task IATMGrain.Transfer(long fromAccount, long toAccount, uint amountToTransfer)
        {
            return Task.WhenAll(
                this.GrainFactory.GetGrain<IAccountGrain>(fromAccount).Withdraw(amountToTransfer),
                this.GrainFactory.GetGrain<IAccountGrain>(toAccount).Deposit(amountToTransfer));
        }
    }

    public class AccountGrain : Grain, IAccountGrain//加錢,減錢,查錢啦
    {
        private readonly ITransactionalState<Balance> _balance;

        public AccountGrain(
            [TransactionalState("balance")] ITransactionalState<Balance> balance)
        {
            _balance = balance ?? throw new ArgumentNullException(nameof(balance));
        }

        async Task IAccountGrain.Deposit(uint amount)
        {
            await _balance.PerformUpdate(x => x.Value += amount);
        }

        async Task IAccountGrain.Withdraw(uint amount)
        {
            await _balance.PerformUpdate(x =>
            {
                if (x.Value < amount)
                {
                    throw new InvalidOperationException( "The transferred amount was greater than the balance.");
                }
                return x.Value -= amount;
            });
        }

        Task<uint> IAccountGrain.GetBalance()
        {
            return _balance.PerformRead(x => x.Value);
        }
    }

 5.controller相關的代碼,這里也是照舊只貼一部分

    [Route("api/[controller]")]
    public class ValuesController : Controller
    {
        private readonly IClusterClient _client;

        public ValuesController(IClusterClient client)
        {
            _client = client;
        }

        [HttpGet("[action]/{id}")]
        public async Task<object> GetInfo(long id)
        {
            var userGrain = _client.GetGrain<IUserGrain>(id);
            return await userGrain.GetInfo();
        }
   }    

  代碼地址:https://github.com/iJzFan/orleansdemo

  可以看到2.1之后配置真的簡單了很多,簡單幾步之后你就能快樂的進行無數據庫設計無並發考慮的編程啦。

  最后面是我用jmeter做的一個小測試(不是特別嚴謹,日志都是開着的,不要太糾結數據),配置嘛就是那個1核兩G的騰訊雲垃圾主機啦,上面跑了一個兩個docker,一個是前面的orleansdemo,一個是mongodb。

  測試條件就是用戶1和用戶2相互轉賬( ̄︶ ̄)↗ ,10個線程,分別轉1000次(對應的URL:/api/values/atm?from=1&to=2&amount=1和/api/values/atm?from=2&to=1&amount=1)。

  測試條件就是1轉2,2轉3,3轉4,4轉1,10個線程,分別轉500次(url參考上面)。

  時延還是挺低的,平均才55~61ms,騰訊雲那個垃圾主機一秒都能處理150~160的事務請求。

  最最后面貼幾個orleans相關的代碼庫,畢竟我上面的demo還是太小兒科了,

  https://github.com/RayTale/Ray 分布式、高性能、事件溯源、事件驅動、最終一致性框架

  https://github.com/Squidex/squidex Headless CMS and Content Managment Hub

 


免責聲明!

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



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