【问题标题】:Orleans. Akka.net. Problem with understanding the actor model奥尔良。阿卡网。理解演员模型的问题
【发布时间】:2020-02-07 00:46:21
【问题描述】:

如果你不懂 C#,但你熟悉 Actor 模型,请阅读下面我的问题,因为它更多关于架构和数据管理。

我是一名非常初级的 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. AccountActor;
  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 发送有关帐户更改的消息到新的 Actor,我将在其中调用适当的存储库。但是,这不是瓶颈吗?让我们想象一下有 1000 个在线用户和大约 100 000 个帐户之间的交易。然后负责将帐户更改保存到数据库的参与者可能有太多消息需要处理。

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

感谢您的关注。

【问题讨论】:

  • 将您的思想与演员和数据库分离。假装你只有一个持久化参与者(也许它的存储是一个关系数据库,也许它是一个 no-sql ......或者更奇特的东西)
  • @BozoJoe 你的意思是如果应用程序的所有状态都由保存在数据库中的参与者呈现(我不是指每个业务实体,而是像 akka.persistence)?但是如果我想要一些关系存储,那么我只需要找到一种方法来同步“应用程序状态”(持久参与者)和我的关系存储?对吗?
  • @BozoJoe 认为状态由应用程序本身(参与者)维护是否正确?如果需要,我们会将状态与其他类型的存储同步(可能使用事件溯源)。
  • 你开始明白了
  • @BozoJoe 非常感谢

标签: c# akka.net orleans actor-model


【解决方案1】:

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

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

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

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

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

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

是的,事实上这是强制性的。演员中没有状态,演员也不好。

将这些更改保存到数据库的最佳方法是什么?我读 如果我直接从演员调用数据库,我会 由于操作受阻而失去所有好处。我应该创建 多一个actor来处理来自其他actor的消息并写入 使用存储库更改数据库?

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

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

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

【讨论】:

    猜你喜欢
    • 2013-05-19
    • 1970-01-01
    • 2014-12-29
    • 2018-02-02
    • 1970-01-01
    • 1970-01-01
    • 2011-08-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多