如何确保所有事情都完成,或者 none 完成?

How to ensure either all things are done, or none is done?

标题可能会产生误导(老实说,我想不出更好的标题)所以请阅读我的解释:

假设我们正在尝试创建用户并更新缓存:

  1. 创建用户并插入数据库。
  2. 用创建的用户更新缓存。

我们正在尝试在创建用户后发布事件(例如在微服务中)

  1. 创建用户并插入数据库。
  2. 使用创建的用户发布活动。

我们正在努力做 n 件事,我们希望确保全部完成或 none。

  1. 创建用户并插入数据库。
  2. 更新缓存。
  3. 发送电子邮件。
  4. 发送短信。
  5. 发布活动,...(不胜枚举)

在没有失败的完美世界中,我们可以按顺序编写它们,仅此而已,但是当我们在用户创建完成后出现失败时会发生什么? (在添加到缓存或发送事件等之前)

这些例子是为缓存例子编造的:

const data = {
  id: 1
};
const user = database.createUser(data);
// Power goes out here (or any kind of failure)
cache.setCache(user);

至此,我们成功创建了用户,但未能更新缓存。

让我们再举一个使用数据库事务的例子:

const data = {
  id: 1
};
const transaction = database.startTransaction();
try {
  const user = database.createUser(data);
  cache.setCache(user);
// Power goes out here (or any kind of failure)
  transaction.commit();
} catch(err) {
  transaction.rollback();
}

在这里,我们已经成功更新了缓存,但由于失败而从未创建用户。

感谢您的宝贵时间。

使用微服务时,我们习惯使用的常见 ACID 事务将不适用。相反,您可以查看 BASE 交易。

看这里:https://www.johndcook.com/blog/2009/07/06/brewer-cap-theorem-base/

An alternative to ACID is BASE:

  • Basic Availability
  • Soft-state
  • Eventual consistency

Rather than requiring consistency after every transaction, it is enough for the database to eventually be in a consistent state. (Accounting systems do this all the time. It’s called “closing out the books.”) It’s OK to use stale data, and it’s OK to give approximate answers.

从技术上讲,这意味着您必须找到一种干净的方法来处理失败,例如在失败的情况下发送事件(这意味着您创建的用户应该从缓存中删除,或者事件发送一封电子邮件,说有一个错误)。

我们经常在订单或支付系统中看到这样的例子,您可以在其中收到一封电子邮件,说订单无法处理。