前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >基于redis的分布式锁

基于redis的分布式锁

作者头像
烟草的香味
发布2020-03-26 03:01:48
3350
发布2020-03-26 03:01:48
举报
文章被收录于专栏:烟草的香味烟草的香味

概述

在之前, 我也使用redis做过分布式锁, 当时的做法是这样的:

  1. setnx: 向 redis中创建一个过期时间为1s的key, 若创建失败, 则锁获取失败
  2. expire: 获取锁成功后, 给锁增加过期时间
  3. del: 处理后释放锁

当时觉得貌似没什么问题. 是我太天真了, 今天突然想到, 恩, 有问题.

问题

1.如果在第一步之后, 程序崩了, 没有给锁设置过期时间, 导致所有后续操作都无法正常获取到锁. 怎么破?

2.在A成功上锁后, 因为IO阻塞等原因, 执行时间有点长, 锁已经过期了, 这时B过来成功上锁, A在释放锁的时候释放的就是B的锁.

3.redis突然挂了. 如果redis突然挂了, 怎么办? 当然, 可以增加redis节点, 主节点挂了, 从节点立刻补上. 但是, 主节点的数据同步到从节点也是需要时间的吧. 假设一个场景:

  1. A在主节点设置锁
  2. 主节点还没有同步数据的时候, 挂了
  3. 从节点接替成为主节点
  4. B在主节点也成功设置了锁

这个时候, 分布式锁就失效了.

解决

那么有没有办法解决上面的问题呢? 我到万能的谷歌上找了一下, 恩, 真的有.

上面的问题一个一个解决.

问题一

如何避免没有给锁设置过期时间的问题?

其实看看就知道了, 问题出在设置key和设置value分成两条命令执行, 所以导致如果在 setnx命令执行过后, 程序崩溃, expire命令没有正常执行, 将其合并为一条命令就好啦.

set key value NX PX 5000

其中NX表示存在则不设置, PX表示过期时间.

如此, 至少可以保证不会出现没有过期时间的锁了

问题二

如何避免A释放了B的锁.

如何避免释放了其他人的锁呢? 换个问题, 如何保证这个锁是你加的呢? so easy, 加锁的时候, 讲value值设置成一个只有我知道的随机数字, 释放的时候看看值是不是我的就行了.

如此在释放的时候需要两步操作:

  1. 获取redis锁的值
  2. 若值是我的, 释放锁

当然, 为了保证释放锁操作的原子性, 这两步操作最好也能合并为一步操作. 那redis如何实现值是否相同的判断呢? Lua脚本.

简单介绍一下

代码语言:javascript
复制
eval "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 key1 key2 argv1 argv2
# 看懂了吧, 哈哈
# eval 是redis内置的命令
# 第一个参数是运行的脚本逻辑
# 第二个参数表示后面有几个key
# 第五个参数开始就是附加参数, 在脚本逻辑中使用的

所以, 脚本内容如下:

代码语言:javascript
复制
if redis.call("get",KEYS[1]) == ARGV[1] then
    return redis.call("del",KEYS[1])
else
    return 0
end

如此, 至少可以保证不会出现A释放了B锁的情况了

问题三

如何保证在主节点挂掉的时候, 从节点接替后, 不会重复获得锁?

官网上提供了一个方法, 从多个redis实例同时获取锁. 因为我没看太明白, 之后看懂了在说吧. 过...

其实, 如果不是处理金钱这种不容出错的业务, 这种小概率事件个人觉得还是可以容忍的.


总结

最终, 在redis单机下实现的分布式锁操作如下:

代码语言:javascript
复制
# 获取分布式锁,过期时间可调
set lock_key random_value NX PX 5000
# ...do something
# 释放分布式锁
eval "if redis.call("get",KEYS[1]) == ARGV[1] then return redis.call("del",KEYS[1]) else return 0 end" 1 lock_key random_value
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-03-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 烟草的香味 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 概述
  • 解决
  • 总结
相关产品与服务
云数据库 Redis
腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档