在 ngx.shared 中缓存 Redis 数据是一个好的实践吗?

我有一些 Lua 代码嵌入在 nginx 中。在这个代码中,我从 Redis 缓存获取一些小数据。我想知道,在使用 ngx.shared 结构在 nginx 中缓存这些数据(已经在某种程度上进行了缓存)是否是一个好的实践?这样做有什么优缺点吗?在伪代码中,我期望有类似如下的内容:

local cache = ngx.shared.cache
local cached_key = cache:get("cached_key")
if cached_key == nil then
    ... 从 Redis 获取数据
    cache:set("cached_key", cached_key)
end
点赞
用户162054
用户162054

如文档所述ngx.shared是nginx服务器中所有工作进程共享的空间。

所有列出的操作都是原子的,因此只有在对ngx.shared连续使用两个操作时,您才需要担心竞态条件。在这种情况下,应使用ngx.semaphore进行保护。

优点:

  • 使用ngx.shared提供了更快速的访问数据,因为您可以避免与Redis服务器的请求/响应循环。
  • 即使您需要一个ngx.semaphore,您也可以期望更快速的访问数据(但我没有提供基准测试)。

缺点:

  • ngx.shared缓存提供不准确的数据,因为您的本地缓存不反映当前Redis值。这并不总是关键点,因为工作进程中使用的值和存储在Redis中的值之间总会存在差值。
  • 存储在ngx.shared中的数据可能不一致,这更为重要。例如,它可以存储x=truey=false,而在Redis中xy始终具有相同的值。这取决于您如何更新本地缓存。
  • 您必须自己处理缓存,即在将其发送到Redis时更新缓存中的值。这可以通过包装Redis函数轻松完成。如果您通过在每次调用redis.get后进行更新来处理更新,那么请预期存在错误,因为您(或他人)忘记它。
  • 您还必须处理读取:每当您的缓存中未找到值时,您必须自动从Redis中读取它。如果您通过在每次调用cache.get后进行读取来处理读取,则请预期存在错误,因为您(或他人)忘记它。

对于最后两点,您可以轻松编写一个小包装器模块。

总之:

  • 如果您的服务器仅运行一个实例,带有一个或多个工作进程,那么使用ngx.shared很有意义,因为您始终可以拥有一个始终更新的Redis数据缓存。
  • 如果您的服务器运行多个实例,并且必须始终具有最新的缓存,或者如果可能存在一致性问题,则应避免使用ngx.shared进行缓存。
  • 在所有情况下,如果您的数据大小可能很大,请确保提供一种在内存消耗过高之前清理它的方法。如果您无法提供清理,则不应使用ngx.shared

此外,不要忘记将缓存的值存储在local变量中,以避免再次get它,从而提高效率。

2017-08-16 14:54:45