【问题标题】:Database base failure in microservice architecture微服务架构中的数据库基础故障
【发布时间】:2021-08-02 00:18:55
【问题描述】:

假设我们在一个微服务架构中

  • 2 个微服务,带有用于同步调用的 API 接口
  • 1 个 RDBMS,每个微服务 1 个 DB
  • 1 个异步呼叫队列系统

用户 A 使用其 API 向微服务 1 的端点发出请求。
端点任务例如计算一些东西,然后将结果放在微服务数据库的一个表中。

用户请求过程中数据库出现故障如何处理?
例子: 在请求期间,数据库崩溃。

那该怎么办?

返回错误?但是有什么错误? 500?

但是微服务架构不是应该避免这种类型的耦合吗?
我们应该让系统更松耦合吗?
微服务是否将数据保存在本地文件或队列中,然后重试插入数据库?
但是用户呢?他不可能检索/更新它刚刚创建的数据,让系统从本地数据返回结果....但这很复杂,不是吗?
我们怎样才能做到这一点...

我对队列系统的使用也有同样的疑问。 在事件驱动的设计中,我们在微服务中拥有消费者和生产者。
消费者在事件总线中收听主题,然后可以在其数据库中插入数据。
当在 DB 上为自己的数据插入操作时触发生产者并将其发送到主题上的事件总线时,将调用生产者。

想象一下事件总线崩溃......
如果是这样,消费者也会在微服务中崩溃。
如果发生 db insert,生产者无法将事件发送到事件总线......
所以数据丢失了?
那么生产者是否应该将数据保存在其本地存储中以供重试?

我在脑海中多次回答这个问题,但我没有一个弹性系统。

【问题讨论】:

    标签: microservices


    【解决方案1】:

    返回错误?但是有什么错误? 500?

    是的,返回错误。从您的微服务返回错误并没有错。如果您的数据库出现故障,通常“500 Internal Server Error”是正确的错误。这是 Rest API 的标准行为。

    但是微服务架构不是应该避免这种类型的吗? 耦合?我们应该让系统更松耦合吗?

    我认为这里存在混淆。微服务与自己的数据库通信不被视为耦合。 Micro-service-A 正在使用其获得的数据库 micro-service-A-database 被视为一个逻辑单元或垂直。如果没有它的数据库,微服务 A 就没有多大用处,反之亦然。这完全没问题,您可以以与标准 WebApplication 类似的方式查看它的前端、后端(类似于您的服务)和数据库。应避免不同微服务之间的耦合。例如,微服务 A 不应与微服务 B 或微服务 C 紧密耦合。每个微服务都应该是原子的,并且尽可能独立,但不能独立于其数据库、缓存或类似的东西。您可以将数据库视为它的逻辑部分。

    微服务是否应将数据保存在本地文件或队列中? 重试插入数据库?

    不,预计数据库可能会失败,或者至少您还必须处理该选项。从用户的角度来看,您只会返回错误代码 500。至少在大多数情况下,这将是预期的行为。在某些特殊情况下,您希望不惜一切代价保存数据而不是因为该请求而丢失数据(也有一些方法可以处理这种情况)。

    但是用户呢?

    如果是标准网络用户,他会重试几次,如果问题仍然存在,则可能稍后再试(此处返回错误 500 没有任何问题)。如果用户的意思是另一个微服务正在执行调用,那么调用者微服务必须预期会发生故障。现在这取决于你在这里做什么?假设微服务 A 正在使用 Http 请求调用微服务 B:

    • Get Call:这里你可以在微服务A中建立重试策略,如果微服务B在重试后返回500,你可以向调用微服务B的用户返回错误.
    • Post/Put/Patch Call:您也可以在此处尝试与 Get Calls 类似的操作,但前提是涉及 1 项服务。如果您有微服务-A 调用微服务-B,然后是微服务-C,并且如果一个调用成功(保存了一些数据)而另一个调用失败,则必须考虑 Sagas(如果操作应该是事务性的) .

    想象一下事件总线崩溃......如果是这样,消费者也会崩溃 在微服务中。

    如果您的本地微服务数据库崩溃,那么所有其他渠道也应该崩溃。如果您无法将实体保存在本地微服务数据库中,为什么还要进一步执行诸如将消息发布到队列之类的操作?您的数据/实体的真实来源是数据库(至少在大多数情况下)。因此,如果数据库失败,您应该抛出异常并向调用者/用户返回错误。

    如果 db insert 发生,生产者无法将事件发送到事件 总线....所以数据丢失了?生产者也应将数据保存在本地 重试存储?

    因此,如果您将数据/实体保存在数据库中并且队列不可用,您可以简单地将消息/事件保存到数据库中的表中,然后在队列启动时发布消息/事件,并且再次运行。实际上,在这种情况下,这是一种非常常见的模式。例如,您的实现可能是事务性的:

    1. 将实体保存到其表中并
    2. 将事件/消息保存到事件表。这样,如果一个人失败了 操作将被回滚。

    您可以让后台工作人员(取决于您用于后端的技术)以异步方式将消息发布到队列中。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-03-25
      • 2020-09-12
      • 1970-01-01
      • 2019-03-03
      • 2020-08-17
      • 2020-07-05
      • 2017-09-09
      • 2017-11-30
      相关资源
      最近更新 更多