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

io.fabric8.mq.controller.model.DefaultModel Maven / Gradle / Ivy

/*
 *
 *  * Copyright 2005-2015 Red Hat, Inc.
 *  * Red Hat licenses this file to you 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.
 *
 */

package io.fabric8.mq.controller.model;

import com.codahale.metrics.JmxReporter;
import io.fabric8.mq.controller.coordination.brokers.BrokerModel;
import io.fabric8.mq.controller.coordination.brokers.BrokerOverview;
import io.fabric8.mq.controller.multiplexer.Multiplexer;
import io.fabric8.mq.controller.multiplexer.MultiplexerInput;
import io.fabric8.utils.JMXUtils;
import org.apache.activemq.command.ActiveMQDestination;
import org.apache.activemq.util.ServiceStopper;
import org.apache.activemq.util.ServiceSupport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Default;
import javax.inject.Inject;
import javax.management.ObjectName;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

@ApplicationScoped
@Default
public class DefaultModel extends ServiceSupport implements Model {
    private static Logger LOG = LoggerFactory.getLogger(DefaultModel.class);
    private final ConcurrentMap objectNameMap = new ConcurrentHashMap<>();
    private final ConcurrentMap brokerModelMap = new ConcurrentHashMap<>();
    @Inject
    BrokerLimitsConfig brokerLimitsConfig;
    private JmxReporter jmxReporter = JmxReporter.forRegistry(METRIC_REGISTRY).inDomain(DEFAULT_JMX_DOMAIN).build();

    public BrokerLimitsConfig getBrokerLimitsConfig() {
        return brokerLimitsConfig;
    }

    @Override
    public void add(Multiplexer multiplexer) {
        try {
            ObjectName objectName = new ObjectName(DEFAULT_JMX_DOMAIN, "name", multiplexer.getName());
            registerInJmx(objectName, multiplexer);
        } catch (Throwable e) {
            LOG.error("Failed to register " + multiplexer, e);
        }
    }

    @Override
    public void remove(Multiplexer multiplexer) {
        unregisterInJmx(multiplexer);
    }

    @Override
    public void add(MultiplexerInput multiplexerInput) {
        try {
            ObjectName objectName = new ObjectName(DEFAULT_JMX_DOMAIN, "name", multiplexerInput.getName());
            registerInJmx(objectName, multiplexerInput);
        } catch (Throwable e) {
            LOG.error("Failed to register " + multiplexerInput, e);
        }
    }

    @Override
    public void remove(MultiplexerInput multiplexerInput) {
        unregisterInJmx(multiplexerInput);
    }

    @Override
    public void add(BrokerModel brokerModel) {
        if (brokerModelMap.putIfAbsent(brokerModel.getBrokerId(), brokerModel) == null) {
            try {
                String name = "broker." + brokerModel.getBrokerId();
                ObjectName objectName = new ObjectName(DEFAULT_JMX_DOMAIN, "name", ObjectName.quote(name));
                registerInJmx(objectName, brokerModel);
            } catch (Throwable e) {
                LOG.error("Failed to register " + brokerModel, e);
            }
        }
    }

    @Override
    public void remove(BrokerModel brokerModel) {
        if (brokerModel != null) {
            if (brokerModelMap.remove(brokerModel.getBrokerId()) != null) {
                brokerModel.unlockWriteLock();
                brokerModel.unlockReadLock();
                unregisterInJmx(brokerModel);
            }
        }
    }

    @Override
    public void register(MultiplexerInput multiplexerInput, DestinationStatistics destinationStatistics) {
        try {
            ObjectName objectName = new ObjectName(DEFAULT_JMX_DOMAIN, "name", destinationStatistics.getName());
            registerInJmx(objectName, destinationStatistics);
            destinationStatistics.start();
        } catch (Throwable e) {
            LOG.error("Failed to register " + destinationStatistics, e);
        }
    }

    @Override
    public void unregister(MultiplexerInput multiplexer, DestinationStatistics destinationStatistics) {
        try {
            destinationStatistics.stop();
            unregisterInJmx(destinationStatistics);
        } catch (Throwable e) {
            LOG.error("Failed to unregister " + destinationStatistics, e);
        }
    }

    @Override
    public BrokerModel getMostLoadedBroker() {
        BrokerModel result = null;
        if (!brokerModelMap.isEmpty()) {
            List list = new ArrayList<>(brokerModelMap.values());
            if (!list.isEmpty()) {
                if (list.size() > 1) {
                    Collections.sort(list, new BrokerComparable());
                    result = list.get(list.size() - 1);
                } else {
                    result = list.get(0);
                }
            }
        }
        return result;
    }

    @Override
    public BrokerModel getLeastLoadedBroker() {
        BrokerModel result = null;
        if (!brokerModelMap.isEmpty()) {
            List list = new ArrayList<>(brokerModelMap.values());
            if (!list.isEmpty()) {
                if (list.size() > 1) {
                    Collections.sort(list, new BrokerComparable());
                }
                result = list.get(0);
            }
        }
        return result;
    }

    @Override
    public BrokerModel getNextLeastLoadedBroker(BrokerModel brokerModel) {
        BrokerModel result = null;
        if (!brokerModelMap.isEmpty()) {
            List list = new ArrayList<>(brokerModelMap.values());
            if (!list.isEmpty()) {
                if (list.size() > 1) {
                    Collections.sort(list, new BrokerComparable());
                }

                for (int i = 0; i < list.size(); i++) {
                    BrokerModel bm = list.get(i);
                    if (bm.equals(brokerModel)) {
                        int offset = i + 1;
                        if (list.size() > offset) {
                            result = list.get(offset);
                        }
                        break;
                    }
                }
            }
        }
        return result;
    }

    @Override
    public boolean canScaleDownBrokers() {
        boolean result = false;
        int load = 0;
        for (BrokerModel model : brokerModelMap.values()) {
            load += getLoad(model);
        }
        if (load == 0 || (load * 100) / getBrokerCount() < 50) {
            result = true;
        }
        return result;
    }

    @Override
    public boolean shouldScaleUpBrokers() {
        for (BrokerModel brokerModel : brokerModelMap.values()) {
            if (areBrokerLimitsExceeded(brokerModel) || areDestinationLimitsExceeded(brokerModel)) {
                return true;
            }
        }
        return false;
    }

    @Override
    public Collection getBrokers() {
        return brokerModelMap.values();
    }

    @Override
    public int getBrokerCount() {
        return brokerModelMap.size();
    }

    @Override
    public BrokerModel getBrokerById(String id) {
        return brokerModelMap.get(id);
    }

    @Override
    public List getSortedDestinations(BrokerModel brokerModel, int maxNumber) {
        DestinationComparable destinationComparable = new DestinationComparable(brokerModel);
        return destinationComparable.getSortedDestinations(maxNumber);
    }

    @Override
    public List getSortedDestinations(BrokerModel brokerModel) {
        DestinationComparable destinationComparable = new DestinationComparable(brokerModel);
        return destinationComparable.getSortedDestinations();
    }

    @Override
    public Set getActiveDestinations(BrokerModel brokerModel) {
        return brokerModel.getActiveDestinations();
    }

    @Override
    public boolean areBrokerLimitsExceeded(BrokerModel brokerModel) {
        if (brokerModel != null) {
            BrokerOverview brokerOverview = brokerModel.getBrokerOverview();
            if (brokerOverview != null) {
                String brokerName = brokerModel.getBrokerId();
                int totalConnections = brokerOverview.getTotalConnections();
                int maxConnectionsPerBroker = brokerLimitsConfig.getMaxConnectionsPerBroker();
                boolean connectionsExceeded = totalConnections > maxConnectionsPerBroker;
                if (connectionsExceeded) {
                    LOG.info("Broker " + brokerName + " EXCEEDED connection limits(" + maxConnectionsPerBroker + ") with " + totalConnections + " connections");
                } else {
                    LOG.info("Broker " + brokerName + " within connection limits(" + maxConnectionsPerBroker + ") with " + totalConnections + " connections");
                }

                int totalDestinations = brokerOverview.getTotalActiveDestinations();
                int maxDestinationsPerBroker = brokerLimitsConfig.getMaxDestinationsPerBroker();
                boolean destinationsExceeded = totalDestinations > maxDestinationsPerBroker;

                if (destinationsExceeded) {
                    LOG.info("Broker " + brokerName + " EXCEEDED destination limits(" + maxDestinationsPerBroker + ") with " + totalDestinations + " active destinations");
                } else {
                    LOG.info("Broker " + brokerName + " within destination limits(" + maxDestinationsPerBroker + ") with " + totalDestinations + " active destinations");
                }
                return connectionsExceeded || destinationsExceeded;
            }
        }
        return false;
    }

    @Override
    public boolean areDestinationLimitsExceeded(BrokerModel brokerModel) {
        if (brokerModel != null) {
            BrokerOverview brokerOverview = brokerModel.getBrokerOverview();
            if (brokerOverview != null) {
                for (BrokerDestinationOverview brokerDestinationOverview : brokerOverview.getQueueOverviews().values()) {
                    if (brokerDestinationOverview.getQueueDepth() > brokerLimitsConfig.getMaxDestinationDepth()) {
                        return true;
                    }
                    if (brokerDestinationOverview.getNumberOfProducers() > brokerLimitsConfig.getMaxProducersPerDestination()) {
                        return true;
                    }
                    if (brokerDestinationOverview.getNumberOfConsumers() > brokerLimitsConfig.getMaxConsumersPerDestination()) {
                        return true;
                    }
                }
            }
            return false;
        }
        return false;
    }

    @Override
    public int getLoad(BrokerModel brokerModel) {
        int load = 0;
        if (brokerModel != null) {
            BrokerOverview brokerOverview = brokerModel.getBrokerOverview();
            if (brokerOverview != null) {
                int numConnections = brokerOverview.getTotalConnections();
                int connectionLoad = numConnections > 0 ? (numConnections * 30) / brokerLimitsConfig.getMaxConnectionsPerBroker() : 0;
                int numDestinations = brokerOverview.getTotalActiveDestinations();
                int destinationLoad = numDestinations > 0 ? (numDestinations * 35) / brokerLimitsConfig.getMaxDestinationsPerBroker() : 0;
                int queueDepth = brokerOverview.getTotalQueueDepth();
                int queueDepthLoad = queueDepth > 0 ? (queueDepth * 35) / brokerLimitsConfig.getMaxDestinationDepth() : 0;
                return destinationLoad + queueDepthLoad;
            }
        }
        return load;
    }

    @Override
    protected void doStart() throws Exception {
        jmxReporter.start();
    }

    @Override
    protected void doStop(ServiceStopper serviceStopper) throws Exception {
        jmxReporter.stop();
    }

    public void registerInJmx(ObjectName objectName, Object object) throws Exception {
        JMXUtils.registerMBean(object, objectName);
        objectNameMap.put(object, objectName);
    }

    public void unregisterInJmx(Object object) {
        ObjectName objectName = objectNameMap.remove(object);
        if (objectName != null) {
            JMXUtils.unregisterMBean(objectName);
        }
    }

    private class BrokerComparable implements Comparator {

        @Override
        public int compare(BrokerModel broker1, BrokerModel broker2) {
            int result = 0;
            if (broker1 != broker2) {
                result = getLoad(broker1) - getLoad(broker2);
            }
            return result;
        }
    }

    private class DestinationComparable implements Comparator {

        private final BrokerModel brokerModel;

        DestinationComparable(BrokerModel brokerModel) {
            this.brokerModel = brokerModel;
        }

        List getSortedDestinations() {
            List list = new ArrayList<>(brokerModel.getActiveDestinations());
            Collections.sort(list, this);
            return list;
        }

        List getSortedDestinations(int max) {
            List list = new ArrayList<>(brokerModel.getActiveDestinations());
            Collections.sort(list, this);
            if (max > 0 && list.size() > max) {
                while (list.size() > max) {
                    list.remove(list.size() - 1);
                }
            }
            return list;
        }

        @Override
        public int compare(ActiveMQDestination dest1, ActiveMQDestination dest2) {
            int depth1 = brokerModel.getDepth(dest1);
            int depth2 = brokerModel.getDepth(dest2);
            int result = depth1 - depth2;
            if (result == 0) {
                result = brokerModel.getNumberOfProducers(dest1) - brokerModel.getNumberOfProducers(dest2);
                if (result == 0) {
                    result = brokerModel.getNumberOfConsumers(dest1) - brokerModel.getNumberOfConsumers(dest2);
                }
            }
            return result;
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy