美文网首页
redis getOrSet 要么取出要么设置 实现

redis getOrSet 要么取出要么设置 实现

作者: Yellowtail | 来源:发表于2021-01-15 20:37 被阅读0次

背景

工作中遇到这么一个场景:
并发场景下,分布式下多个线程都想对数据库(MongoDB)里的一个对象 进行操作
分支A:如果这个对象存在,就进行字段更新
分支B:如果这个对象不存在,创建之后,再用_id进行字段更新(多个线程都想拿到数据库里的一个不存在对象的_id, 进行操作)

针对A分支,没什么说的,无脑操作就行
针对B分支,大家实现起来就各显神通了

锁加自旋

我看到过一种实现是这样的

if(exist) {
  doSomthing();
} else {
  if(redis.lock()) {
    // 拿到锁
    create();
  } else {
    while(true) {
      sleep(x);
      if(exist) {
        break;
      }
     }
  }
  doSomthing();
}

getOrSet

因为MongoDBdocument可以自行设置 _id, 再加上 upsert 并发也不丢字段(必须是幂等操作), 所以我觉得可以优化掉 sleep

第一个问题就是:分布式下多个线程都想拿到数据库里的一个不存在对象的_id, 进行操作,这个 _id 怎么互相感知

想法思路是: 大家到同一个地方去get某个东西,有的话就取出来,当成_id使用;没有的话,就生成一个设置进去

日常工作中,有分布式能力且唾手可得的中间件就是 redis

那么redis原生有没有这个实现呢?

首先想到了 getset
但是仔细一看文档,作用原来是这样的Getset 命令用于设置指定 key 的值,并返回 key 的旧值

值每次都没修改了,无法达到分布式统一的目的

setnx 有这个效果,但是返回的是数字,想要获取,还需要再get一下,有点繁琐

那么能不能把setnxget合并起来写成lua脚本呢?

可以的,经过测试,以下lua脚本可行

local key_name = KEYS[1] 
local value = ARGV[1]
local exp_second = ARGV[2]
local redis_value = redis.call('get', key_name)
if redis_value then
    return redis_value
end    
redis.call('set', key_name, value, 'EX', exp_second)
return value

用的时候就这样用

eval script 1 key value second

java伪代码优化为如下

if(exist) {
    doSomthing();
} else {
    _id = new ObjectId();
    redisId = redis.getOrSet(_id)
    
    if(redisId == _id)) {
        // 说明是当前线程设置进去的,负责创建
        create();
    } else {
        upsert(redisId)
    }

    doSomthing();
}

相关文章

  • redis getOrSet 要么取出要么设置 实现

    背景 工作中遇到这么一个场景:在并发场景下,分布式下多个线程都想对数据库(MongoDB)里的一个对象 进行操作分...

  • golang基于sync.Map实现限流器降级

    我们平常用的限流器,一般都会借助redis去实现,因为redis可以支撑很高的并发,但是一旦redis挂掉,要么所...

  • redis-事务

    mysql事务: 多个sql操作,要么一起成功要么一起失败 redis命令都是原子性的,一个命令执行时要么成功要么...

  • Redis实现分布式锁(设计模式应用实战)

    笔者看过网络上各种各样使用redis实现分布式锁的代码,要么错误,要么片段化,没有一个完整的例子,借这个周末给大家...

  • 要么,要么

    either。。。or 要么A要么B的思维,比如历史究竟是想象还是事实,新政究竟是改革还是革命。 这中思维的假设就...

  • 要么,要么

    如果 这世界上还有花草为阳光而生存 要么寂寂无声 要么繁华似锦 如果 这世界上还有爱我的人在为我等 要么永远别来 ...

  • 要么……要么……

    老师问:请用“要么。。。要么。。。”造句。 学生答:气球五毛钱一个,要么,要么?

  • 要么·要么··

    除了来放大自己那一点点好的地方之外,很久没有和别人聊自己欠缺的部分。 能意识到问题就该去改,马上动起来。那...

  • 要么 要么

    要么拥有钱权,要么一无所有

  • 要么干,要么忍,要么滚,要么……

    昨天开始,陆续接到了四起吐槽:年底,真是一个多事之冬。 天哪,这样的评价真水! 无聊,太不公平了吧! 他有什么理由...

网友评论

      本文标题:redis getOrSet 要么取出要么设置 实现

      本文链接:https://www.haomeiwen.com/subject/acowaktx.html