通过云服务 API 创建无服务器(Serverless)数据库
下面我们来演示如何在 AWS 中创建一个无服务器数据库。
无服务器即 Serverless,并不是真的没有服务器,而是开发者不需要关心和维护对应的硬件服务器资源,而是可以通过软件方式创建和编排服务器,是一种云原生开发模式。国内腾讯云、阿里云亦可,基本流程一样,具体的 API 不同而已,你可以下载对应平台的 SDK,并根据官方文档调用相应的 API 实现。
编写任务类
要实现这个功能,需要创建网络、然后分配访问权限、最后创建数据库。我们为每个操作创建一个对应的任务类。
以上每一步可能都要耗费几分钟才能完成,开始处理时,AWS 会返回 provisioning
状态,我们会监控资源直到状态值变成 active
,上一步操作的状态没有变成 active
就不能进行下一步操作。
负责创建网络的 EnsureANetworkExists
任务类的 handle
方法如下所示:
如果网络不存在,则创建一个新的并等待其状态变成 active
(通过重新执行任务模拟多进程阻塞)。
负责分配访问权限的 EnsureNetworkHasInternetAccess
任务类 handle
方法与之类似:
最后是负责创建数据库的 CreateDatabase
任务类,其 handle
方法如下所示:
分发任务链
上面三个步骤需要一个接一个运行,如果其中某个步骤执行失败,还需要清理对应资源。
可以将其类比为数据库事务,所有语句执行成功才会提交,否则进行回滚操作。
这是一个典型的责任链模式,在消息队列中,我们可以将其称之为任务链,Laravel 的 Bus
服务提供了分发任务链的方法:
使用 Bus::chain
传入队列任务,然后调用 dispatch
进行分发即可。
和批处理不同,任务链是串行处理的,如果某个任务没有执行成功,则一直重试到成功才会继续执行下一个任务,如果某个任务执行失败,则整个任务链会被删除。
处理任务链执行失败
如果任务链执行失败,则需要回滚所有已执行任务,在某些场景下,这非常简单,只需要删除所有创建的资源即可,在我们这个场景下,稍微复杂一些。
从网络中移除访问权限之前,还需要确保它们没有被其他资源使用。和完全移除网络一样,这个智能移除任务链影响的过程称为「补偿事务」:
首先,我们需要检查网络是否被其他资源使用,如果没有就可以删除了,不过,如果网络被其他资源使用,但是不涉及到访问权限,则只能删除访问权限,不能删除网络。
要运行这个补偿事务,可以在 catch
代码块中处理:
如果任务链中的某个任务运行失败,则会执行 catch
中的闭包函数进行回滚处理。
注:一个任务运行失败意味着已经尝试了该任务类配置的
retries
次数。catch()
方法的闭包函数调用时,队列任务类的failed
方法也会被调用。
保持补偿事务的精简
catch
中的闭包会在任务用完所有尝试次数后执行,该操作在任务从队列中移除、获取下一个任务之前完成。
如果任务运行时间+闭包执行时间超过了任务的超时时间,队列处理器会立即退出,导致系统出现状态不一致的情况。
所以,要确保 catch
闭包的代码或者任务类的 failed
方法尽可能精简,如果你想要执行更多工作,可以将其分发到另一个队列任务中执行:
No Comments