【问题标题】:CQRS and eventual consistencyCQRS 和最终一致性
【发布时间】:2018-08-20 20:33:57
【问题描述】:

我已被添加到一个正在开发的项目中。这是一个使用 Mediatr 和 CQRS 模式的 ASP.Net MVC 5 应用程序(具有只读数据库和只写数据库 - 最终一致)。该应用程序有一个管理部分,其中包含大量 CRUD 操作,我们遇到了问题。例如,假设有一个 Widget Controller:

public class WidgetController : Controller
{
    private readonly IMediator _mediator;

    public WidgetController(IMediator mediator)
    {
        _mediator = mediator;
    }

    // GET: Widget
    public ActionResult Index()
    {
        // Reads from the read-only database and may not have synced
        // This call is not guaranteed to have the newly added or edited widget (and usually doesn't)
        var allWidgets = _mediator.Send(new GetAllWidgets());
        return View(allWidgets);
    }

    [HttpPost]
    public ActionResult Create(Widget widget)
    {
        try
        {
            // This call contains the database logic to write into the write only database
            _mediator.Send(new CreateWidget(widget));
            return RedirectToAction("Index");
        }
        catch
        {
            return View();
        }
    }

    [HttpPost]
    public ActionResult Edit(Widget updatedWidget)
    {
        try
        {
            // Writes to the write-only database
            _mediator.Send(new UpdateWidget(updatedWidget));
            return RedirectToAction("Index");
        }
        catch
        {
            return View();
        }
    }
}

在“创建”和“编辑”操作中,创建或编辑小部件,并且对只写数据库进行这些更改。随后立即重定向到从只读数据库读取的索引操作。在此调用完成并呈现视图时,这些更改通常不会从只写数据库同步。为了解决这个问题,我们使用 Redis 来缓存新创建或更新的对象,然后如果在 Index 操作中检索到的列表不包含新的或编辑的对象,我们会从缓存中检索它。 这感觉非常非常错误。

由于我们项目中的任何人都没有参与过 CQRS 项目,因此我们不知道如何解决这个问题。感觉我们真的错过了这种模式的一些东西。

所以,我想我要问的是......是否有处理这种情况的最佳实践?有没有更好的方法来做到这一点?

【问题讨论】:

    标签: cqrs eventual-consistency


    【解决方案1】:

    在 CQRS 中,写入持久性和读取持久性是分开的(逻辑上、时间上甚至物理上),您所经历的都是正常的,您应该接受这一点,而不是将其视为根本问题。相反,您应该修改您的客户端以弥补这一点。例如,您应该调用以更新后台实体(即 AJAX),而不是将客户端重定向到编辑页面。这是最简单的解决方案之一。其他更复杂,例如使用相关或因果标识符、最后修改的时间戳、在应用程序或表示层等待读取模型处理事件等。

    【讨论】:

      【解决方案2】:

      所以,我想我要问的是......是否有处理这种情况的最佳实践?有没有更好的方法来做到这一点?

      您需要的许多部件已经到位。

      考虑 CQRS 的一种方式是写入发生在域模型的实时表示上,而读取发生在缓存的表示上。

      HTTP 对caching 有很好的理解。特别是,HTTP 感知缓存了解不安全操作invalidate 缓存表示。所以任何对 POST 请求的非错误响应都会使缓存的数据失效。

      你甚至有一个状态码来处理最终的一致性; 202 Accepted 向中介宣布请求不是错误(使缓存无效),而是“处理尚未完成”。与200 response 非常相似,有效负载是“操作状态的表示”。

      因此,您可以向客户端发送 202 Accepted 并带有指向状态监视器的链接,其中包含了解读取模型是否已更新所需的信息。例如,写入模型可能知道您正在等待的对象的“版本”,或者有多少事件(如果您正在进行事件溯源),或者帖子本身的 correlation identifier
      将此元数据编码到状态监视器的目标资源中,客户端可以轮询状态监视器,直到它指示读取模型已更新。

      甚至还有对弱验证器的理解,它可以通过修改操作返回以指示资源的版本,而无需知道强验证器所需的表示的细节。

      但是...我承认我没有发现各种各样的部分会产生令人满意的整体。感觉好像少了一个东西——让我们返回一个带有动作状态表示的验证器,帮助客户端发出适当的条件请求来读取表示。

      【讨论】:

        【解决方案3】:

        快速搜索how to handle the eventual consistency。在我的项目中,我们主要依赖 websocket 通知(即SignalR),但有时“假响应”是一种足够好的方法。

        我想知道为什么您使用 CQRS,特别是用于 CRUD 操作。看起来如果你过度设计你的设计。 Asyncronicity comes with a lot of issues to face

        【讨论】:

        • 我无法回答原因。这是在我加入该项目之前很久就决定的。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-06-25
        • 1970-01-01
        • 2018-12-20
        • 1970-01-01
        • 2015-06-05
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多