Zookeeper选举Master

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;
    

    }

    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();
}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值