分布式锁&&redis
什么是锁?不同线程竞争线程外部资源就会用到锁,锁是为了防止数据被错乱的使用而导致各种各样的问题发生,最终避免操作失败的一种方案,也可以称为事务。synchronized机制,Lock接口,这些都是Java为我们提供的锁,但是这些锁有一个前提,这些资源的竞争者只有在一个JVM中的时候,这两个锁才成立。
所以分布式情况下这两种锁就什么也做不了,如果要求事务就必须搞到新的分布式锁。
事务的要求ACID,原子性(Atomicity)一致性(Consistency)隔离性(Isolation)持久性(Durability),这是老生常谈了,不讲了。
考虑Java提供的锁的原理,对象头,锁标识等等,这些都是为了告诉其他竞争者,im here,you out!所以分布式事务的核心就是在找一个可以被所有竞争者正确读取的锁,而这个锁需要被保存和读取,读就不说了,所以所有可以保持数据的东西理论上都可以作为分布式锁的载体。
比如说人,纸,标记等等,或者说redis,mq,mysql等等。实现天差地别,原理CRUD。
Redis基于内存而非基于磁盘,基于单线程而非多线程,再加上NIO的实现原理。所以NIO+单线程+基于内存造就了redis高效,简单的特色,因这两个特色让redis在Nosql领域占有一席之地。
这里介绍以下redis实现分布式锁:
一步一步的详细步骤可以了解这里:https://baijiahao.baidu.com/s?id=1623086259657780069&wfr=spider&for=pc
下面介绍下思路:
之前的文章介绍过Lua脚本,这个语言可以完成多操作原子执行,因为分布式要求ACID,传统的set,get因分布执行稍有差错极易导致事务失败,而redis自己本身的操作对多步操作虽然不提供原子解决方案,但Lua脚本是解决方案之一,Lua脚本可以将多个操作原子执行,因为Lua脚本简单易学,推荐Lua脚本。而原子操作的Lua脚本加上单线程的redis,加锁和解锁都会是正确的,同步的。
将资源作为key存入redis,但是存入redis和释放key这两个操作必须放在Lua脚本中。资源请求者查询该资源是否在redis有记录,如果没有就代表没有对该资源加锁,使用Lua脚本给其加锁,设置合理的失效时间(防止锁一直得不到释放),在加锁时将自己存入Value,解锁时对比Value防止解的不是自己的锁。解锁步骤相同。