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

alluxio.master.AlluxioMaster Maven / Gradle / Ivy

/*
 * The Alluxio Open Foundation licenses this work under the Apache License, version 2.0
 * (the "License"). You may not use this work except in compliance with the License, which is
 * available at www.apache.org/licenses/LICENSE-2.0
 *
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied, as more fully set forth in the License.
 *
 * See the NOTICE file distributed with this work for information regarding copyright ownership.
 */

package alluxio.master;

import alluxio.AlluxioURI;
import alluxio.Configuration;
import alluxio.Constants;
import alluxio.RuntimeConstants;
import alluxio.master.block.BlockMaster;
import alluxio.master.file.FileSystemMaster;
import alluxio.master.journal.ReadWriteJournal;
import alluxio.master.lineage.LineageMaster;
import alluxio.metrics.MetricsSystem;
import alluxio.security.authentication.TransportProvider;
import alluxio.underfs.UnderFileSystem;
import alluxio.util.ConfigurationUtils;
import alluxio.util.LineageUtils;
import alluxio.util.network.NetworkAddressUtils;
import alluxio.util.network.NetworkAddressUtils.ServiceType;
import alluxio.web.MasterUIWebServer;
import alluxio.web.UIWebServer;

import com.google.common.base.Preconditions;
import com.google.common.base.Throwables;
import com.google.common.collect.Lists;

import org.apache.thrift.TMultiplexedProcessor;
import org.apache.thrift.TProcessor;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.server.TServer;
import org.apache.thrift.server.TThreadPoolServer;
import org.apache.thrift.server.TThreadPoolServer.Args;
import org.apache.thrift.transport.TServerSocket;
import org.apache.thrift.transport.TTransportFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.ServiceLoader;

import javax.annotation.concurrent.NotThreadSafe;
import javax.annotation.concurrent.ThreadSafe;

/**
 * Entry point for the Alluxio master program.
 */
@NotThreadSafe
public class AlluxioMaster {
  private static final Logger LOG = LoggerFactory.getLogger(Constants.LOGGER_TYPE);

  private static AlluxioMaster sAlluxioMaster = null;

  /**
   * Starts the Alluxio master.
   *
   * @param args command line arguments, should be empty
   */
  public static void main(String[] args) {
    if (args.length != 0) {
      LOG.info("java -cp {} {}", RuntimeConstants.ALLUXIO_JAR,
          AlluxioMaster.class.getCanonicalName());
      System.exit(-1);
    }

    // validate the conf
    if (!ConfigurationUtils.validateConf(Configuration.createServerConf())) {
      LOG.error("Invalid configuration found");
      System.exit(-1);
    }

    AlluxioMaster master = get();
    try {
      master.start();
    } catch (Exception e) {
      LOG.error("Uncaught exception while running Alluxio master, stopping it and exiting.", e);
      try {
        master.stop();
      } catch (Exception e2) {
        // continue to exit
        LOG.error("Uncaught exception while stopping Alluxio master, simply exiting.", e2);
      }
      System.exit(-1);
    }
  }

  /**
   * Returns a handle to the Alluxio master instance.
   *
   * @return Alluxio master handle
   */
  public static synchronized AlluxioMaster get() {
    if (sAlluxioMaster == null) {
      sAlluxioMaster = Factory.create();
    }
    return sAlluxioMaster;
  }

  /** Maximum number of threads to serve the rpc server. */
  private final int mMaxWorkerThreads;

  /** Minimum number of threads to serve the rpc server. */
  private final int mMinWorkerThreads;

  /** The port for the RPC server. */
  private final int mPort;

  /** The socket for thrift rpc server. */
  private final TServerSocket mTServerSocket;

  /** The transport provider to create thrift server transport. */
  private final TransportProvider mTransportProvider;

  /** The address for the rpc server. */
  private final InetSocketAddress mMasterAddress;

  /** The master metrics system. */
  private final MetricsSystem mMasterMetricsSystem;

  /** The master managing all block metadata. */
  protected BlockMaster mBlockMaster;

  /** The master managing all file system related metadata. */
  protected FileSystemMaster mFileSystemMaster;

  /** The master managing all lineage related metadata. */
  protected LineageMaster mLineageMaster;

  /** A list of extra masters to launch based on service loader. */
  protected List mAdditionalMasters;

  /** The journal for the block master. */
  protected final ReadWriteJournal mBlockMasterJournal;

  /** The journal for the file system master. */
  protected final ReadWriteJournal mFileSystemMasterJournal;

  /** The journal for the lineage master. */
  protected final ReadWriteJournal mLineageMasterJournal;

  /** The web ui server. */
  private UIWebServer mWebServer = null;

  /** The RPC server. */
  private TServer mMasterServiceServer = null;

  /** is true if the master is serving the RPC server. */
  private boolean mIsServing = false;

  /** The start time for when the master started serving the RPC server. */
  private long mStartTimeMs = -1;

  /** The master services' names. */
  private static List sServiceNames;

  /** The master service loaders. */
  private static ServiceLoader sServiceLoader;

  /**
   * @return the (cached) master service loader
   */
  private static ServiceLoader getServiceLoader() {
    if (sServiceLoader != null) {
      return sServiceLoader;
    }
    // Discover and register the available factories.
    // NOTE: ClassLoader is explicitly specified so we don't need to set ContextClassLoader.
    sServiceLoader = ServiceLoader.load(MasterFactory.class, MasterFactory.class.getClassLoader());
    return sServiceLoader;
  }

  /**
   * @return the (cached) list of the enabled master services' names
   */
  public static List getServiceNames() {
    if (sServiceNames != null) {
      return sServiceNames;
    }
    sServiceNames = new ArrayList<>();
    sServiceNames.add(Constants.BLOCK_MASTER_NAME);
    sServiceNames.add(Constants.FILE_SYSTEM_MASTER_NAME);
    sServiceNames.add(Constants.LINEAGE_MASTER_NAME);

    for (MasterFactory factory : getServiceLoader()) {
      if (factory.isEnabled()) {
        sServiceNames.add(factory.getName());
      }
    }

    return sServiceNames;
  }

  /**
   * Factory for creating {@link AlluxioMaster} or {@link FaultTolerantAlluxioMaster} based on
   * {@link Configuration}.
   */
  @ThreadSafe
  public static final class Factory {
    /**
     * @return {@link FaultTolerantAlluxioMaster} if Alluxio configuration is set to use zookeeper,
     *         otherwise, return {@link AlluxioMaster}.
     */
    public static AlluxioMaster create() {
      if (MasterContext.getConf().getBoolean(Constants.ZOOKEEPER_ENABLED)) {
        return new FaultTolerantAlluxioMaster();
      }
      return new AlluxioMaster();
    }

    private Factory() {} // prevent instantiation.
  }

  protected AlluxioMaster() {
    Configuration conf = MasterContext.getConf();

    mMinWorkerThreads = conf.getInt(Constants.MASTER_WORKER_THREADS_MIN);
    mMaxWorkerThreads = conf.getInt(Constants.MASTER_WORKER_THREADS_MAX);

    Preconditions.checkArgument(mMaxWorkerThreads >= mMinWorkerThreads,
        Constants.MASTER_WORKER_THREADS_MAX + " can not be less than "
            + Constants.MASTER_WORKER_THREADS_MIN);

    try {
      // Extract the port from the generated socket.
      // When running tests, it is fine to use port '0' so the system will figure out what port to
      // use (any random free port).
      // In a production or any real deployment setup, port '0' should not be used as it will make
      // deployment more complicated.
      if (!conf.getBoolean(Constants.IN_TEST_MODE)) {
        Preconditions.checkState(conf.getInt(Constants.MASTER_RPC_PORT) > 0,
            "Alluxio master rpc port is only allowed to be zero in test mode.");
        Preconditions.checkState(conf.getInt(Constants.MASTER_WEB_PORT) > 0,
            "Alluxio master web port is only allowed to be zero in test mode.");
      }
      mTransportProvider = TransportProvider.Factory.create(conf);
      mTServerSocket =
          new TServerSocket(NetworkAddressUtils.getBindAddress(ServiceType.MASTER_RPC, conf));
      mPort = NetworkAddressUtils.getThriftPort(mTServerSocket);
      // reset master port
      conf.set(Constants.MASTER_RPC_PORT, Integer.toString(mPort));
      mMasterAddress = NetworkAddressUtils.getConnectAddress(ServiceType.MASTER_RPC, conf);

      // Check the journal directory
      String journalDirectory = conf.get(Constants.MASTER_JOURNAL_FOLDER);
      if (!journalDirectory.endsWith(AlluxioURI.SEPARATOR)) {
        journalDirectory += AlluxioURI.SEPARATOR;
      }
      Preconditions.checkState(isJournalFormatted(journalDirectory),
          "Alluxio master was not formatted! The journal folder is " + journalDirectory);

      // Create the journals.
      mBlockMasterJournal = new ReadWriteJournal(BlockMaster.getJournalDirectory(journalDirectory));
      mFileSystemMasterJournal =
          new ReadWriteJournal(FileSystemMaster.getJournalDirectory(journalDirectory));
      mLineageMasterJournal =
          new ReadWriteJournal(LineageMaster.getJournalDirectory(journalDirectory));

      mBlockMaster = new BlockMaster(mBlockMasterJournal);
      mFileSystemMaster = new FileSystemMaster(mBlockMaster, mFileSystemMasterJournal);
      if (LineageUtils.isLineageEnabled(MasterContext.getConf())) {
        mLineageMaster = new LineageMaster(mFileSystemMaster, mLineageMasterJournal);
      }

      mAdditionalMasters = new ArrayList<>();
      List masters = Lists.newArrayList(mBlockMaster, mFileSystemMaster);
      for (MasterFactory factory : getServiceLoader()) {
        Master master = factory.create(masters, journalDirectory);
        if (master != null) {
          mAdditionalMasters.add(master);
        }
      }

      MasterContext.getMasterSource().registerGauges(this);
      mMasterMetricsSystem = new MetricsSystem("master", MasterContext.getConf());
      mMasterMetricsSystem.registerSource(MasterContext.getMasterSource());
    } catch (Exception e) {
      LOG.error(e.getMessage(), e);
      throw Throwables.propagate(e);
    }
  }

  /**
   * @return the externally resolvable address of this master
   */
  public InetSocketAddress getMasterAddress() {
    return mMasterAddress;
  }

  /**
   * @return the actual bind hostname on RPC service (used by unit test only)
   */
  public String getRPCBindHost() {
    return NetworkAddressUtils.getThriftSocket(mTServerSocket).getInetAddress().getHostAddress();
  }

  /**
   * @return the actual port that the RPC service is listening on (used by unit test only)
   */
  public int getRPCLocalPort() {
    return mPort;
  }

  /**
   * @return the actual bind hostname on web service (used by unit test only)
   */
  public String getWebBindHost() {
    if (mWebServer != null) {
      return mWebServer.getBindHost();
    }
    return "";
  }

  /**
   * @return the actual port that the web service is listening on (used by unit test only)
   */
  public int getWebLocalPort() {
    if (mWebServer != null) {
      return mWebServer.getLocalPort();
    }
    return -1;
  }

  /**
   * @return internal {@link BlockMaster}
   */
  public BlockMaster getBlockMaster() {
    return mBlockMaster;
  }

  /**
   * @return other additional {@link Master}s
   */
  public List getAdditionalMasters() {
    return Collections.unmodifiableList(mAdditionalMasters);
  }

  /**
   * @return internal {@link FileSystemMaster}
   */
  public FileSystemMaster getFileSystemMaster() {
    return mFileSystemMaster;
  }

  /**
   * @return internal {@link LineageMaster}
   */
  public LineageMaster getLineageMaster() {
    return mLineageMaster;
  }

  /**
   * @return the start time of the master in milliseconds
   */
  public long getStartTimeMs() {
    return mStartTimeMs;
  }

  /**
   * @return the uptime of the master in milliseconds
   */
  public long getUptimeMs() {
    return System.currentTimeMillis() - mStartTimeMs;
  }

  /**
   * @return true if the system is the leader (serving the rpc server), false otherwise
   */
  boolean isServing() {
    return mIsServing;
  }

  /**
   * Starts the Alluxio master server.
   *
   * @throws Exception if starting the master fails
   */
  public void start() throws Exception {
    startMasters(true);
    startServing();
  }

  /**
   * Stops the Alluxio master server.
   *
   * @throws Exception if stopping the master fails
   */
  public void stop() throws Exception {
    if (mIsServing) {
      LOG.info("Stopping RPC server on Alluxio master @ {}", mMasterAddress);
      stopServing();
      stopMasters();
      mTServerSocket.close();
      mIsServing = false;
    } else {
      LOG.info("Stopping Alluxio master @ {}", mMasterAddress);
    }
  }

  protected void startMasters(boolean isLeader) {
    try {
      connectToUFS();

      mBlockMaster.start(isLeader);
      mFileSystemMaster.start(isLeader);
      if (LineageUtils.isLineageEnabled(MasterContext.getConf())) {
        mLineageMaster.start(isLeader);
      }
      // start additional masters
      for (Master master : mAdditionalMasters) {
        master.start(isLeader);
      }

    } catch (IOException e) {
      LOG.error(e.getMessage(), e);
      throw Throwables.propagate(e);
    }
  }

  protected void stopMasters() {
    try {
      if (LineageUtils.isLineageEnabled(MasterContext.getConf())) {
        mLineageMaster.stop();
      }
      // stop additional masters
      for (Master master : mAdditionalMasters) {
        master.stop();
      }
      mBlockMaster.stop();
      mFileSystemMaster.stop();
    } catch (IOException e) {
      LOG.error(e.getMessage(), e);
      throw Throwables.propagate(e);
    }
  }

  private void startServing() {
    startServing("", "");
  }

  protected void startServing(String startMessage, String stopMessage) {
    mMasterMetricsSystem.start();
    startServingWebServer();
    LOG.info("Alluxio master version {} started @ {} {}", RuntimeConstants.VERSION, mMasterAddress,
        startMessage);
    startServingRPCServer();
    LOG.info("Alluxio master version {} ended @ {} {}", RuntimeConstants.VERSION, mMasterAddress,
        stopMessage);
  }

  protected void startServingWebServer() {
    Configuration conf = MasterContext.getConf();
    mWebServer = new MasterUIWebServer(ServiceType.MASTER_WEB,
        NetworkAddressUtils.getBindAddress(ServiceType.MASTER_WEB, conf), this, conf);

    // Add the metrics servlet to the web server, this must be done after the metrics system starts
    mWebServer.addHandler(mMasterMetricsSystem.getServletHandler());
    // start web ui
    mWebServer.startWebServer();
  }

  private void registerServices(TMultiplexedProcessor processor, Map services) {
    for (Map.Entry service : services.entrySet()) {
      processor.registerProcessor(service.getKey(), service.getValue());
    }
  }

  protected void startServingRPCServer() {
    // set up multiplexed thrift processors
    TMultiplexedProcessor processor = new TMultiplexedProcessor();
    registerServices(processor, mBlockMaster.getServices());
    registerServices(processor, mFileSystemMaster.getServices());
    if (LineageUtils.isLineageEnabled(MasterContext.getConf())) {
      registerServices(processor, mLineageMaster.getServices());
    }
    // register additional masters for RPC service
    for (Master master : mAdditionalMasters) {
      registerServices(processor, master.getServices());
    }

    // Return a TTransportFactory based on the authentication type
    TTransportFactory transportFactory;
    try {
      transportFactory = mTransportProvider.getServerTransportFactory();
    } catch (IOException e) {
      throw Throwables.propagate(e);
    }

    // create master thrift service with the multiplexed processor.
    Args args = new TThreadPoolServer.Args(mTServerSocket).maxWorkerThreads(mMaxWorkerThreads)
        .minWorkerThreads(mMinWorkerThreads).processor(processor).transportFactory(transportFactory)
        .protocolFactory(new TBinaryProtocol.Factory(true, true));
    if (MasterContext.getConf().getBoolean(Constants.IN_TEST_MODE)) {
      args.stopTimeoutVal = 0;
    } else {
      args.stopTimeoutVal = Constants.THRIFT_STOP_TIMEOUT_SECONDS;
    }
    mMasterServiceServer = new TThreadPoolServer(args);

    // start thrift rpc server
    mIsServing = true;
    mStartTimeMs = System.currentTimeMillis();
    mMasterServiceServer.serve();
  }

  protected void stopServing() throws Exception {
    if (mMasterServiceServer != null) {
      mMasterServiceServer.stop();
      mMasterServiceServer = null;
    }
    if (mWebServer != null) {
      mWebServer.shutdownWebServer();
      mWebServer = null;
    }
    mMasterMetricsSystem.stop();
    mIsServing = false;
  }

  /**
   * Checks to see if the journal directory is formatted.
   *
   * @param journalDirectory the journal directory to check
   * @return true if the journal directory was formatted previously, false otherwise
   * @throws IOException if an I/O error occurs
   */
  private boolean isJournalFormatted(String journalDirectory) throws IOException {
    Configuration conf = MasterContext.getConf();
    UnderFileSystem ufs = UnderFileSystem.get(journalDirectory, conf);
    if (!ufs.providesStorage()) {
      // TODO(gene): Should the journal really be allowed on a ufs without storage?
      // This ufs doesn't provide storage. Allow the master to use this ufs for the journal.
      LOG.info("Journal directory doesn't provide storage: {}", journalDirectory);
      return true;
    }
    String[] files = ufs.list(journalDirectory);
    if (files == null) {
      return false;
    }
    // Search for the format file.
    String formatFilePrefix = conf.get(Constants.MASTER_FORMAT_FILE_PREFIX);
    for (String file : files) {
      if (file.startsWith(formatFilePrefix)) {
        return true;
      }
    }
    return false;
  }

  private void connectToUFS() throws IOException {
    Configuration conf = MasterContext.getConf();
    String ufsAddress = conf.get(Constants.UNDERFS_ADDRESS);
    UnderFileSystem ufs = UnderFileSystem.get(ufsAddress, conf);
    ufs.connectFromMaster(conf, NetworkAddressUtils.getConnectHost(ServiceType.MASTER_RPC, conf));
  }

  /**
   * @return the master metric system reference
   */
  public MetricsSystem getMasterMetricsSystem() {
    return mMasterMetricsSystem;
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy