【发布时间】:2019-01-20 17:17:09
【问题描述】:
两个问题
- lua 脚本真的可以解决所有 redis 事务的情况吗?
- 来自一个客户端的异步事务的最佳做法是什么?
让我解释一下,第一期
Redis 事务受到限制,无法unwatch 特定键,并且所有键在exec 上都无人关注;我们仅限于给定客户端上的单个正在进行的交易。
我见过threads,许多redis 用户声称他们只需要lua 脚本。甚至 redis 官方文档也声明他们可能会删除事务以支持 lua 脚本。但是,也有这样不够的情况,比如最标准的情况:使用redis作为缓存。
假设我们想在 redis 中缓存一些来自持久数据存储的数据。这是一个快速的过程:
- 检查缓存 -> 未命中
- 从数据库加载数据
- 存储在 redis 中
但是,如果在第 2 步(加载数据)和第 3 步(存储在 redis 中)之间,数据被另一个客户端更新了怎么办?
存储在 redis 中的数据将是陈旧的。所以......我们使用redis事务对吗?我们在从 db 加载之前watch 密钥,如果密钥在存储之前在其他地方更新,存储将失败。伟大的!但是,在原子 lua 脚本中,我们无法从外部数据库加载数据,因此此处不能使用 lua。希望我只是遗漏了一些东西,或者我们的流程有问题。
继续第二期(异步事务)
假设我们有一个 socket.io 集群,它处理各种消息和游戏请求,用于服务器和客户端之间的高速通信。这个集群是用 node.js 编写的,适当地使用了 Promise 和异步概念。
假设有两个请求到达我们集群中的一个服务器,这需要在 redis 中加载和缓存数据。使用上面的事务,可以监视多个键,并且多个 multi->exec 事务将在一个 redis 连接上以重叠的顺序运行。一旦第一个 exec 运行,所有被监视的键都将不被监视,即使另一个事务仍在运行。这可能允许第二个事务在它应该失败时成功。
这些重叠可能发生在同一服务器上发生的完全不同的请求中,如果需要同时加载多种数据类型,有时甚至可能发生在同一个请求中。
这里的最佳做法是什么?我们是否需要为每个单独的事务创建单独的 redis 连接?似乎我们会损失很多速度,如果是这种情况,我们会看到许多连接仅从一台服务器创建。
作为替代方案,我们可以使用 redlock / mutex 锁定代替 redis 事务,但相比之下这很慢。
任何帮助表示赞赏!
【问题讨论】:
标签: redis transactions