假设一个教室50个人,但只有一个厕所。
当你想上厕所的时候也有其它人想上厕所,这种情况叫冲突。
肯定不能说有内急的人一块上厕所。
如何保证在发生冲突的时候,在同一时间只有一个人可以上厕所呢?
可以制定某种规则,只有符合规则的人才能上厕所。
可以有以下规定:
- 都想上厕所的人打一架、打赢了的人才能上厕所。
- 剪刀石头布,赢的人上厕所。
- 先到先得,谁先来谁上厕所。
先上厕所的人把门关上,上完厕所再把门打开。
但如果这个人一直上厕所,永远不出来也不行。因为他可能在厕所里晕倒了。因此需要在厕所设置一个闹钟,一旦超时规定时间,闹钟就会响。之后破门而入把他从厕所里面救出来。
但如果这个人确实是因为肚子不舒服需要很长的上厕所时间,但这个闹钟超过了预设的超时时间响了怎么办?强行破门后,发现对方真的是肚子不舒服,而不是晕倒在厕所。
实现分布式锁的方式
那在程序种如何实现这整套厕所的分配规则呢?
比如在数据库中有个字段为lock master,当有数据访问时设置为唯一标识,当不访问时设置为null,那其它的程序来访问时候就知道了,这个数据有人正在用。当然这个数据库可以是mysql可以是redis。
而redis的分布式也是这样的,是多个服务器去访问另一个集中的服务器,这个集中的服务器上有redis。
注意事项:用完要释放锁、锁一定要设置过期时间。(如果不加后面,如果服务器执行到一半挂了,后面的所有服务器都用不了)。如果方法执行过长,可能会释放别人的锁,可以使用续期(续期的别名叫看门狗)
实现分布式锁的工具
MySQL数据库:select for update 行级锁(最简单)(但比较吃性能),这里涉及到乐观锁和悲观锁。
redis来存储标识。(性能比较好,读写更快)支持setnx,支持lua脚本,也方便实现分布式锁
Zookeeper(不推荐,企业用的少)
实现分布式锁的实现
Redisson实现分布式锁,上面那些都不要自己写。
官网:Redisson PRO – Redis Java client with features of In-Memory Data Grid
给Redisson下定义(当别人问你Redisson是什么的时候,你怎么回答?):Redisson是一个用Java操作Redis的客户端。提供了大量的分布式数据集,用来简化对Redis的操作和使用。可以让开发者像使用本地集合一样使用Redis,让开发者完全感受不到Redis的存在。
补充:Redisson是Java客户端,而Java客户端就是用来操作Java的。用了Redisson可以往Redis里面增删改查。并且Redisson实现了很多Java里支持的接口和数据结构。
分布式锁的优缺点
优点:
- 可以避免分布式系统中的资源竞争问题:在分布式系统中,多个进程或者节点可能同时对同一个资源进行访问,导致竞争和冲突。分布式锁可以通过协调进程或者节点之间的访问,避免这种竞争和冲突。
- 提高系统可用性、降低运营和维护成本:可以不用显式配置服务器,可以部署多个服务器。
- 可以保证数据的一致性和可靠性:分布式锁可以确保在任何时刻只有一个进程或者节点可以访问共享资源,从而保证数据的一致性和可靠性。
缺点:
- 增加开发成本,增加系统复杂度:使用分布式锁需要引入一些新的组件或者服务,比如 ZooKeeper 等,这会增加系统的复杂度。
- 会增加系统的延迟:由于需要通过网络进行通信,分布式锁会增加系统的延迟。在高并发的情况下,这个延迟可能会很大。
- 可能会出现死锁:由于分布式锁涉及多个节点或者进程之间的协调,如果协调不当,就可能会出现死锁问题。