我正在开发一个rest服务,它接受用户请求。每个用户请求都意味着繁重的计算工作。我不想让计算工作阻塞rest服务。我的设计是将用户请求 Package 为一个任务(具有唯一的任务id)并推送到kafka。后台工作人员订阅Kafka并处理任何传入的任务。rest服务将任务保存到数据库中,将任务id推送到kafka,然后立即返回任务id。用户使用任务id继续轮询任务状态。
这个设计很好。但是我仍然不知道如何处理一个场景:如果在将任务保存到数据库之后,但在将任务id推送到kafka之前,服务立即崩溃(例如进程关闭、容器停用),那么该任务将永远不会被处理。
这是一个边缘的情况,可能很少发生。但在服务重新启动或重新部署期间,可能会发生这种情况。那么,我如何使这两个操作(保存到数据库和推到Kafka)原子化呢?或者有解决办法吗?
1条答案
按热度按时间wxclj1h51#
假设您有一条正在处理的消息,那么在处理过程中最不应该发生的事情就是应该确认该消息。那么,让我们假设在最佳流动状态下发生以下情况:
公称流量
代理将消息放入队列
这个工人拉着信息
辅助进程更新数据库中任务的状态
工人开始计算
工人计算完毕
worker将结果存储在数据库中
工人将任务id推给kafka(我不知道这到底是做什么的)。
worker向代理发送消息完成的确认
代理丢弃已成功处理的消息。
非标称流量
你的问题涉及6到7之间的中断。如果中断发生在这里,根据标称流,那么确认将不被发送,消息将在队列的头部被替换。
需要做的是在第2步和第3步之间调整您的标称处理顺序。在开始处理消息之前,让工作人员检查数据库中的现有结果。如果已经计算了结果,则可以跳到步骤7并从那里继续。