首页 > 解决方案 > 奥尔良。阿卡网。理解演员模型的问题

问题描述

如果您不了解 C# 但您熟悉演员模型,请阅读下面的问题,因为它更多地是关于架构和数据管理。

我是一名非常初级的 C# 开发人员,并试图了解演员模型是什么。我已经完成了它,但它留下了我无法得到的一点。

在我告诉你一个问题之前,让我描述一下上下文,以便为你提供更好的理解。

作为一个测试示例,我想为一家假想的银行构建一个应用程序。我将通过使用 akka.net 和 Orleans 来实现这个应用程序,用于学习目的并能够比较它们。

用例:

因此,有以下实体:

识别用户与其帐户之间的一对一关系。我将使用 ORM 将这些数据存储在我的数据库中。显然,模型看起来像这样:

public class User
{
    public Guid Id { get; set; }
    public string FullName { get; set; }
    ....
}

public class Account
{
    public Guid Id { get; set; }
    public string UniqueNumber { get; set; }
    public string Balance { get; set; }
    ...
}

而且我还想要两个演员/谷物:

  1. 会计演员;
  2. 交易服务;

他们的接口:

//Or IAccountGrain
public interface IAccountActor
{
    void Deposit(Money amount);
    void Withdraw(Money amount);
}

//Or ITransactionGrain
public interface ITransactionActor
{
    void Transfer(IAccountActor from, IAccountActor to, Money amount);
}

我不明白的是如何处理关系数据库中的数据。让我们想象以下场景:

50 位用户在线,通过客户端应用程序向应用程序的 REST API 发起请求。他们几乎没有任何停顿地取款、存款和转账。

问题是:

  1. 我应该为每个用户帐户创建一个演员吗?我很确定我需要,因为这样我才能在不同账户之间实现数千笔交易。
  2. 如何将用户帐户与 AccountActor 关联?如果我在演员激活/启动之前使用存储库从数据库加载数据并设置状态,是否正确?

主要问题: 如何将状态保存回数据库?

让我们想象一个有 1000 美元的账户 A。并且它发生了大约 100 次由涉及该帐户的用户发起的交易。帐户 A 将其状态从消息更改为消息。

将这些更改保存到数据库的最佳方法是什么?我读到如果我直接从参与者调用数据库,我将因为阻塞操作而失去所有好处。

我是否应该再创建一个参与者来处理来自其他参与者的消息并使用存储库将更改写入数据库?

我的意思是我可以从 AccountActor 发送有关帐户更改的消息到我将调用适当存储库的新演员。但是,这不是瓶颈吗?让我们想象一下有 1000 个在线用户和大约 100 000 个帐户之间的交易。然后负责将帐户更改保存到数据库的参与者可能有太多消息需要处理。

对不起,很长的文字。我试图找到使用 Orleans 或 Akka.net 的应用程序示例,但我没有找到任何使用数据库的东西。

谢谢你的关注。

标签: c#akka.netorleansactor-model

解决方案


您在这里缺少一些想法,但让我们按顺序回答问题。

我应该为每个用户帐户创建一个演员吗?我很确定我需要,因为这样我才能在不同账户之间实现数千笔交易。

我假设您正在考虑的替代方案是每个用户帐户多个参与者,这是错误的。每个用户帐户只能有一个参与者,否则您将遇到您描述的问题,即同时请求可以提取相同的钱两次。

如何将用户帐户与 AccountActor 关联?

您缺少拥有 AccountActor 的 UserActor。没有所有者,帐户就无法存在,否则我们不知道谁拥有帐户中的资金。在现实世界中,通常不会向随机账户汇款。他们想将其发送给一个人,并使用发件人用户角色帐户来执行此操作。

如果我在演员激活/启动之前使用存储库从数据库加载数据并设置状态,是否正确?

是的,事实上这是强制性的。没有演员的状态,演员就不会有多大的好处。

将这些更改保存到数据库的最佳方法是什么?我读到如果我直接从参与者调用数据库,我将因为阻塞操作而失去所有好处。我是否应该再创建一个参与者来处理来自其他参与者的消息并使用存储库将更改写入数据库?

你在正确的轨道上,但还没有完全到那里。演员状态的保存是通过异步方法写入数据库的。使用异步方法,主线程不会阻塞等待数据库写入发生,因此处理线程可以继续其业务。

当一个动作只涉及一个actor时,它可以通过异步方法保存自己的状态。在银行寄存器中,总是涉及 2 个帐户,并且对这两个帐户的写入必须成功或失败,从来没有一个成功和一个失败。因此,TransactionActor 将打开一个 DB 事务并告诉每个 AccountActor 使用该 DB 事务保存其状态。如果其中一个失败,它会中止事务并且两者都失败。请注意,此方法是 TransactionActor 上的私有异步方法,因此您可以获得并行处理的好处。

顺便说一句,您在奥尔良找不到任何写入数据库的示例,因为这一切都由框架为您处理。保存方法是自动异步的,它们与数据库交互。您在奥尔良所做的只是引用 Actor 并且状态会自动为您从数据库中提取。


推荐阅读