首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >新奥尔良慢用极简用例

新奥尔良慢用极简用例
EN

Stack Overflow用户
提问于 2022-11-03 23:33:56
回答 1查看 111关注 0票数 2

我正在评估新奥尔良的一个新项目,我们即将开始。

最终,我们想要运行一群持之以恒的演员,但我目前正在努力争取在记忆版的新奥尔良成为演员的底线。

给出以下粮食

代码语言:javascript
复制
using Common.UserWallet;
using Common.UserWallet.Messages;
using Microsoft.Extensions.Logging;

namespace Grains;

public class UserWalletGrain : Orleans.Grain, IUserWalletGrain
{
    private readonly ILogger _logger;

    public UserWalletGrain(ILogger<UserWalletGrain> logger)
    {
        _logger = logger;
    }

    public async Task<CreateOrderResponse> CreateOrder(CreateOrderCommand command)
    {


        return new CreateOrderResponse(Guid.NewGuid());
    }

    public Task Ping()
    {
        return Task.CompletedTask;
    }
}

以下筒仓配置:

代码语言:javascript
复制
static async Task<IHost> StartSiloAsync()
{
    ServicePointManager.UseNagleAlgorithm = false;

    var builder = new HostBuilder()
        .UseOrleans(c =>
        {
            c.UseLocalhostClustering()
            .Configure<ClusterOptions>(options =>
            {
                options.ClusterId = "dev";
                options.ServiceId = "OrleansBasics";
            })
            .ConfigureApplicationParts(
                parts => parts.AddApplicationPart(typeof(HelloGrain).Assembly).WithReferences())

            .AddMemoryGrainStorage("OrleansMemoryProvider");
        });

    var host = builder.Build();
    await host.StartAsync();

    return host;
}

以及以下客户端代码:

代码语言:javascript
复制
static async Task<IClusterClient> ConnectClientAsync()
{
    var client = new ClientBuilder()
        .UseLocalhostClustering()
        .Configure<ClusterOptions>(options =>
        {
            options.ClusterId = "dev";
            options.ServiceId = "OrleansBasics";
        })
        //.ConfigureLogging(logging => logging.AddConsole())
        .Build();

    await client.Connect();
    Console.WriteLine("Client successfully connected to silo host \n");

    return client;
}

static async Task DoClientWorkAsync(IClusterClient client)
{
    List<IUserWalletGrain> grains = new List<IUserWalletGrain>();

    foreach (var _ in Enumerable.Range(1, 100))
    {
        var walletGrain = client.GetGrain<IUserWalletGrain>(Guid.NewGuid());
        await walletGrain.Ping(); //make sure grain is loaded
        grains.Add(walletGrain);
    }

    var sw = Stopwatch.StartNew();
    await Parallel.ForEachAsync(Enumerable.Range(1, 100000), async (o, token) =>
    {
        var command = new Common.UserWallet.Messages.CreateOrderCommand(Guid.NewGuid(), 4, 5, new List<Guid> { Guid.NewGuid(), Guid.NewGuid() });

        var response = await grains[o % 100].CreateOrder(command);

        Console.WriteLine($"{o%10}:{o}");
    });

    Console.WriteLine($"\nElapsed:{sw.ElapsedMilliseconds}\n\n");
}

我能在30秒内发送100,000毫希。相当于每秒3333毫希。这比我在看(https://github.com/yevhen/Orleans.PingPong)时所期望的要少得多。

如果我从10粒、100粒或1000粒开始,这似乎也不重要。

当我在配置表存储时添加持久性时

代码语言:javascript
复制
.AddAzureTableGrainStorage(
        name: "OrleansMemoryProvider",
        configureOptions: options =>
        {
            options.UseJson = true;
            options.ConfigureTableServiceClient(
                "secret);
        })

还有一张单曲

等待WriteStateAsync();在CreateOrder中,情况急剧恶化,大约为280个msgs /s

当我更进一步并实现一些基本的域逻辑时。打电话给其他演员等,我们基本上是以1.2msgs/s的速度慢吞吞的

怎么回事?

编辑:

  • 我的cpu在50%左右。
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-11-04 00:28:19

构建高性能的应用程序可能是棘手的和微妙的。在新奥尔良的一般解决方案是,您有许多谷物和许多调用者,因此您可以获得高度的并发性,从而实现吞吐量。在您的例子中,您有许多谷物(100),但是很少有调用者(我相信在默认情况下,Parallel.ForEachAsync是每个核心的一个),每个调用者在每次调用之后都会写信到控制台,这将大大减慢速度。

如果我删除Console.WriteLine并在我的机器上使用Ororle7.0-Rc2运行您的代码,那么对100个谷物的100 K调用将在850 my内完成。如果我将CreateOrderRequest & CreateOrderResponse类型从类更改为结构,则持续时间将减少到750 If。

如果我运行一个更优化的ping测试(一个来自新奥尔良存储库的测试),我会看到我的计算机上每秒大约有550 K请求,其中一个客户端和一个筒仓进程共享同一个CPU。新奥尔良3.x的数字大约是这个数字的一半。如果我在筒仓进程中共同托管客户机(即从筒仓的IServiceProvider中提取IServiceProvider),那么每秒将看到超过500万次请求。

一旦你开始在你的谷物中做一些不平凡的工作,你就会开始遇到其他的限制。最近,我测试了从同一个过程中调用一个粒,发现一个粒可以处理500 K的RPS,如果它正在做一些琐碎的工作(乒乓)。如果每个请求都必须对存储进行写入,而每次存储写入都需要1ms,那么它将无法处理超过1000个RPS,因为每个调用默认等待上一次调用完成。如果您想要选择退出这种行为,可以通过在您的谷物上启用可重入性来做到这一点,如这里的文档:https://learn.microsoft.com/en-us/dotnet/orleans/grains/reentrancy所描述的那样。Chirper示例提供了更多关于如何使用存储更新实现重入的详细信息:https://github.com/dotnet/orleans/tree/main/samples/Chirper

当谷物方法变得更加复杂,需要执行大量的I/O来服务每个请求(例如,存储更新和随后的谷物调用)时,每个单独的谷物的吞吐量就会下降,因为每个请求都需要更多的工作。希望上面的数字能给你一个大致的指导。

票数 9
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/74310628

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档