Redis:原子性获取和条件设置

7
我想在Redis中执行一个原子GET,如果返回的值等于某个期望值,我想要做一个SET,但我希望将所有这些操作链接在一起作为一个原子操作。(我正在尝试设置一个指示是否有任何进程正在将数据写入磁盘的标志,因为只允许一个进程这样做。)
在Redis中是否可以实现这一点?
我已经看到了关于MULTI操作的文档,但我还没有看到条件操作i MULTI操作。如果有其他建议,将不胜感激!

你可以使用Lua脚本在Redis端完成所有操作:https://redis.io/commands/eval - Chris Tanner
1
@ChrisTanner 把这个变成一个答案,我会点赞的。 - Itamar Haber
如果其他人也想创建写锁,这是一篇很棒的阅读材料:https://redis.io/topics/distlock - duhaime
5个回答

6

您可以使用Lua脚本在redis服务器上执行GET和SET操作。这些操作是原子性的,同时还允许您添加逻辑。


谢谢您的想法。您是否知道有哪些适合初学者的简单Lua脚本在Redis中的教程示例?我以前没有使用过Lua,所以想从一些真正的基础开始... - duhaime
1
这两个页面让我找到了正确的方向,实现了你所寻找的功能。链接如下:https://www.redisgreen.net/blog/intro-to-lua-for-redis-programmers/ 和 https://www.compose.com/articles/a-quick-guide-to-redis-lua-scripting/。 - Kim Burgaard

1
我在寻找类似的函数时遇到了这篇文章,但是我没有看到任何吸引我的选项。相反,我选择用Rust编写了一个小模块,提供了这种精确类型的操作:

https://github.com/KennethWilke/redis-setif

使用此模块,您可以通过以下方式完成:

SETIF <key> <expected> <new>
HSETIF <key> <field> <expected> <new>

1
我最终使用了redlock-py,这是Redis文档推荐用于创建写锁的redlock算法的一种实现:https://redis.io/topics/distlock。这篇文章对于任何想在Redis中创建类似写锁的人来说都是非常好的阅读材料。

0

redis-if - 一个用于“条件事务”的Lua脚本。比WATCH + MULTY更方便。

您可以将任何组合的条件和后续命令作为JSON对象传递:

const Redis = require('ioredis')

const redis = new Redis()

redis.defineCommand('transaction', { lua: require('redis-if').script, numberOfKeys: 0 })

await redis.set('custom-state', 'initialized')
await redis.set('custom-counter', 0)

// this call will change state and do another unrelated operation (increment) atomically
let success = await redis.transaction(JSON.stringify({
  if: [
    // apply changes only if this process has acquired a lock
    [ 'initialized', '==', [ 'sget', 'custom-state' ] ]
  ],
  exec: [
    [ 'set', 'custom-state', 'finished' ],
    [ 'incr', 'custom-counter' ]
  ]
}))

通过这个脚本,我们从项目中删除了所有自定义脚本。


0

您可以通过SET命令来实现此操作,根据文档这里提供的两个参数:

GET - 返回存储在键中的旧字符串,如果键不存在则返回nil。

NX - 仅在键不存在时设置键。

由于Redis不会在运行另一个命令时执行任何命令-因此您可以以原子方式执行这2个操作。


重要提示:从Redis 7.0.0版本开始,允许同时使用NX和GET选项。 - Yehezkel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接