Zookeeper选举Master

282 阅读2分钟

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… 版权声明:本文为博主原创文章,转载请附上博文链接!