All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.taobao.metamorphosis.metaslave.SubscribeHandler Maven / Gradle / Ivy

There is a newer version: 1.4.6.2
Show newest version
/*
 * (C) 2007-2012 Alibaba Group Holding Limited.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * Authors:
 *   wuhua  
 */
package com.taobao.metamorphosis.metaslave;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.taobao.gecko.service.exception.NotifyRemotingException;
import com.taobao.metamorphosis.client.MetaClientConfig;
import com.taobao.metamorphosis.client.consumer.ConsumerConfig;
import com.taobao.metamorphosis.client.consumer.MessageConsumer;
import com.taobao.metamorphosis.client.consumer.MessageListener;
import com.taobao.metamorphosis.cluster.Partition;
import com.taobao.metamorphosis.exception.MetaClientException;
import com.taobao.metamorphosis.server.assembly.MetaMorphosisBroker;
import com.taobao.metamorphosis.server.store.MessageStore;
import com.taobao.metamorphosis.server.utils.MetaConfig;
import com.taobao.metamorphosis.server.utils.MetaMBeanServer;


/**
 * ?????master??????Ϣ???洢??slaver
 * 
 * @author ?޻?
 * @since 2011-6-24 ????06:03:29
 */

public class SubscribeHandler implements SubscribeHandlerMBean {
    private final static Log log = LogFactory.getLog(SubscribeHandler.class);

    private final MetaMorphosisBroker broker;
    private final SlaveZooKeeper slaveZooKeeper;
    private final SlaveMetaMessageSessionFactory sessionFactory;
    private final MessageListener messageListener;
    private MessageConsumer consumer;
    private final SlaveOffsetStorage slaveOffsetStorage;
    private final AtomicBoolean isStarted = new AtomicBoolean(false);
    private String masterServerUrl;


    public SubscribeHandler(final MetaMorphosisBroker broker) throws MetaClientException {
        this.broker = broker;
        this.slaveZooKeeper = new SlaveZooKeeper(this.broker, this);
        final MetaConfig metaConfig = this.broker.getMetaConfig();

        final MetaClientConfig metaClientConfig = new MetaClientConfig();
        metaClientConfig.setDiamondZKDataId(metaConfig.getDiamondZKDataId());
        metaClientConfig.setDiamondZKGroup(metaConfig.getDiamondZKGroup());
        metaClientConfig.setZkConfig(metaConfig.getZkConfig());
        this.sessionFactory = SlaveMetaMessageSessionFactory.create(metaClientConfig, metaConfig.getBrokerId());
        this.slaveOffsetStorage =
                new SlaveOffsetStorage(this.broker, this.slaveZooKeeper, this.sessionFactory.getRemotingClient());
        this.messageListener =
                new MetaSlaveListener(this.broker.getBrokerZooKeeper(), this.broker.getStoreManager(),
                    new SlaveStatsManager(this.broker.getStatsManager()));
        MetaMBeanServer.registMBean(this, null);

    }


    // ??????slave broker????֮??
    synchronized public void start() {
        if (this.isStarted.get()) {
            log.info("Subscriber has been started");
            return;
        }

        try {
            final Map> partitionsForTopics =
                    this.slaveZooKeeper.getPartitionsForTopicsFromMaster();
            if (partitionsForTopics == null || partitionsForTopics.isEmpty()) {
                throw new SubscribeMasterMessageException("topics in master is empty");
            }
            // ??????Ϣ?ļ?,????б?Ҫ?Ļ?
            this.handleMassageFiles(partitionsForTopics);
            this.initMessageConsumer();
            this.subscribeMetaMaster(partitionsForTopics.keySet());
            this.isStarted.set(true);
            log.info("start subscribe message from master success");
        }
        catch (final Throwable e) {
            // ????masterû??????????ԭ???????????ݸ???ʧ?ܵ?,??¼һ??,
            // ??????????zk,????masterʱ???????ݸ???
            log.warn("problem occured in start subscribe message from master,maybe master not started or other errers",
                e);
            log.info("waiting for master start next time...");
        }
        this.slaveZooKeeper.start();
    }


    /** ??һ??topic??ij??patition????????Ϣ?ļ?ʱ,??master??ѯoffset?????????offset????store???ļ? **/
    private void handleMassageFiles(final Map> partitionsForTopics) {
        try {
            this.masterServerUrl = this.slaveZooKeeper.getMasterServerUrl();
            for (final Map.Entry> each : partitionsForTopics.entrySet()) {
                for (final Partition partition : each.getValue()) {
                    final String topic = each.getKey();
                    final MessageStore messageStore =
                            this.broker.getStoreManager().getMessageStore(topic, partition.getPartition());
                    // ???ز???????Ϣ?ļ?
                    final StringBuilder logStr = new StringBuilder();
                    if (messageStore == null) {
                        logStr.append("Local file for topic=").append(topic).append(" is not exist,partition=")
                            .append(partition.getPartition()).append("\n");
                        final long offsetInMaster =
                                this.slaveOffsetStorage.queryOffsetInMaster(this.masterServerUrl, partition, topic);
                        logStr.append("query offset from master,offset=").append(offsetInMaster).append("\n");
                        // ????һ????ָ??offset??ʼ??store???ļ?
                        if (offsetInMaster > 0) {
                            this.broker.getStoreManager().getOrCreateMessageStore(topic, partition.getPartition(),
                                offsetInMaster);
                            logStr.append("create messageStore,offset=").append(offsetInMaster).append("\n");
                        }
                        log.info(logStr.toString());
                    }
                }
            }
        }
        catch (final Throwable e) {
            throw new SubscribeMasterMessageException("errer occur on handleMassageFiles", e);
        }
    }


    public void closeConnectIfNeed() {
        if (StringUtils.isBlank(this.masterServerUrl)) {
            log.warn("can not close connect,master server url is blank");
            return;
        }
        try {
            this.sessionFactory.getRemotingClient().close(this.masterServerUrl, false);
            log.info("Closing " + this.masterServerUrl);
            if (log.isDebugEnabled()) {
                log.debug("connect count="
                        + this.sessionFactory.getRemotingClient().getConnectionCount(this.masterServerUrl));
            }
        }
        catch (final NotifyRemotingException e) {
            log.error("close connect " + this.masterServerUrl + " failed", e);
        }
    }


    public void stop() {
        try {
            if (this.isStarted.compareAndSet(true, false)) {
                log.info("stop subscribe from master");
                this.consumer.shutdown();
                this.consumer = null;
                log.info("stop success");
            }
            else {
                log.info("can not stop,since this not started");
            }
        }
        catch (final MetaClientException e) {
            log.error("stop consumer failed", e);
        }
    }


    public void shutdown() {
        this.stop();
        try {
            this.sessionFactory.shutdown();
        }
        catch (final MetaClientException e) {
            log.error(e);
        }
    }


    private void initMessageConsumer() throws Exception {
        if (this.consumer == null) {
            final ConsumerConfig consumerConfig = new ConsumerConfig(this.broker.getMetaConfig().getSlaveGroup());
            consumerConfig.setMaxDelayFetchTimeInMills(this.broker.getMetaConfig().getSlaveMaxDelayInMills());
            consumerConfig.setMaxFetchRetries(Integer.MAX_VALUE);// ??Ϣ????ʧ?ܿ?????һ????,??????recover
            this.consumer = this.sessionFactory.createConsumer(consumerConfig, this.slaveOffsetStorage);
        }
        else {
            log.warn("consumer existed");
        }
    }


    private void subscribeMetaMaster(final Set topics) throws Exception {
        try {
            for (final String topic : topics) {
                this.consumer.subscribe(topic, 1024 * 1024, this.messageListener);
            }
            this.consumer.completeSubscribe();
        }
        catch (final Exception e) {
            log.warn("start subscribe from meta master fail", e);
            throw e;
        }
    }


    // for test
    SlaveZooKeeper getSlaveZooKeeper() {
        return this.slaveZooKeeper;
    }


    // for test
    boolean isStarted() {
        return this.isStarted.get();
    }


    /*
     * (non-Javadoc)
     * 
     * @see com.taobao.metamorphosis.metaslave.SubscribeHandlerMBean#restart()
     */
    @Override
    public void restart() {
        this.stop();
        this.start();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy