/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF 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 com.alibaba.jstorm.task.master.metrics; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; import backtype.storm.task.TopologyContext; import com.alibaba.jstorm.cluster.StormClusterState; import com.alibaba.jstorm.task.error.ErrorConstants; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.alibaba.jstorm.cluster.Common; import com.alibaba.jstorm.metric.MetricsRegister; import com.alibaba.jstorm.schedule.default_assign.ResourceWorkerSlot; import com.alibaba.jstorm.task.master.TMHandler; import com.alibaba.jstorm.task.master.TopologyMasterContext; import backtype.storm.tuple.Tuple; import backtype.storm.tuple.Values; public class MetricRegister implements TMHandler { static private final Logger LOG = LoggerFactory.getLogger(MetricRegister.class); private MetricsRegister metricsRegister; private TopologyMasterContext tmContext; private StormClusterState zkCluster; private TopologyContext context; private final AtomicBoolean pending = new AtomicBoolean(false); private final AtomicReference<Set<String>> metricNames = new AtomicReference<>(); @Override public void init(TopologyMasterContext tmContext) { this.tmContext = tmContext; this.zkCluster = tmContext.getZkCluster(); this.context = tmContext.getContext(); this.metricsRegister = new MetricsRegister(tmContext.getConf(), tmContext.getTopologyId()); metricNames.set(new HashSet<String>()); } @Override public void process(Object event) throws Exception { if (event instanceof Tuple) { registerMetrics((Tuple) event); } else if (event instanceof MetricsMetaBroadcastEvent) { broadcast(); } else { zkCluster.report_task_error(context.getTopologyId(), context.getThisTaskId(), "Unknown event", ErrorConstants.WARN, ErrorConstants.CODE_USER); throw new RuntimeException("Unknown event"); } } @Override public void cleanup() { } private void registerMetrics(Tuple input) { synchronized (metricNames) { metricNames.get().addAll((Set<String>) input.getValue(0)); } } public void broadcast() { if (pending.compareAndSet(false, true)) { try { Set<String> oldMetricsNames = metricNames.getAndSet(new HashSet<String>()); if (oldMetricsNames.size() > 0) { LOG.debug("register metrics to nimbus from TM, size:{}", oldMetricsNames.size()); Map<String, Long> nameIdMap = metricsRegister.registerMetrics(oldMetricsNames); LOG.debug("register metrics to nimbus from TM, ret size:{}", nameIdMap.size()); if (nameIdMap.size() > 0) { // we broadcast metrics meta to all workers, for large // topologies, might be quite large for (ResourceWorkerSlot worker : tmContext.getWorkerSet().get()) { Set<Integer> tasks = worker.getTasks(); int task = tasks.iterator().next(); tmContext.getCollector().getDelegate().emitDirect(task, Common.TOPOLOGY_MASTER_REGISTER_METRICS_RESP_STREAM_ID, null, new Values(nameIdMap)); } } } } catch (Throwable e) { LOG.error("Error:", e); } finally { pending.set(false); } } else { LOG.warn("pending register metrics, skip..."); } } }