redis分布式锁解决集群环境下的定时任务
需要特殊考虑的是,异常关机碟机而产生的死锁(代码刚刚走到set的时候)
package com.mmall.common.schedule;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import com.mmall.util.RedisShardedPoolUtil;
@Component
public class ScheduleTest {
// @Scheduled(cron="0/5 * * * * ?")
// public void schbobo(){
// Date date = new Date();
// SimpleDateFormat sim = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// String dateStr = sim.format(date);
// log.info("这是spring定时器1,每五秒执行一次,当前时间:" + dateStr);
// System.out.println("这是spring定时器1,每五秒执行一次,当前时间:" + dateStr);
//
// }
//reids分布式锁的定时任务
@Scheduled(cron="0/5 * * * * ?")
public void schbobo_1(){
String key="bobodekey";
Long setresult=RedisShardedPoolUtil.setNx(key,String.valueOf(System.currentTimeMillis()+50000));
if(setresult!=null&&setresult.intValue()==1){
System.out.println("我获得到了锁哦来自schbobo_1");
//获取锁成功,并且进行业务操作
add(key);
System.out.println("结束了生命周期");
}else{//为了防止异常碟机而产生的死锁
String oldKey=RedisShardedPoolUtil.get(key);
if(oldKey!=null&&System.currentTimeMillis()>Long.parseLong(oldKey)){//已经超过vlued的有效期
String getsetVlue=RedisShardedPoolUtil.getset(key, String.valueOf(System.currentTimeMillis()+50000));
if(getsetVlue==null||getsetVlue.equals(oldKey)){
add(key);
}
}
System.out.println("没有获取到锁,我是schbobo_1里面的else");
}
}
/**
* 进行业务操作并且防止死锁的发生
* @param key
*/
private void add(String key){
//设置50秒的有效期
RedisShardedPoolUtil.exPire(key,50);
System.out.println("我做了好多事情唉,都做完了");
RedisShardedPoolUtil.del(key);
}
}
导入架包:
<!-- redisson需要的架包 -->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-avro</artifactId>
<version>2.9.0</version>
</dependency>
编写工具类获取redisson实例
package com.mmall.util;
import javax.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.config.Config;
import org.springframework.stereotype.Component;
@Component
@Slf4j
public class RedissonManager {
private Config config=new Config();
private Redisson redisson=null;
public Redisson getRedisson() {
return redisson;
}
@PostConstruct
private void init() {
try {
config.useSingleServer().setAddress("111.231.114.12:6379").setPassword("bobo");
redisson=(Redisson)redisson.create(config);
log.info("获取redisson实例成功");
} catch (Exception e) {
log.info("获取redisson实例失败,error{}",e);
}
}
}
重新设计分布式锁,使用redisson的可重入锁解决分布式的定时任务
/**
* 使用redisson操作锁
*/
@Scheduled(cron="0/5 * * * * ?")
public void shcbobo_2(){
String key="bobodekeyzuihouyige";
RLock lock= RedissonManager.getRedisson().getLock(key);
Boolean getlock=false;
try {
//第一个参数是等待多少秒,一般设置成0,因为无法估算业务运行完的一个时间,如果设置短了,就会被其他的进行获取到锁,所以设置成0,不进行等待
//第二个参数是有效期50秒,超过50秒就会失效
//第三个参数是单位是秒
if(getlock=lock.tryLock(0,50,TimeUnit.SECONDS)){
System.out.println("执行了业务");
}else{
System.out.println("没有获取到锁");
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
if(!getlock){
return;
}
//删除锁
lock.unlock();
System.out.println("删除了锁");
}
}
redis,主从配置,读写分离,哨兵模式
redis主从配置,配置master 只能为写,slave只能为读,在客户端对poolconnect请求时候,,会将读请求转到slave上面,写请求转到master上面,同时,master和slave有同步功能,这就实现了(数据层)读写分离对上层(逻辑层)透明的正常逻辑。无需再通过中间件或者代码进行读写分析实现。
https://blog.csdn.net/zmx729618/article/details/76671746