hdp ambari-server start 过程分析

在linux下我们启动ambari-server的时候只需要执行命令ambari-server start
那么我们就从这个命令开始分析一下这个启动过程都干了啥

$ ambari-server start --debug
Using python  /usr/bin/python
Starting ambari-server
Ambari Server running with administrator privileges.
Organizing resource files at /var/lib/ambari-server/resources...
Ambari database consistency check started...
Server PID at: /var/run/ambari-server/ambari-server.pid
Server out at: /var/log/ambari-server/ambari-server.out
Server log at: /var/log/ambari-server/ambari-server.log
Waiting for server start.................................
Server started listening on 8080

DB configs consistency check found warnings. See /var/log/ambari-server/ambari-server-check-database.log for more details.
Ambari Server 'start' completed successfully.

当我们执行完这个命令后,脚本在/etc/init.d/ambari-server,这个脚本定义了ambari-server的start/stop/restart/status....
在源码中这个文件在ambari-server工程目录下的sbin/ambari-server
Ambari-server安装后在liunx上其实是个软链接

[root@host-10-1-yy-xx sbin]# ls -al /sbin/ambari-server
lrwxrwxrwx 1 root root 25 Apr  1 17:14 /sbin/ambari-server -> /etc/init.d/ambari-server

ambari-server

#ambari-server
#$@=传入脚本的所有参数
AMBARI_PYTHON_EXECUTABLE="$ROOT/usr/sbin/ambari-server.py"
echo "Using python " $PYTHON

ret=0
case "${1:-}" in
  start)
        echo -e "Starting ambari-server"
        $PYTHON "$AMBARI_PYTHON_EXECUTABLE" "$@"
        ;;
  stop)
        echo -e "Stopping ambari-server"
        $PYTHON "$AMBARI_PYTHON_EXECUTABLE" "$@"
        ;;
 ...

从文件中我们可以看出ambari-server start,其实执行的是/usr/sbin/ambari-server.py start

ambari-server.py

# ambari-server.py
@OsFamilyFuncImpl(OsFamilyImpl.DEFAULT)
def start(args):
  logger.info("Starting ambari-server.")
  status, pid = is_server_runing() #先检查ambari-server是否已经在running
  if status:
    err = "Ambari Server is already running."
    raise FatalException(1, err)

  server_process_main(args) #这个里边儿才真正开始处理起动过程
  logger.info("Started ambari-server.")

ambari_server_main.py

# ambari_server_main.py
def server_process_main(options, scmStatus=None):
  #先去读取这个配置文件/etc/ambari-server/conf/ambari.properties
  properties = get_ambari_properties()
  if properties == -1:
    err ="Error getting ambari properties"
    raise FatalException(-1, err)

  properties_for_print = []
  logger.info("Ambari server properties config:")
  for key, value in properties.getPropertyDict().items():
     if "passwd" not in key and "password" not in key:
       properties_for_print.append(key + "=" + value)

  logger.info(properties_for_print)

  # debug mode, including stop Java process at startup
  try:
    #如果有--debug启动,就会在这里设置为debug模式
    set_debug_mode_from_options(options)
  except AttributeError:
    pass

  # 检查hostname dns
  if not check_reverse_lookup():
    print_warning_msg("The hostname was not found in the reverse DNS lookup. "
                      "This may result in incorrect behavior. "
                      "Please check the DNS setup and fix the issue.")

  #检查在/etc/ambari-server/conf/ambari.properties中是否有配置数据库名称    
  #server.jdbc.database_name=ambari
  check_database_name_property()
  #从配置文件/etc/ambari-server/conf/ambari.properties中,加载数据库连接相关属性
  parse_properties_file(options)

  #检查配置文件/etc/ambari-server/conf/ambari.properties中是否有配置active.instance
  #如果没有配置默认这个值就为true,如果有的话也应配置为true,如果不为true的话,这个节点就不能启动ambari-server
  is_active_instance = get_is_active_instance()
  if not is_active_instance:
      print_warning_msg("This instance of ambari server is not designated as active. Cannot start ambari server.")
      err = "This is not an active instance. Shutting down..."
      raise FatalException(1, err)

  #从配置/etc/ambari-server/conf/ambari.properties中读到ambari-server.user=root
  ambari_user = read_ambari_user()
  #会判断当前用户是不是$ambari_user,是不是root用户
  #如果不是,会提示必须用root用户,sudo或者$ambari_user启动服务
  current_user = ensure_can_start_under_current_user(ambari_user)

  print_info_msg("Ambari Server is not running...")
  
  # 会首先查检配置在/etc/ambari-server/conf/ambari.properties中java.home=/usr/jdk64/jdk1.8.0_112的jdk是否可用,然后再检查配置的默认jdk安装路径下是否有可用jdk
  jdk_path = find_jdk()
  if jdk_path is None:
    err = "No JDK found, please run the \"ambari-server setup\" " \
          "command to install a JDK automatically or install any " \
          "JDK manually to " + configDefaults.JDK_INSTALL_DIR
    raise FatalException(1, err)

  if not options.skip_properties_validation:
    #检查必须要配置的properties,在properties中是否都配置了
    missing_properties = get_missing_properties(properties)
    if missing_properties:
      err = "Required properties are not found: " + str(missing_properties) + ". To skip properties validation " \
            "use \"--skip-properties-validation\""
      raise FatalException(1, err)

  # Preparations
  if is_root():
    print configDefaults.MESSAGE_SERVER_RUNNING_AS_ROOT

  #检查jdbc driver安装,没有就去下载安装(/etc/ambari-server/conf/ambari.properties会配置jdbc信息)
  ensure_jdbc_driver_is_installed(options, properties)
  #检查数据库是否启动,没有就启动
  ensure_dbms_is_running(options, properties, scmStatus)

  if scmStatus is not None:
    scmStatus.reportStartPending()

  # 刷新resource、stacks路径下的archives
  #/var/lib/ambari-server/resources
  #/var/lib/ambari-server/resources/stacks
  refresh_stack_hash(properties)

  if scmStatus is not None:
    scmStatus.reportStartPending()

  #就查了下是不是root用户,
  #如果不是root用户提示了:如果没有root权限无法检查firewall status,
  #如果有需要disable或adjust firewall
  ensure_server_security_is_configured()

  if scmStatus is not None:
    scmStatus.reportStartPending()

  #获取java home路径
  java_exe = get_java_exe_path()

  #ambari server class 对象
  serverClassPath = ServerClassPath(properties, options)

  #前边有设置是否debug,这里获取一下
  #默认不开启_DEBUG_MODE = 0,如果开启了会为1
  debug_mode = get_debug_mode()
  #SERVER_START_DEBUG = False
  debug_start = (debug_mode & 1) or SERVER_START_DEBUG
  #SUSPEND_START_MODE = False
  suspend_start = (debug_mode & 2) or SUSPEND_START_MODE
  suspend_mode = 'y' if suspend_start else 'n'

  #如果没用启用security.passwords.encryption.enabled,比较简单直接返回系统环境变量
  #如果启用需要做一些处理,这里先不解释
  environ = generate_env(options, ambari_user, current_user)
  
  # ambari_class_path=/usr/lib/ambari-server:server.jdbc.driver.path:SERVER_CLASSPATH:jdbc driver classpath
  # conf_dir=/etc/ambari-server/conf
  # class_path=conf_dir + os.pathsep + ambari_class_path
  class_path = serverClassPath.get_full_ambari_classpath_escaped_for_shell(validate_classpath=True)

  if options.skip_database_check:
    global jvm_args
    jvm_args += " -DskipDatabaseConsistencyCheck"
    print "Ambari Server is starting with the database consistency check skipped. Do not make any changes to your cluster " \
          "topology or perform a cluster upgrade until you correct the database consistency issues. See \"" \
          + configDefaults.DB_CHECK_LOG + "\" for more details on the consistency issues."
    properties.process_pair(CHECK_DATABASE_SKIPPED_PROPERTY, "true")
  else:
    print "Ambari database consistency check started..."
    if options.fix_database_consistency:
      jvm_args += " -DfixDatabaseConsistency"
    properties.process_pair(CHECK_DATABASE_SKIPPED_PROPERTY, "false")

  #更新/etc/ambari-server/conf/ambari.properties文件
  update_properties(properties)
  #起实就是去拼启动命令去了......
  param_list = generate_child_process_param_list(ambari_user, java_exe, class_path, debug_start, suspend_mode)

  #这是server_process_main()的内部方法哈
    # The launched shell process and sub-processes should have a group id that
  # is different from the parent.
  def make_process_independent():
    if IS_FOREGROUND: # upstart script is not able to track process from different pgid.
      return
    
    processId = os.getpid()
    if processId > 0:
      try:
        os.setpgid(processId, processId)
      except OSError, e:
        print_warning_msg('setpgid({0}, {0}) failed - {1}'.format(pidJava, str(e)))
        pass

  print_info_msg("Running server: " + str(param_list))
  
  #通过param_list去启动ambari-server java 进程
  procJava = subprocess32.Popen(param_list, env=environ, preexec_fn=make_process_independent)
  #获取进程pid
  pidJava = procJava.pid
  if pidJava <= 0:
    procJava.terminate()
    exitcode = procJava.returncode
    exitfile = os.path.join(configDefaults.PID_DIR, EXITCODE_NAME)
    save_pid(exitcode, exitfile)

    if scmStatus is not None:
      scmStatus.reportStopPending()

    raise FatalException(-1, AMBARI_SERVER_DIE_MSG.format(exitcode, configDefaults.SERVER_OUT_FILE))
  else:
    pidfile = os.path.join(configDefaults.PID_DIR, PID_NAME)

    print "Server PID at: "+pidfile
    print "Server out at: "+configDefaults.SERVER_OUT_FILE
    print "Server log at: "+configDefaults.SERVER_LOG_FILE

    wait_for_server_start(pidfile, scmStatus)

  if scmStatus is not None:
    scmStatus.reportStarted()
    
  if IS_FOREGROUND:
    procJava.communicate()

  return procJava

generate_child_process_param_list方法主要代码,启动命令大概就是下面SERVER_START_CMD这个样子

org.apache.ambari.server.controller.AmbariServer是ambari-server工程的入口main

SERVER_START_CMD = "{0} " \
    "-server -XX:NewRatio=3 " \
    "-XX:+UseConcMarkSweepGC " + \
    "-XX:-UseGCOverheadLimit -XX:CMSInitiatingOccupancyFraction=60 " \
    "-XX:+CMSClassUnloadingEnabled " \
    "-Dsun.zip.disableMemoryMapping=true " + \
    "{1} {2} " \
    "-cp {3} "\
    "org.apache.ambari.server.controller.AmbariServer " \
    "> {4} 2>&1 || echo $? > {5}"
SERVER_START_CMD_DEBUG = "{0} " \
    "-server -XX:NewRatio=2 " \
    "-XX:+UseConcMarkSweepGC " + \
    "{1} {2} " \
    " -Xdebug -Xrunjdwp:transport=dt_socket,address=5005," \
    "server=y,suspend={6} " \
    "-cp {3} " + \
    "org.apache.ambari.server.controller.AmbariServer " \
    "> {4} 2>&1 || echo $? > {5}"

def generate_child_process_param_list(ambari_user, java_exe, class_path,
                                      debug_start, suspend_mode):
  from ambari_commons.os_linux import ULIMIT_CMD

  properties = get_ambari_properties()

  command_base = SERVER_START_CMD_DEBUG if debug_start else SERVER_START_CMD

  ulimit_cmd = "%s %s" % (ULIMIT_CMD, str(get_ulimit_open_files(properties)))
  command = command_base.format(java_exe,
          ambari_provider_module_option,
          jvm_args,
          class_path,
          configDefaults.SERVER_OUT_FILE,
          os.path.join(configDefaults.PID_DIR, EXITCODE_NAME),
          suspend_mode)

  # required to start properly server instance
  os.chdir(configDefaults.ROOT_FS_PATH)

  #For properly daemonization server should be started using shell as parent
  param_list = [locate_file('sh', '/bin'), "-c"]
  if is_root() and ambari_user != "root":
    # To inherit exported environment variables (especially AMBARI_PASSPHRASE),
    # from subprocess32, we have to skip --login option of su command. That's why
    # we change dir to / (otherwise subprocess32 can face with 'permission denied'
    # errors while trying to list current directory
    cmd = "{ulimit_cmd} ; {su} {ambari_user} -s {sh_shell} -c '. {ambari_env_file} && {command}'".format(ulimit_cmd=ulimit_cmd,
                                                                                su=locate_file('su', '/bin'), ambari_user=ambari_user,
                                                                                sh_shell=locate_file('sh', '/bin'), command=command,
                                                                                ambari_env_file=AMBARI_ENV_FILE)
  else:
    cmd = "{ulimit_cmd} ; {command}".format(ulimit_cmd=ulimit_cmd, command=command)
    
  param_list.append(cmd)
  return param_list

你可能感兴趣的:(ambari)