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

org.apache.flink.runtime.healthmanager.metrics.RestServerMetricProvider Maven / Gradle / Ivy

/*
 * 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 org.apache.flink.runtime.healthmanager.metrics;

import org.apache.flink.api.common.JobID;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.configuration.ConfigOption;
import org.apache.flink.configuration.ConfigOptions;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.runtime.healthmanager.RestServerClient;
import org.apache.flink.runtime.healthmanager.metrics.timeline.TimelineAggType;
import org.apache.flink.runtime.healthmanager.metrics.timeline.TimelineAggregatorDescriptor;
import org.apache.flink.runtime.jobgraph.JobVertexID;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

/**
 * MetricProvider based on Rest Server.
 */
public class RestServerMetricProvider implements MetricProvider {

	private static final Logger LOGGER = LoggerFactory.getLogger(RestServerMetricProvider.class);

	private static final ConfigOption METRIC_FETCH_INTERVAL_OPTION =
			ConfigOptions.key("metric.provider.fetch.interval.ms").defaultValue(10_000L);

	private static final ConfigOption METRIC_FLOATING_TIMELINE_WINDOW_OPTION =
			ConfigOptions.key("metric.provider.floating.timeline.window.enabled").defaultValue(true);

	private Configuration config;
	private RestServerClient restServerClient;
	private ScheduledExecutorService scheduledExecutorService;

	private ScheduledFuture fetchTaskHandler;

	/** all task metric subscription, format: [job id, [vertex id, [metric name, subscription]]]. */
	private Map>>> taskMetricSubscriptions =
			new HashMap<>();
	/** all job tm metric subscription, format: [job id, [metric name, subscription]]. */
	private Map>> jobTMMetricSubscriptions = new HashMap<>();
	/** all tm metric subscription, format: [tm id, [metric name, subscription]]. */
	private Map>> tmMetricSubscriptions = new HashMap<>();

	public RestServerMetricProvider(
			Configuration config,
			RestServerClient restServerClient,
			ScheduledExecutorService scheduledExecutorService) {

		this.config = config;
		this.restServerClient = restServerClient;
		this.scheduledExecutorService = scheduledExecutorService;

	}

	@Override
	public void open() {
		long fetchIntervalMS = this.config.getLong(METRIC_FETCH_INTERVAL_OPTION);
		fetchTaskHandler = this.scheduledExecutorService.scheduleAtFixedRate(
				new MetricFetcher(), fetchIntervalMS, fetchIntervalMS, TimeUnit.MILLISECONDS);
	}

	@Override
	public void close() {
		if (fetchTaskHandler != null) {
			fetchTaskHandler.cancel(true);
		}
	}

	@Override
	public synchronized JobTMMetricSubscription subscribeAllTMMetric(
			JobID jobID, String metricName, long timeInterval, TimelineAggType timeAggType) {
		long startTime = config.getBoolean(METRIC_FLOATING_TIMELINE_WINDOW_OPTION) ? System.currentTimeMillis() : 0;
		JobTMMetricSubscription metricSubscription = new JobTMMetricSubscription(
				jobID, metricName, new TimelineAggregatorDescriptor.SimpleTimelineAggregatorDescriptor(timeAggType, timeInterval, startTime));
		jobTMMetricSubscriptions
				.computeIfAbsent(jobID, k -> new HashMap<>())
				.computeIfAbsent(metricName, k-> new LinkedList<>()).add(metricSubscription);
		return metricSubscription;
	}

	@Override
	public synchronized TaskManagerMetricSubscription subscribeTaskManagerMetric(
			String tmId, String metricName, long timeInterval, TimelineAggType timeAggType) {
		long startTime = config.getBoolean(METRIC_FLOATING_TIMELINE_WINDOW_OPTION) ? System.currentTimeMillis() : 0;
		TaskManagerMetricSubscription metricSubscription = new TaskManagerMetricSubscription(
				tmId, metricName, new TimelineAggregatorDescriptor.SimpleTimelineAggregatorDescriptor(timeAggType, timeInterval, startTime));
		tmMetricSubscriptions.computeIfAbsent(tmId, k -> new HashMap<>())
				.computeIfAbsent(metricName, k -> new LinkedList<>()).add(metricSubscription);
		return metricSubscription;
	}

	@Override
	public synchronized TaskMetricSubscription subscribeTaskMetric(
			JobID jobId, JobVertexID vertexId, String metricName, MetricAggType subtaskAggType,
			long timeInterval, TimelineAggType timeAggType) {
		long startTime = config.getBoolean(METRIC_FLOATING_TIMELINE_WINDOW_OPTION) ? System.currentTimeMillis() : 0;
		TaskMetricSubscription metricSubscription = new TaskMetricSubscription(
				jobId, vertexId, subtaskAggType, metricName, new TimelineAggregatorDescriptor.SimpleTimelineAggregatorDescriptor(timeAggType, timeInterval, startTime));
		taskMetricSubscriptions.computeIfAbsent(jobId, k -> new HashMap<>())
				.computeIfAbsent(vertexId, k -> new HashMap<>())
				.computeIfAbsent(metricName, k -> new LinkedList<>()).add(metricSubscription);
		return metricSubscription;
	}

	@Override
	public TaskMetricSubscription subscribeTaskMetric(JobID jobId, JobVertexID vertexId,
			String metricName, MetricAggType subtaskAggType, long timelineInterval,
			TimelineAggType timelineAggType, long subTimelineInterval,
			TimelineAggType subTimelineAggType) {
		long startTime = config.getBoolean(METRIC_FLOATING_TIMELINE_WINDOW_OPTION) ? System.currentTimeMillis() : 0;
		TaskMetricSubscription metricSubscription = new TaskMetricSubscription(
				jobId, vertexId, subtaskAggType, metricName, new TimelineAggregatorDescriptor.CombinedTimelineAggregatorDescriptor(timelineAggType, timelineInterval, subTimelineAggType, subTimelineInterval, startTime));
		taskMetricSubscriptions.computeIfAbsent(jobId, k -> new HashMap<>())
				.computeIfAbsent(vertexId, k -> new HashMap<>())
				.computeIfAbsent(metricName, k -> new LinkedList<>()).add(metricSubscription);
		return metricSubscription;
	}

	@Override
	public synchronized void unsubscribe(MetricSubscription subscription) {

		if (subscription instanceof TaskMetricSubscription) {
			TaskMetricSubscription taskMetricSubscription = (TaskMetricSubscription) subscription;
			Map>> subscriptionByJobVertex =
					taskMetricSubscriptions.get(taskMetricSubscription.getJobID());
			Map> subscriptionByMetricName =
					subscriptionByJobVertex.get(taskMetricSubscription.getJobVertexID());

			List subscriptionsOfOneMetric =
					subscriptionByMetricName.get(taskMetricSubscription.getMetricName());
			subscriptionsOfOneMetric.remove(taskMetricSubscription);
			if (subscriptionsOfOneMetric.isEmpty()) {
				subscriptionByMetricName.remove(taskMetricSubscription.getMetricName());
				if (subscriptionByMetricName.isEmpty()) {
					subscriptionByJobVertex.remove(taskMetricSubscription.getJobVertexID());
					if (subscriptionByJobVertex.isEmpty()) {
						taskMetricSubscriptions.remove(taskMetricSubscription.getJobID());
					}
				}
			}
		}

		if (subscription instanceof TaskManagerMetricSubscription) {
			TaskManagerMetricSubscription taskManagerMetricSubscription = (TaskManagerMetricSubscription) subscription;
			Map> subscriptionByMetricName =
					tmMetricSubscriptions.get(taskManagerMetricSubscription.getTmId());
			List subscriptionsOfOneMetric =
					subscriptionByMetricName.get(taskManagerMetricSubscription.getMetricName());
			subscriptionsOfOneMetric.remove(taskManagerMetricSubscription);
			if (subscriptionsOfOneMetric.isEmpty()) {
				subscriptionByMetricName.remove(taskManagerMetricSubscription.getMetricName());
				if (subscriptionByMetricName.isEmpty()) {
					tmMetricSubscriptions.remove(taskManagerMetricSubscription.getTmId());
				}
			}
		}

		if (subscription instanceof JobTMMetricSubscription) {
			JobTMMetricSubscription jobTMMetricSubscription = (JobTMMetricSubscription) subscription;
			Map> subscriptionByMetricName =
					jobTMMetricSubscriptions.get(jobTMMetricSubscription.getJobID());
			List subscriptionOfOneMetric =
					subscriptionByMetricName.get(jobTMMetricSubscription.getMetricName());
			subscriptionOfOneMetric.remove(jobTMMetricSubscription);
			if (subscriptionOfOneMetric.isEmpty()) {
				subscriptionByMetricName.remove(jobTMMetricSubscription.getMetricName());
				if (subscriptionByMetricName.isEmpty()) {
					jobTMMetricSubscriptions.remove(jobTMMetricSubscription.getJobID());
				}
			}
		}
	}

	private class MetricFetcher implements Runnable {

		@Override
		public void run() {
			synchronized (RestServerMetricProvider.this) {
				try {
					for (Map.Entry>>> jobEntry : taskMetricSubscriptions.entrySet()) {
						for (Map.Entry>> vertexEntry : jobEntry.getValue().entrySet()) {
							Map>> values =
									restServerClient.getTaskMetrics(jobEntry.getKey(), vertexEntry.getKey(), vertexEntry.getValue().keySet());
							for (Map.Entry> metricEntry : vertexEntry.getValue().entrySet()) {
								for (TaskMetricSubscription subscription : metricEntry.getValue()) {
									if (values.containsKey(metricEntry.getKey())) {
										subscription.addValue(values.get(metricEntry.getKey()));
									}
								}
							}
						}
					}

					for (Map.Entry>> jobEntry : jobTMMetricSubscriptions.entrySet()) {
						Map>> values =
								restServerClient.getTaskManagerMetrics(jobEntry.getKey(), jobEntry.getValue().keySet());
						for (Map.Entry> metricEntry : jobEntry.getValue().entrySet()) {
							for (JobTMMetricSubscription subscription : metricEntry.getValue()) {
								if (values.containsKey(metricEntry.getKey())) {
									subscription.addValue(values.get(metricEntry.getKey()));
								}
							}
						}
					}

					for (Map.Entry>> tmEntry : tmMetricSubscriptions.entrySet()) {
						Map>> values =
								restServerClient.getTaskManagerMetrics(Collections.singleton(tmEntry.getKey()), tmEntry.getValue().keySet());
						for (Map.Entry> metricEntry : tmEntry.getValue().entrySet()) {
							for (TaskManagerMetricSubscription subscription : metricEntry.getValue()) {
								if (values.containsKey(metricEntry.getKey())) {
									subscription.addValue(values.get(metricEntry.getKey()).get(tmEntry.getKey()));
								}
							}
						}
					}
				} catch (Throwable e) {
					LOGGER.warn("Fail to fetch metrics", e);
				}
			}
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy