控制定时任务的执行
原因
1.浪费资源,想象10000台服务器同时“打鸣”
2.脏数据,比如重复插入
要控制定时任务在同一时间只有1个服务器能执行。
怎么做?
1.分离定时任务程序和主程序,只在1个服务器运行定时任务。成本太大
2.写死配置,每个服务器都执行定时任务,但是只有符合配置的服务器才真实执行业务逻辑,其他的直接返回。成本最低;但是我们的IP可能是不固定的,把P写的太死了
3.动态配置,配置是可以轻松的、很方便地更新的(代码无需重启),但是只有坦符合配置的服务器才真实执行业务逻辑。
● 数据库
● Redis
● 配置中心(Nacos、Apollo、Spring Cloud Config)
(单机就会存在单点故障。)
4.分布式锁,只有抢到锁的服务器才能执行业务逻辑。坏处:增加成本;好处:不用手动配置,多少个服务器都一样
锁
有限资源的情况下,控制同一时间(段)只有某些线程(用户/服务器)能访问到资源。
Java实现锁:synchronized关键字、并发包的类
问题:只对单个JVM有效
为啥需要分布式锁?
1.有限资源的情况下,控制同一时间(段)只有某些线程(用户/服务器)能访问到资源。
2.单个锁只对单个VM有效
怎么保证同一时间只有1个服务器能抢到锁?
核心思想就是:先来的人先把数据改成自己的标识(服务器),后来的人发现标识已存在,就抢锁失败,继续等待。等先来的人执行方法结束,把标识清空,其他的人继续抢锁。
● MySQL数据库:select for update行级锁(最简单)(乐观锁的内容略)
● Zookeeper实现(不推荐)
● Redis实现:内存数据库,读写速度快。支持setux、lua脚本,比较方便我们实现分布式锁。
○ setnx:set if not exists如果不存在,则设置;只有设置成功才会返回true,否则返回false
具体讲redis分布式锁
Redis实现:内存数据库,读写速度快。支持setux、lua脚本,比较方便我们实现分布式锁。
setnx:set if not exists如果不存在,则设置;只有设置成功才会返回true,否则返回false
可能会出现的问题:
● 一个服务器一直占着一个锁不放
● 在占着锁的时候服务器挂掉了,那么一直锁着
注意事项:
● 用完锁要释放
● 锁一定要加过期时间
○ 衍生问题:
■ 连锁效应:释放掉别人的锁这样
■ 还是会存在多个方法同时执行的情况?● 解决方法:
○ 续期
○
■ 衍生问题:4.释放锁的时候,有可能先判断出是自己的锁,但这时锁过期了,最后还是释放了别人的锁
● ● Redis如果是集群(而不是只有一个Redis),如果分布式锁的数据不同步怎么办?
https://blog.csdn.net/feiyingOcanglang/article/details/113258494
Redission实现分布式锁
Java客户端,数据网格
实现了很多Java里支持的接口和数据结构
Redisson是一个java操作Redis的客户端,提供了大量的分布式数据集来简化对Redis的操作和使用,可以让开发者像使用本地集合一样使用Redis,完全感知不到Redis的存在。
2种引入方式
1.spring boot starter入(不推荐,版本迭代太快,容易冲突)
2.直接引入并自己配置:https://github.com/redisson/redisson#quick-start
一个Redission配置实例:
一个使用分布式锁的实例
定时任务+锁
1.waitTime设置为0,只抢一次,抢不到就放弃
2.2.注意释放锁要写在finally中
实现代码:
看门狗机制
redisson提供的续期机制
开一个监听线程,如果方法还没执行完,就帮你重置redis锁的过期时间。
原理:
原理:
1.监听当前线程,默认过期时间是30秒,每10秒续期一次(补到30秒)
2.如果线程挂掉(注意debug模式也会被它当成服务器宕机),则不会续期
https://blog.csdn.net/gg_26222859/article/details/79645203