最近在研究锁,来谈谈这部分的理解。
首先,我们在使用锁时,要明确,为什么我们要使用锁?大概有三点:
1.多任务的环境中才需要?这个多任务可以指多线程或者多进程。
2.任务都需要对同一共享资源进行写操作时。对共享资源多线程进行修改时会引发并发安全问题。
3.对资源的访问都是互斥的。
当一个线程或者进行在对一共享资源进行操作时,其他线程或者进程都不可以对这个资源进行操作,知道该线程或者进程完成其操作,其他线程或者进程才能对该资源进行操作,而其他线程或者进程又处于等待状态。
分布式锁方案目前主流的大概有三种:
1.利用mysql的实现方案
实现思路:利用数据库自身提供的锁机制实现,要求数据库支持行级锁
2.利用redis的实现方案
实现思路:使用缓存的CAS机制实现,保证对缓存操作序列的原子性
3.利用zk的实现方案
基于zk的节点特点以及watch机制实现
今天我们主要介绍下基于redis的分布式锁。
Redis是一个开源,内存存储的数据结构服务器。可用作数据库。高速缓存和消息队列代理。采用单线程单进程模型,并发能力强大,是目前互联网架构中主流的分布式架构工具。
关于redis分布式锁的基础知识
- 缓存有效期
redis的数据,不一定都是持久话的;给定key设置的生存时间,当key过期时,它会自动删除。
- SETNX命令
SETNX key value ,将key的值设为value,当且仅当key不存在。若给定的key已经存在,则SETNX不做任何动作。
SETNX是【SET IF NOT EXISTS】如果不存在,则SET的简称
- lua脚本
轻量小巧的脚本语言,用于支持redis操作序列的原子性;
redis加解锁的正确姿势
- 加锁
通过setnx想特定的key写入一个随机值,并设置失效时间,写值成功及加锁成功
注意点:必须设置一个失效时间 ------>避免死锁
加锁时,每个节点产生一个随机字符串 ------>避免锁误删
写入随机值与失效时间必须是同时的 ------>保证加锁是原子性。
SET key value NX PX 30000
- 解锁
匹配随机值,删除redis上的特点key数据,要保证获取数据、判断一致、删除数据三个操作是原子的。
执行如下lua脚本:
if redis.call("get",KEY[1])==ARGV[1]then
return redis.call("del",KEYS[1])
else
return 0;
end