最近接手一个含有定时任务的历史项目,需要部署两个实例,为了减少重复打包的工作,在技术经理的建议下,决定采用zookeeper临时节点存在与否的方式来控制各个实例下定时任务的是否执行,同时也大部分避免了宕机的情况定时任务不会执行的情况。
具体代码实现:
import com.loan_manage.service.MasterService;
import com.netflix.curator.RetryPolicy;
import com.netflix.curator.framework.CuratorFramework;
import com.netflix.curator.framework.CuratorFrameworkFactory;
import com.netflix.curator.retry.RetryUntilElapsed;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.data.Stat;
import org.junit.Assert;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.List;
/**
* 是否主节点实现
* @author wuhanhong
*/
@Service
public class MasterServiceImpl implements MasterService {
private final static Logger logger = LoggerFactory.getLogger(MasterServiceImpl.class);
private CuratorFramework zk;
@Value("${zookeeper.registry.address}")
private String hosts;
@Value("${zookeeper.retry.times}")
private Integer retry;
@Value("${zookeeper.connection.timeout}")
private Integer connectTimeout;
@Value(("${zookeeper.session.timeout}"))
private Integer sessionTimeout;
@Value("${zookeeper.nodes.path}")
private String root;
@PostConstruct
public void startZookeeper() throws Exception {
logger.debug("start zookeeper ...");
RetryPolicy retryPolicy = new RetryUntilElapsed(1000,1000);
zk = CuratorFrameworkFactory.newClient(hosts, retryPolicy);
zk.start();
}
@PreDestroy
private void stopZookeeper() throws Exception {
if(zk != null) {
logger.debug("stop zookeeper ...");
zk.close();
}
}
@Override
public boolean isMaster() {
try {
if(zk == null || zk.getZookeeperClient() == null || zk.getZookeeperClient().getZooKeeper() == null ){
return false;
}
Long sessionId = zk.getZookeeperClient().getZooKeeper().getSessionId();
List<String> children = null;
if(zk.checkExists().forPath(root) != null){
children = zk.getChildren().forPath(root);
}
if(children == null || children.isEmpty()){
zk.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL).forPath(root+"/"+sessionId,"".getBytes());
return true;
}else{
String child = children.get(0);
if(sessionId.toString().equals(child)){
return true;
}
}
} catch (Exception e) {
logger.warn("create node failed....",e);
}
return false;
}
public String getHosts() {
return hosts;
}
public void setHosts(String hosts) {
this.hosts = hosts;
}
public Integer getRetry() {
return retry;
}
public void setRetry(Integer retry) {
this.retry = retry;
}
public Integer getConnectTimeout() {
return connectTimeout;
}
public void setConnectTimeout(Integer connectTimeout) {
this.connectTimeout = connectTimeout;
}
public Integer getSessionTimeout() {
return sessionTimeout;
}
public void setSessionTimeout(Integer sessionTimeout) {
this.sessionTimeout = sessionTimeout;
}
public String getRoot() {
return root;
}
public void setRoot(String root) {
this.root = root + "/master";
}
}
配置文件:
zookeeper.registry.address=192.168.1.61:5181,192.168.1.61:5182,192.168.1.61:5181 zookeeper.retry.times = 3 zookeeper.connection.timeout = 30 zookeeper.session.timeout = 300 zookeeper.nodes.path = /tasks/nodes
一旦有机器宕机,机器与zookeeper的链接会断开,临时节点就会失效,当下一台机器再次check的时候,发现临时节点不存在,就是创建临时节点,将自己作为定时任务的master,然后继续执行定时任务。
来源:oschina
链接:https://my.oschina.net/u/940506/blog/1553506