首页 > 解决方案 > 使用 Redis 处理多个同时请求的模式

问题描述

A 有一个 API 执行需要 1 分钟处理的查询。如果有人向这个 API 发出 GET 请求,我将执行查询并将结果保存在 Redis 中。

对此 API 的新请求将使用来自 Redis 的缓存数据,避免再次执行此 1 分钟查询。

我的问题是:早上 8 点,我的缓存被删除,因为数据库中有新数据可用。第一个 API 请求将执行 1 分钟长的查询。第二个请求也将执行相同的 1 分钟长的查询,因为第一个请求还没有完成并且 Redis 是空的。

最后,我有数千个查询正在运行,而数据库无法处理所有查询,并且由于数据库停止工作,因此没有查询可以完成。

是否有已知的模式来处理这个问题?

我正在做的是设置一个标志“isQueryRunning”(锁线程安全)以允许每次只执行一个线程,让其他线程等待,但我想知道是否还有其他已知的策略。

标签: c#restredis

解决方案


有几种策略。你提到的那个是有效的,如果有点基本的话,因为它在负载均衡器后面不能很好地工作,因为你的锁不是分布式的。

解决此问题的一种常见方法是将状态存储在持久存储中。在您的情况下,此状态标志可以存储在 Redis 本身中。这让你克服了非分布式锁的问题。

但是,这会占用服务器,因为您正在等待请求线程。在 REST 中,API 简单地检查状态是很常见的,或者

  • 返回过时的数据(在重建缓存时仍然可以使用不同的缓存副本)或

  • 返回一个202 ACCEPTED HTTP 状态,并带有一个LOCATION标头,该标头具有一个指向新数据的 URI。然后客户端可以轮询该位置。这当然意味着您必须编写另一个端点,它将继续返回202直到数据可用,然后要么

    • 返回200和数据,或者
    • 返回301307(重定向回原始 URI)

如果陈旧的数据是可以接受的,那么第一个非常简单。当新数据可用时,您可以简单地在缓存中进行“交换”(非常快)。(顺便说一句,这种交换可能比在替换之前完全删除数据要好)。

第二个当然更复杂,但可以很好地扩展并尽可能避免过时的数据。可以返回的不仅仅是一个位置。您可以返回诸如数据可能的就绪时间(例如 1 分钟)、指示检索到多少数据的值(例如百分比)或其他状态等信息。例如,请参见此处


推荐阅读