Zookeeper选举master可以保证一台服务器执行,在项目中运用到的是在没有专门的定时任务服务时,由于一个服务会启多个节点这样就会导致节点之前去抢定时任务,从而造成数据的不一致性。 根据之前说的情况,我用了Zookeeper选举Master的原理来保证同一时间只有一个服务在执行服务中的定时任务。 下面是实现代码: 第一个类 package com.baibei.pay.configurer;
import lombok.extern.slf4j.Slf4j; import org.apache.curator.RetryPolicy; import org.apache.curator.framework.CuratorFramework; import org.apache.curator.framework.CuratorFrameworkFactory; import org.apache.curator.retry.ExponentialBackoffRetry; import org.apache.curator.utils.CloseableUtils;
/**
@author hwq
@date 2018/11/20
*/
@Slf4j
public class ZooKeeperConnector {
private String hosts;
private CuratorFramework client;
private static final int DEFAULT_SESSION_TIMEOUT_MS = 30000;
private static final int DEFAULT_CONNECTION_TIMEOUT_MS = 10000;
private int sessionTimeout = 30000;
private int connectionTimeout = 10000;
public ZooKeeperConnector() {
}
public void connect() {
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
this.client = CuratorFrameworkFactory.newClient(this.hosts, this.sessionTimeout, this.connectionTimeout, retryPolicy);
this.client.start();
log.info("Successfully connected to Zookeeper [{}] ", this.hosts);
}
public void close() {
CloseableUtils.closeQuietly(this.client);
}
public String getHosts() {
return this.hosts;
}
public void setHosts(String hosts) {
this.hosts = hosts;
}
public CuratorFramework getClient() {
if (this.client == null) {
this.connect();
}
return this.client;
1
}
public CuratorFramework reconnect() {
this.connect();
return this.client;
}
public void setClient(CuratorFramework client) {
this.client = client;
}
public int getSessionTimeout() {
return this.sessionTimeout;
}
public void setSessionTimeout(int sessionTimeout) {
this.sessionTimeout = sessionTimeout;
}
public int getConnectionTimeout() {
return this.connectionTimeout;
}
public void setConnectionTimeout(int connectionTimeout) {
this.connectionTimeout = connectionTimeout;
}
}
package com.baibei.pay.configurer;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
第二个类
/**
定时任务master节点判断配置
@author wenqing
*/
@Data
@Configuration
public class SchedulerMasterConfig {
@Value("${ZOOKEEPER.CONNECTION.HOSTS}")
private String zk;
@Value("${ZOOKEEPER.MASTER.ZKSESSIONTIMEOUT}")
private int zkSessionTimeout;
@Value("${BUSINESS.TYPE}")
private String businessType;
}
核心类
package com.baibei.pay.configurer;
import lombok.extern.slf4j.Slf4j;
import org.I0Itec.zkclient.IZkDataListener;
import org.I0Itec.zkclient.ZkClient;
import org.I0Itec.zkclient.exception.ZkNodeExistsException;
import org.I0Itec.zkclient.serialize.SerializableSerializer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.UUID;
/**
@author hwq
@date 2018/11/20
定时任务使用ZK限制单点执行,只有master节点才执行定时任务
每个节点有不同的serverID,第1个把自己serverID写到ZK node上的为master,当某个节点down掉后,其他节点争抢master
*/
@Slf4j
@Service
public class SchedulerMasterCheck implements IZkDataListener {
@Autowired
SchedulerMasterConfig schedulerMasterConfig;
String MASTER_NODE = “/paymaster_”;
//ZK客户端
private ZkClient zk = null;
//临时serverID
private String serverId = UUID.randomUUID().toString().toLowerCase();
public void init(){
MASTER_NODE += schedulerMasterConfig.getBusinessType();
zk = new ZkClient(schedulerMasterConfig.getZk(), schedulerMasterConfig.getZkSessionTimeout(), schedulerMasterConfig.getZkSessionTimeout(), new SerializableSerializer());
log.info(“Temp serverId = {}”, serverId);
takeMaster();
zk.subscribeDataChanges(MASTER_NODE, this);
}
//抢master
private void takeMaster(){
try{
zk.createEphemeral(MASTER_NODE, serverId);
log.info(“serverId {} take master SUCCESS”, serverId);
}catch(ZkNodeExistsException e){//节点已存在
log.info(“serverId {} take master FAILURE”, serverId);
if(zk.readData(MASTER_NODE) == null){//在读取过程中,发现master节点已经被释放
takeMaster();
}
}
}
public boolean isMaster(){
try{
String data = zk.readData(MASTER_NODE);
if(serverId.equalsIgnoreCase(data)){
return true;
}
}catch(Exception e){
log.error(e.getMessage());
}
return false;
}
@Override
public void handleDataChange(String s, Object o) throws Exception {
}
@Override
public void handleDataDeleted(String s) throws Exception {
log.info(“Old Master is down, Take master…”);
takeMaster();
}
}
配置文件
应用
@Autowired
private SchedulerMasterCheck schedulerMasterCheck;
/**
* 五分钟执行一次
*/
@Scheduled(cron = “0 0/5 * * * ?”)
public void doUpQueryOrder() {
if (schedulerMasterCheck.isMaster()) {
log.info(“现在我在执行”);
queryOrder();
// payService.tetsZookeeper();
}
}
作者:闷骚的狐狸 来源:CSDN 原文:blog.csdn.net/fox100629/a… 版权声明:本文为博主原创文章,转载请附上博文链接!