/* * 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. */ package org.apache.hadoop.hive.llap.registry.impl; import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.MalformedURLException; import java.net.URL; import java.net.UnknownHostException; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.hadoop.classification.InterfaceAudience; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hive.conf.HiveConf; import org.apache.hadoop.hive.conf.HiveConf.ConfVars; import org.apache.hadoop.hive.llap.registry.ServiceInstance; import org.apache.hadoop.hive.llap.registry.ServiceInstanceSet; import org.apache.hadoop.hive.llap.registry.ServiceInstanceStateChangeListener; import org.apache.hadoop.hive.llap.registry.ServiceRegistry; import org.apache.hadoop.net.NetUtils; import org.apache.hadoop.util.StringUtils; import org.apache.hadoop.yarn.api.records.ApplicationId; import org.apache.hadoop.yarn.api.records.Resource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class LlapFixedRegistryImpl implements ServiceRegistry { private static final Logger LOG = LoggerFactory.getLogger(LlapFixedRegistryImpl.class); @InterfaceAudience.Private // This is primarily for testing to avoid the host lookup public static final String FIXED_REGISTRY_RESOLVE_HOST_NAMES = "fixed.registry.resolve.host.names"; private final int port; private final int shuffle; private final int mngPort; private final int webPort; private final int outputFormatPort; private final String webScheme; private final String[] hosts; private final int memory; private final int vcores; private final boolean resolveHosts; private final Map<String, String> srv = new HashMap<String, String>(); public LlapFixedRegistryImpl(String hosts, Configuration conf) { this.hosts = hosts.split(","); this.port = HiveConf.getIntVar(conf, ConfVars.LLAP_DAEMON_RPC_PORT); this.shuffle = HiveConf.getIntVar(conf, ConfVars.LLAP_DAEMON_YARN_SHUFFLE_PORT); this.resolveHosts = conf.getBoolean(FIXED_REGISTRY_RESOLVE_HOST_NAMES, true); this.mngPort = HiveConf.getIntVar(conf, ConfVars.LLAP_MANAGEMENT_RPC_PORT); this.outputFormatPort = HiveConf.getIntVar(conf, ConfVars.LLAP_DAEMON_OUTPUT_SERVICE_PORT); this.webPort = HiveConf.getIntVar(conf, ConfVars.LLAP_DAEMON_WEB_PORT); boolean isSsl = HiveConf.getBoolVar(conf, ConfVars.LLAP_DAEMON_WEB_SSL); this.webScheme = isSsl ? "https" : "http"; for (Map.Entry<String, String> kv : conf) { if (kv.getKey().startsWith(HiveConf.PREFIX_LLAP) || kv.getKey().startsWith(HiveConf.PREFIX_HIVE_LLAP)) { // TODO: read this somewhere useful, like the task scheduler srv.put(kv.getKey(), kv.getValue()); } } this.memory = HiveConf.getIntVar(conf, ConfVars.LLAP_DAEMON_MEMORY_PER_INSTANCE_MB); this.vcores = HiveConf.getIntVar(conf, ConfVars.LLAP_DAEMON_NUM_EXECUTORS); } @Override public void start() throws IOException { // nothing to start } @Override public void stop() throws IOException { // nothing to stop } @Override public String register() throws IOException { // nothing to register (return host-<hostname>) return getWorkerIdentity(InetAddress.getLocalHost().getCanonicalHostName()); } @Override public void unregister() throws IOException { // nothing to unregister } public static String getWorkerIdentity(String host) { // trigger clean errors for anyone who mixes up identity with hosts return "host-" + host; } private final class FixedServiceInstance implements ServiceInstance { private final String host; private final String serviceAddress; public FixedServiceInstance(String host) { if (resolveHosts) { try { InetAddress inetAddress = InetAddress.getByName(host); if (NetUtils.isLocalAddress(inetAddress)) { InetSocketAddress socketAddress = new InetSocketAddress(0); socketAddress = NetUtils.getConnectAddress(socketAddress); LOG.info("Adding host identified as local: " + host + " as " + socketAddress.getHostName()); host = socketAddress.getHostName(); } } catch (UnknownHostException e) { LOG.warn("Ignoring resolution issues for host: " + host, e); } } this.host = host; final URL serviceURL; try { serviceURL = new URL(LlapFixedRegistryImpl.this.webScheme, host, LlapFixedRegistryImpl.this.webPort, ""); this.serviceAddress = serviceURL.toString(); } catch (MalformedURLException e) { throw new RuntimeException(e); } } public String getWorkerIdentity() { return LlapFixedRegistryImpl.getWorkerIdentity(host); } @Override public String getHost() { return host; } @Override public int getRpcPort() { // TODO: allow >1 port per host? return LlapFixedRegistryImpl.this.port; } @Override public int getManagementPort() { return LlapFixedRegistryImpl.this.mngPort; } @Override public int getShufflePort() { return LlapFixedRegistryImpl.this.shuffle; } @Override public int getOutputFormatPort() { return LlapFixedRegistryImpl.this.outputFormatPort; } @Override public String getServicesAddress() { return serviceAddress; } @Override public Map<String, String> getProperties() { Map<String, String> properties = new HashMap<>(srv); // no worker identity return properties; } @Override public Resource getResource() { return Resource.newInstance(memory, vcores); } @Override public String toString() { return "FixedServiceInstance{" + "host=" + host + ", memory=" + memory + ", vcores=" + vcores + '}'; } } private final class FixedServiceInstanceSet implements ServiceInstanceSet { // LinkedHashMap have a repeatable iteration order. private final Map<String, ServiceInstance> instances = new LinkedHashMap<>(); public FixedServiceInstanceSet() { for (String host : hosts) { // trigger bugs in anyone who uses this as a hostname instances.put(getWorkerIdentity(host), new FixedServiceInstance(host)); } } @Override public Collection<ServiceInstance> getAll() { return instances.values(); } @Override public List<ServiceInstance> getAllInstancesOrdered(boolean consistentIndexes) { List<ServiceInstance> list = new LinkedList<>(); list.addAll(instances.values()); Collections.sort(list, new Comparator<ServiceInstance>() { @Override public int compare(ServiceInstance o1, ServiceInstance o2) { return o2.getWorkerIdentity().compareTo(o2.getWorkerIdentity()); } }); return list; } @Override public ServiceInstance getInstance(String name) { return instances.get(name); } @Override public Set<ServiceInstance> getByHost(String host) { Set<ServiceInstance> byHost = new HashSet<ServiceInstance>(); ServiceInstance inst = getInstance(getWorkerIdentity(host)); if (inst != null) { byHost.add(inst); } return byHost; } @Override public int size() { return instances.size(); } } @Override public ServiceInstanceSet getInstances(String component, long timeoutMs) throws IOException { return new FixedServiceInstanceSet(); } @Override public void registerStateChangeListener(final ServiceInstanceStateChangeListener listener) { // nothing to set LOG.warn("Callbacks for instance state changes are not supported in fixed registry."); } @Override public String toString() { return String.format("FixedRegistry hosts=%s", StringUtils.join(",", this.hosts)); } @Override public ApplicationId getApplicationId() throws IOException { return null; // No good way to find out (may even have no app). } }