【杂谈】如何对Redis进行原子操作

什么时候需要进行需要原子操作?

很常见的例子,就是利用Redis实现分布式锁。

实现锁需要哪些条件?

我们知道要实现锁,就需要一个改变锁状态的方法。这个方法能原子地对锁的状态进行检查并修改。如果修改成功,则意味着获得了锁。对于硬件,它提供的就是test-and-set,compare-and-swap等原语。

Redis有没有提供类似的原语呢?

有的。Redis有提供setnx(),它会提供这样的原子操作:如果key没有值,则将值设置进去,如果已有值就不做处理,提示失败。

这样就可以基于这个原语来实现锁,简单原理就是:key就是对应的锁,如果key有值就说明锁被占用。删除值代表释放锁。如果插入值成功,则代表获得锁。再加上过期时间,基本就可以满足分布式锁的需求了。

除了锁,还有哪些地方需要原子操作?

假如我们在操作Redis数据的时候,需要判断Redis中某个值是否满足条件,只有满足条件才做这个操作

我随便举个例子,例如:如果key-xxx的值不为0,则加1,如果为0,则删除。

这种情况Redis可以处理吗?

可以,Lua脚本。Redis支持Lua脚本。针对上面的问题,我们只要写这样的Lua脚本就可以了。

local a = redis.call('get', 'xxx') //调用redis的get方法,key为'xxx'
if(tonumber(a) > 0) then  //redis都是以String进行存储的,需要转型
    redis.call('incr', 'xxx') //调用redis的incr方法,key为'xxx'
    return 'OK'
else
    return 'FAIL'

为什么Lua脚本可以实现原子操作, 看不出来它有用锁啊?

这与Redis的请求处理有关。Redis只用一个线程来处理客户端的请求。所以在执行lua脚本的时候,没有其他客户端的请求在处理。所以在lua脚本中的对redis数据的修改操作就是原子的。

只用一个线程处理的过来吗?

Redis的请求处理线程,利用Select和事件循环进行处理,大概就是下面这样:

while(1) {
    events = getEvents(); //先利用SELECT拿到最近的请求
    for(e in events)  //然后逐个处理
        processEvent(e);
}

由于使用的是select()来处理网络I/O,所以线程不会在一个socket连接上阻塞。另一方面因为redis的操作的数据都在内存中。处理起来也很快,所以也不会出现响应时间太长的情况。

万一这个线程阻塞了怎么办?

一般情况下,阻塞不了。前面也说了,客户端上来的请求都是操作内存的,不会有其他调用(例如文件I/O这样的调用)。但是,这是一般情况。别忘了lua,lua脚本里面是可以写阻塞操作的(比如文件I/O,或者最简单的死循环)。实测发现,如果往Redis中提交一个死循环的lua脚本,Redis就挂了。所以写lua脚本的时候要小心。

转载于:https://www.cnblogs.com/longfurcat/p/11250827.html

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值