我正在重构一个需要进行大量计算的分析系统,我需要一些关于可能的架构设计的想法来解决我面临的数据一致性问题。
当前架构
我有一个基于队列的系统,其中不同的请求应用程序创建最终由工作人员使用的消息。
每个“请求应用”将大型计算分解为较小的部分,这些部分将发送到队列并由工作人员处理。
当所有部分完成后,原始“请求应用程序”将合并结果。
此外,工作人员使用来自集中式数据库(SQL Server)的信息来处理请求(重要:工作人员不会更改数据库上的任何数据,仅使用它)。
问题
好的。到目前为止,一切都很好。当我们包含更新数据库信息的 Web 服务时,问题就出现了。这种情况随时可能发生,但至关重要的是,源自同一“请求应用程序”的每个“大型计算”都能在数据库中看到相同的数据。
例如:
- 应用A生成消息A1和A2,并将其发送到队列
- 工作线程 W1 获取消息 A1 进行处理。
- 网络服务器更新数据库,从状态 S0 更改为 S1。
- 工作线程W2获取消息A2进行处理
我不能让工作人员 W2 使用数据库的状态 S1。为了使整个计算保持一致,应该使用之前的 S0 状态。
想法
锁定模式,用于防止网络服务器在工作人员使用数据库中的信息时更改数据库。
- 缺点:锁定可能会持续很长时间,因为不同“请求应用程序”的计算可能会重叠(A1、B1、A2、B2、C1、B3 等)。
在数据库和工作线程(通过 req.app 控制数据库缓存的服务器)之间创建新层
- 缺点:添加另一层可能会带来巨大的开销(也许?),而且工作量很大,因为我必须重写工作人员的持久性(大量代码)。
我正在等待第二种解决方案,但对此不太有信心。
有什么绝妙的想法吗?我是否设计错误,或者遗漏了什么?
OBS:
- 这是一个巨大的 2 层遗留系统(C# 语言),我们正在尝试 以最少的努力演变成一个更具可扩展性的解决方案 有可能。
- 每个工作线程可能在不同的服务器上运行。
最佳答案
你可以版本化你的数据库吗?
假设请求应用程序用 ct1 标记计算的开始。现在,此计算生成的每条消息都带有相同的时间戳。
而且每个数据库更新都会用更新时间标记数据库状态。因此,状态 S0 在时间 t0 上,状态 S1 在时间 t1 上,等等。
现在,当工作人员收到消息时,它需要获取更新时间小于或等于消息时间的最大值的数据库状态。在您的示例中,如果 A1 和 A2 都带有 ct1 标记,并且 t1 > ct1,则两个工作线程都将检索 S0 而不是 S1。
这当然意味着您需要在数据库中保存多个版本。如果您知道计算必须在某个时间窗口后完成,您可以在一段时间后清理这些版本。
关于sql-server - 分布式分析系统数据一致性的架构设计,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24788337/